partitioning_20091102.patch

application/octet-stream

Filename: partitioning_20091102.patch
Type: application/octet-stream
Part: 0
Message: Re: Syntax for partitioning

Patch

Format: context
File+
src/backend/catalog/dependency.c 55 1
src/backend/catalog/heap.c 26 0
src/backend/catalog/Makefile 1 1
src/backend/commands/tablecmds.c 144 0
src/backend/nodes/copyfuncs.c 48 0
src/backend/nodes/equalfuncs.c 42 0
src/backend/nodes/outfuncs.c 30 0
src/backend/parser/gram.y 198 5
src/backend/parser/parse_utilcmd.c 181 1
src/backend/tcop/utility.c 10 0
src/backend/utils/cache/lsyscache.c 62 0
src/backend/utils/cache/syscache.c 14 2
src/include/catalog/dependency.h 1 0
src/include/catalog/heap.h 1 0
src/include/catalog/indexing.h 3 0
src/include/catalog/pg_partition.h 55 0
src/include/commands/tablecmds.h 2 0
src/include/nodes/nodes.h 3 0
src/include/nodes/parsenodes.h 37 1
src/include/parser/kwlist.h 3 0
src/include/parser/parse_utilcmd.h 1 0
src/include/utils/lsyscache.h 2 0
src/include/utils/syscache.h 2 1
src/test/regress/expected/partition.out 264 0
src/test/regress/expected/sanity_check.out 2 1
src/test/regress/parallel_schedule 1 1
src/test/regress/serial_schedule 1 0
src/test/regress/sql/partition.sql 93 0
diff -cprN head/src/backend/catalog/Makefile work/src/backend/catalog/Makefile
*** head/src/backend/catalog/Makefile	2009-10-08 07:14:16.000000000 +0900
--- work/src/backend/catalog/Makefile	2009-11-02 09:22:16.251471873 +0900
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
*** 37,43 ****
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
  	pg_ts_parser.h pg_ts_template.h \
  	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
! 	pg_default_acl.h \
  	toasting.h indexing.h \
      )
  
--- 37,43 ----
  	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
  	pg_ts_parser.h pg_ts_template.h \
  	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
! 	pg_default_acl.h pg_partition.h \
  	toasting.h indexing.h \
      )
  
diff -cprN head/src/backend/catalog/dependency.c work/src/backend/catalog/dependency.c
*** head/src/backend/catalog/dependency.c	2009-10-06 04:24:35.000000000 +0900
--- work/src/backend/catalog/dependency.c	2009-11-02 14:01:00.145461433 +0900
***************
*** 41,46 ****
--- 41,47 ----
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
  #include "catalog/pg_opfamily.h"
+ #include "catalog/pg_partition.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_rewrite.h"
  #include "catalog/pg_tablespace.h"
*************** static const Oid object_classes[MAX_OCLA
*** 149,155 ****
  	ForeignDataWrapperRelationId,	/* OCLASS_FDW */
  	ForeignServerRelationId,	/* OCLASS_FOREIGN_SERVER */
  	UserMappingRelationId,		/* OCLASS_USER_MAPPING */
! 	DefaultAclRelationId		/* OCLASS_DEFACL */
  };
  
  
--- 150,157 ----
  	ForeignDataWrapperRelationId,	/* OCLASS_FDW */
  	ForeignServerRelationId,	/* OCLASS_FOREIGN_SERVER */
  	UserMappingRelationId,		/* OCLASS_USER_MAPPING */
! 	DefaultAclRelationId,		/* OCLASS_DEFACL */
! 	PartitionRelationId			/* OCLASS_PARTITION */
  };
  
  
*************** doDeletion(const ObjectAddress *object)
*** 1143,1148 ****
--- 1145,1154 ----
  			RemoveDefaultACLById(object->objectId);
  			break;
  
+ 		case OCLASS_PARTITION:
+ 			RemovePartitionById(object->objectId);
+ 			break;
+ 
  		default:
  			elog(ERROR, "unrecognized object class: %u",
  				 object->classId);
*************** getObjectClass(const ObjectAddress *obje
*** 2066,2071 ****
--- 2072,2081 ----
  		case DefaultAclRelationId:
  			Assert(object->objectSubId == 0);
  			return OCLASS_DEFACL;
+ 
+ 		case PartitionRelationId:
+ 			Assert(object->objectSubId == 0);
+ 			return OCLASS_PARTITION;
  	}
  
  	/* shouldn't get here */
*************** getObjectDescription(const ObjectAddress
*** 2671,2676 ****
--- 2681,2730 ----
  				break;
  			}
  
+ 		case OCLASS_PARTITION:
+ 			{
+ 				Relation	rel;
+ 				ScanKeyData skey[1];
+ 				SysScanDesc rcscan;
+ 				HeapTuple	tup;
+ 				Form_pg_partition partition;
+ 
+ 				rel = heap_open(PartitionRelationId, AccessShareLock);
+ 
+ 				ScanKeyInit(&skey[0],
+ 							Anum_pg_partition_partrelid,
+ 							BTEqualStrategyNumber, F_OIDEQ,
+ 							ObjectIdGetDatum(object->objectId));
+ 
+ 				rcscan = systable_beginscan(rel, PartitionRelidIndexId,
+ 											true, SnapshotNow, 1, skey);
+ 
+ 				tup = systable_getnext(rcscan);
+ 
+ 				if (!HeapTupleIsValid(tup))
+ 					elog(ERROR, "could not find tuple for partition %u",
+ 						 object->objectId);
+ 
+ 				partition = (Form_pg_partition) GETSTRUCT(tup);
+ 
+ 				switch (partition->partkind)
+ 				{
+ 					case PARTITION_BY_RANGE:
+ 						appendStringInfo(&buffer, _("range partition"));
+ 						break;
+ 					case PARTITION_BY_LIST:
+ 						appendStringInfo(&buffer, _("list partition"));
+ 						break;
+ 					default:
+ 						appendStringInfo(&buffer, _("partition"));
+ 						break;
+ 				}
+ 
+ 				systable_endscan(rcscan);
+ 				heap_close(rel, AccessShareLock);
+ 				break;
+ 			}
+ 
  		default:
  			appendStringInfo(&buffer, "unrecognized object %u %u %d",
  							 object->classId,
diff -cprN head/src/backend/catalog/heap.c work/src/backend/catalog/heap.c
*** head/src/backend/catalog/heap.c	2009-10-06 04:24:35.000000000 +0900
--- work/src/backend/catalog/heap.c	2009-11-02 14:59:14.606458455 +0900
***************
*** 43,48 ****
--- 43,49 ----
  #include "catalog/pg_constraint.h"
  #include "catalog/pg_inherits.h"
  #include "catalog/pg_namespace.h"
+ #include "catalog/pg_partition.h"
  #include "catalog/pg_statistic.h"
  #include "catalog/pg_tablespace.h"
  #include "catalog/pg_type.h"
*************** RemoveStatistics(Oid relid, AttrNumber a
*** 2361,2366 ****
--- 2362,2392 ----
  
  
  /*
+  * Remove a pg_partition entry
+  */
+ void
+ RemovePartitionById(Oid relid)
+ {
+ 	Relation	rel;
+ 	HeapTuple	tup;
+ 
+ 	rel = heap_open(PartitionRelationId, RowExclusiveLock);
+ 
+ 	tup = SearchSysCache(PARTITIONKEY,
+ 						 ObjectIdGetDatum(relid),
+ 						 0, 0, 0);
+ 	if (!HeapTupleIsValid(tup))
+ 		elog(ERROR, "cache lookup failed for partition %u", relid);
+ 
+ 	simple_heap_delete(rel, &tup->t_self);
+ 
+ 	ReleaseSysCache(tup);
+ 
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ 
+ /*
   * RelationTruncateIndexes - truncate all indexes associated
   * with the heap relation to zero tuples.
   *
diff -cprN head/src/backend/commands/tablecmds.c work/src/backend/commands/tablecmds.c
*** head/src/backend/commands/tablecmds.c	2009-10-15 07:14:21.000000000 +0900
--- work/src/backend/commands/tablecmds.c	2009-11-02 14:29:59.330453022 +0900
***************
*** 32,37 ****
--- 32,38 ----
  #include "catalog/pg_inherits_fn.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_opclass.h"
+ #include "catalog/pg_partition.h"
  #include "catalog/pg_tablespace.h"
  #include "catalog/pg_trigger.h"
  #include "catalog/pg_type.h"
***************
*** 65,70 ****
--- 66,72 ----
  #include "storage/bufmgr.h"
  #include "storage/lmgr.h"
  #include "storage/smgr.h"
+ #include "tcop/utility.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/fmgroids.h"
*************** static void ATExecEnableDisableRule(Rela
*** 331,336 ****
--- 333,339 ----
  						char fires_when);
  static void ATExecAddInherit(Relation rel, RangeVar *parent);
  static void ATExecDropInherit(Relation rel, RangeVar *parent);
+ static void ATExecPartitionBy(Relation rel, PartitionBy *defs);
  static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
  				   ForkNumber forkNum, bool istemp);
  static const char *storage_name(char c);
*************** RenameRelationInternal(Oid myrelid, cons
*** 2234,2239 ****
--- 2237,2281 ----
  }
  
  /*
+  * CREATE PARTITION partition ON table 
+  */
+ void
+ CreatePartition(CreatePartitionStmt *stmt, const char *queryString)
+ {
+ 	Oid			relid;
+ 	Node	   *key;
+ 	Oid			oprid;
+ 	List	   *opr;
+ 	List	   *stmts;
+ 	ListCell   *cell;
+ 
+ 	relid = RangeVarGetRelid(stmt->parent, false);
+ 	key = get_partition_key(relid, &oprid);
+ 	if (key == NULL)
+ 	{
+ 		ereport(ERROR,
+ 			(errcode(ERRCODE_UNDEFINED_TABLE),
+ 				(stmt->parent->schemaname
+ 				? errmsg("relation \"%s.%s\" does not have partition key",
+ 					stmt->parent->schemaname, stmt->parent->relname)
+ 				: errmsg("relation \"%s\" does not have partition key",
+ 					stmt->parent->relname)),
+ 			 errhint("Use ALTER TABLE PARTITION BY first")));
+ 	}
+ 
+ 	if ((opr = get_opfullname(oprid)) == NIL)
+ 		elog(ERROR, "cache lookup failed for operator %u", oprid);
+ 
+ 	stmts = transformPartition(stmt->def, stmt->parent, key, opr);
+ 
+ 	foreach(cell, stmts)
+ 	{
+ 		ProcessUtility((Node *) lfirst(cell),
+ 					   queryString, NULL, false, NULL, NULL);
+ 	}
+ }
+ 
+ /*
   * Disallow ALTER TABLE (and similar commands) when the current backend has
   * any open reference to the target table besides the one just acquired by
   * the calling command; this implies there's an open cursor or active plan.
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2593,2598 ****
--- 2635,2641 ----
  		case AT_DisableRule:
  		case AT_AddInherit:		/* INHERIT / NO INHERIT */
  		case AT_DropInherit:
+ 		case AT_PartitionBy:	/* PARTITION BY / NO PARTITION */
  			ATSimplePermissions(rel, false);
  			/* These commands never recurse */
  			/* No command-specific prep needed */
*************** ATExecCmd(List **wqueue, AlteredTableInf
*** 2838,2843 ****
--- 2881,2889 ----
  		case AT_DropInherit:
  			ATExecDropInherit(rel, (RangeVar *) cmd->def);
  			break;
+ 		case AT_PartitionBy:	/* PARTITION BY / NO PARTITION */
+ 			ATExecPartitionBy(rel, (PartitionBy *) cmd->def);
+ 			break;
  		default:				/* oops */
  			elog(ERROR, "unrecognized alter table type: %d",
  				 (int) cmd->subtype);
*************** ATExecAlterColumnType(AlteredTableInfo *
*** 6164,6169 ****
--- 6210,6220 ----
  					 getObjectDescription(&foundObject));
  				break;
  
+ 			case OCLASS_PARTITION:
+ 				/* TODO: recreate all partitions */
+ 				elog(ERROR, "cannot change partition key");
+ 				break;
+ 
  			default:
  				elog(ERROR, "unrecognized object class: %u",
  					 foundObject.classId);
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7147,7152 ****
--- 7198,7205 ----
  	HeapTuple	inheritsTuple;
  	int32		inhseqno;
  	List	   *children;
+ 	Node	   *partkey;
+ 	Oid			partopr;
  
  	/*
  	 * AccessShareLock on the parent is what's obtained during normal CREATE
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7238,7243 ****
--- 7291,7314 ----
  	/* Match up the constraints and bump coninhcount as needed */
  	MergeConstraintsIntoExisting(child_rel, parent_rel);
  
+ 	/* If the parent has parition key, add dependency to partition key */
+ 	partkey = get_partition_key(RelationGetRelid(parent_rel), &partopr);
+ 	if (partkey)
+ 	{
+ 		ObjectAddress	partitionObj;
+ 		ObjectAddress	childObj;
+ 
+ 		/* TODO: Match up the partition key */
+ 
+ 		partitionObj.classId = PartitionRelationId;
+ 		partitionObj.objectId = RelationGetRelid(child_rel);
+ 		partitionObj.objectSubId = 0;
+ 		childObj.classId = RelationRelationId;
+ 		childObj.objectId = RelationGetRelid(child_rel);
+ 		childObj.objectSubId = 0;
+ 		recordDependencyOn(&childObj, &partitionObj, DEPENDENCY_NORMAL);
+ 	}
+ 
  	/*
  	 * OK, it looks valid.	Make the catalog entries that show inheritance.
  	 */
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7717,7722 ****
--- 7788,7866 ----
  
  
  /*
+  * ALTER TABLE PARTITION BY / NO PARTITION
+  */
+ static void
+ ATExecPartitionBy(Relation rel, PartitionBy *defs)
+ {
+ 	Oid				relid = RelationGetRelid(rel);
+ 	ObjectAddress	myself;
+ 
+ 	myself.classId = PartitionRelationId;
+ 	myself.objectId = relid;
+ 	myself.objectSubId = 0;
+ 
+ 	if (defs == NULL)
+ 	{
+ 		/* ALTER TABLE <name> NO PARTITION */
+ 		performDeletion(&myself, DROP_RESTRICT);
+ 	}
+ 	else
+ 	{
+ 		Relation		catalogRel;
+ 		TupleDesc		catalogDesc;
+ 		Datum			datum[Natts_pg_partition];
+ 		bool			nulls[Natts_pg_partition];
+ 		HeapTuple		tuple;
+ 		Node		   *partkey;
+ 		Oid				keytype;
+ 		Oid				partopr;
+ 		ParseState	   *pstate;
+ 		RangeTblEntry  *rte;
+ 
+ 		Assert(defs->key != NULL);
+ 		Assert(defs->opr != NIL);
+ 
+ 		/* Transform the expression of partition key. */
+ 		pstate = make_parsestate(NULL);
+ 		rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
+ 		addRTEtoQuery(pstate, rte, true, true, true);
+ 		partkey = transformExpr(pstate, defs->key);
+ 		free_parsestate(pstate);
+ 
+ 		/* Extract operator oid to compare partition keys */
+ 		keytype = exprType(partkey);
+ 		partopr = compatible_oper_opid(defs->opr, keytype, keytype, false);
+ 
+ 		/*
+ 		 * Make the pg_partition entry
+ 		 */
+ 		memset(nulls, 0, sizeof(nulls));
+ 		datum[0] = ObjectIdGetDatum(relid);			/* partrelid */
+ 		datum[1] = ObjectIdGetDatum(partopr);		/* partopr */
+ 		datum[2] = CharGetDatum(defs->kind);		/* partkind */
+ 		datum[3] = CStringGetTextDatum(nodeToString(partkey));	/* partkey */
+ 
+ 		catalogRel = heap_open(PartitionRelationId, RowExclusiveLock);
+ 		catalogDesc = RelationGetDescr(catalogRel);
+ 
+ 		tuple = heap_form_tuple(catalogDesc, datum, nulls);
+ 		simple_heap_insert(catalogRel, tuple);
+ 		CatalogUpdateIndexes(catalogRel, tuple);
+ 		heap_freetuple(tuple);
+ 
+ 		/* Store a dependency */
+ 		recordDependencyOnSingleRelExpr(&myself, partkey, relid,
+ 										DEPENDENCY_NORMAL, DEPENDENCY_AUTO);
+ 
+ 		heap_close(catalogRel, RowExclusiveLock);
+ 
+ 		/* Caller will create partition tables */
+ 	}
+ }
+ 
+ 
+ /*
   * Execute ALTER TABLE SET SCHEMA
   *
   * Note: caller must have checked ownership of the relation already
diff -cprN head/src/backend/nodes/copyfuncs.c work/src/backend/nodes/copyfuncs.c
*** head/src/backend/nodes/copyfuncs.c	2009-10-28 23:55:38.000000000 +0900
--- work/src/backend/nodes/copyfuncs.c	2009-11-02 09:22:16.255470382 +0900
*************** _copyCreateStmt(CreateStmt *from)
*** 2503,2508 ****
--- 2503,2509 ----
  	COPY_NODE_FIELD(options);
  	COPY_SCALAR_FIELD(oncommit);
  	COPY_STRING_FIELD(tablespacename);
+ 	COPY_NODE_FIELD(partitions);
  
  	return newnode;
  }
*************** _copyAlterTSConfigurationStmt(AlterTSCon
*** 3450,3455 ****
--- 3451,3494 ----
  	return newnode;
  }
  
+ static Partition *
+ _copyPartition(Partition *from)
+ {
+ 	Partition *newnode = makeNode(Partition);
+ 
+ 	COPY_SCALAR_FIELD(kind);
+ 	COPY_NODE_FIELD(name);
+ 	COPY_NODE_FIELD(value);
+ 	COPY_NODE_FIELD(options);
+ 	COPY_STRING_FIELD(tablespacename);
+ 
+ 	return newnode;
+ }
+ 
+ static PartitionBy *
+ _copyPartitionBy(PartitionBy *from)
+ {
+ 	PartitionBy *newnode = makeNode(PartitionBy);
+ 
+ 	COPY_SCALAR_FIELD(kind);
+ 	COPY_NODE_FIELD(key);
+ 	COPY_NODE_FIELD(opr);
+ 	COPY_NODE_FIELD(defs);
+ 
+ 	return newnode;
+ }
+ 
+ static CreatePartitionStmt *
+ _copyCreatePartitionStmt(CreatePartitionStmt *from)
+ {
+ 	CreatePartitionStmt *newnode = makeNode(CreatePartitionStmt);
+ 
+ 	COPY_NODE_FIELD(parent);
+ 	COPY_NODE_FIELD(def);
+ 
+ 	return newnode;
+ }
+ 
  /* ****************************************************************
   *					pg_list.h copy functions
   * ****************************************************************
*************** copyObject(void *from)
*** 4117,4122 ****
--- 4156,4170 ----
  		case T_AlterTSConfigurationStmt:
  			retval = _copyAlterTSConfigurationStmt(from);
  			break;
+ 		case T_Partition:
+ 			retval = _copyPartition(from);
+ 			break;
+ 		case T_PartitionBy:
+ 			retval = _copyPartitionBy(from);
+ 			break;
+ 		case T_CreatePartitionStmt:
+ 			retval = _copyCreatePartitionStmt(from);
+ 			break;
  
  		case T_A_Expr:
  			retval = _copyAExpr(from);
diff -cprN head/src/backend/nodes/equalfuncs.c work/src/backend/nodes/equalfuncs.c
*** head/src/backend/nodes/equalfuncs.c	2009-10-28 23:55:38.000000000 +0900
--- work/src/backend/nodes/equalfuncs.c	2009-11-02 09:22:16.255470382 +0900
*************** _equalCreateStmt(CreateStmt *a, CreateSt
*** 1101,1106 ****
--- 1101,1107 ----
  	COMPARE_NODE_FIELD(options);
  	COMPARE_SCALAR_FIELD(oncommit);
  	COMPARE_STRING_FIELD(tablespacename);
+ 	COMPARE_NODE_FIELD(partitions);
  
  	return true;
  }
*************** _equalAlterTSConfigurationStmt(AlterTSCo
*** 1900,1905 ****
--- 1901,1938 ----
  }
  
  static bool
+ _equalPartition(Partition *a, Partition *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_NODE_FIELD(name);
+ 	COMPARE_NODE_FIELD(value);
+ 	COMPARE_NODE_FIELD(options);
+ 	COMPARE_STRING_FIELD(tablespacename);
+ 
+ 	return true;
+ }
+ 
+ static bool
+ _equalPartitionBy(PartitionBy *a, PartitionBy *b)
+ {
+ 	COMPARE_SCALAR_FIELD(kind);
+ 	COMPARE_NODE_FIELD(key);
+ 	COMPARE_NODE_FIELD(opr);
+ 	COMPARE_NODE_FIELD(defs);
+ 
+ 	return true;
+ }
+ 
+ static bool
+ _equalCreatePartitionStmt(CreatePartitionStmt *a, CreatePartitionStmt *b)
+ {
+ 	COMPARE_NODE_FIELD(parent);
+ 	COMPARE_NODE_FIELD(def);
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalAExpr(A_Expr *a, A_Expr *b)
  {
  	COMPARE_SCALAR_FIELD(kind);
*************** equal(void *a, void *b)
*** 2810,2815 ****
--- 2843,2857 ----
  		case T_AlterTSConfigurationStmt:
  			retval = _equalAlterTSConfigurationStmt(a, b);
  			break;
+ 		case T_Partition:
+ 			retval = _equalPartition(a, b);
+ 			break;
+ 		case T_PartitionBy:
+ 			retval = _equalPartitionBy(a, b);
+ 			break;
+ 		case T_CreatePartitionStmt:
+ 			retval = _equalCreatePartitionStmt(a, b);
+ 			break;
  
  		case T_A_Expr:
  			retval = _equalAExpr(a, b);
diff -cprN head/src/backend/nodes/outfuncs.c work/src/backend/nodes/outfuncs.c
*** head/src/backend/nodes/outfuncs.c	2009-10-28 23:55:38.000000000 +0900
--- work/src/backend/nodes/outfuncs.c	2009-11-02 09:22:16.256471643 +0900
*************** _outCreateStmt(StringInfo str, CreateStm
*** 1782,1787 ****
--- 1782,1788 ----
  	WRITE_NODE_FIELD(options);
  	WRITE_ENUM_FIELD(oncommit, OnCommitAction);
  	WRITE_STRING_FIELD(tablespacename);
+ 	WRITE_NODE_FIELD(partitions);
  }
  
  static void
*************** _outConstraint(StringInfo str, Constrain
*** 2419,2424 ****
--- 2420,2448 ----
  	}
  }
  
+ static void
+ _outPartition(StringInfo str, Partition *node)
+ {
+ 	WRITE_NODE_TYPE("PARTITION");
+ 
+ 	WRITE_CHAR_FIELD(kind);
+ 	WRITE_NODE_FIELD(name);
+ 	WRITE_NODE_FIELD(value);
+ 	WRITE_NODE_FIELD(options);
+ 	WRITE_STRING_FIELD(tablespacename);
+ }
+ 
+ static void
+ _outPartitionBy(StringInfo str, PartitionBy *node)
+ {
+ 	WRITE_NODE_TYPE("PARTITIONBY");
+ 
+ 	WRITE_CHAR_FIELD(kind);
+ 	WRITE_NODE_FIELD(key);
+ 	WRITE_NODE_FIELD(opr);
+ 	WRITE_NODE_FIELD(defs);
+ }
+ 
  
  /*
   * _outNode -
*************** _outNode(StringInfo str, void *obj)
*** 2872,2877 ****
--- 2896,2907 ----
  			case T_XmlSerialize:
  				_outXmlSerialize(str, obj);
  				break;
+ 			case T_Partition:
+ 				_outPartition(str, obj);
+ 				break;
+ 			case T_PartitionBy:
+ 				_outPartitionBy(str, obj);
+ 				break;
  
  			default:
  
diff -cprN head/src/backend/parser/gram.y work/src/backend/parser/gram.y
*** head/src/backend/parser/gram.y	2009-10-15 07:14:22.000000000 +0900
--- work/src/backend/parser/gram.y	2009-11-02 11:38:00.829508450 +0900
*************** static TypeName *TableFuncTypeName(List 
*** 183,188 ****
--- 183,190 ----
  
  	InsertStmt			*istmt;
  	VariableSetStmt		*vsetstmt;
+ 	Partition			*partition;
+ 	PartitionBy			*partitionby;
  }
  
  %type <node>	stmt schema_stmt
*************** static TypeName *TableFuncTypeName(List 
*** 198,204 ****
  		CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
  		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
  		CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
! 		CreateUserStmt CreateUserMappingStmt CreateRoleStmt
  		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
  		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
  		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
--- 200,206 ----
  		CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
  		CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
  		CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
! 		CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePartitionStmt
  		CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
  		DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
  		DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
*************** static TypeName *TableFuncTypeName(List 
*** 435,440 ****
--- 437,447 ----
  %type <str>		opt_existing_window_name
  %type <ival>	opt_frame_clause frame_extent frame_bound
  
+ %type <partition> RangePartition ListPartition
+ %type <partitionby> PartitionBy OptPartition
+ %type <node> 	RangeUpper
+ %type <list>	OptUsingOp OptRangePartitions RangePartitions
+ 				OptListPartitions ListPartitions ListValues ConstValues
  
  /*
   * Non-keyword token types.  These are hard-wired into the "flex" lexer.
*************** static TypeName *TableFuncTypeName(List 
*** 497,503 ****
  	KEY
  
  	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
--- 504,510 ----
  	KEY
  
  	LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
! 	LEAST LEFT LESS LEVEL LIKE LIMIT LIST LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
  	LOCATION LOCK_P LOGIN_P
  
  	MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
*************** static TypeName *TableFuncTypeName(List 
*** 525,531 ****
  	STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
  	SYMMETRIC SYSID SYSTEM_P
  
! 	TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
  	TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
  	TRUNCATE TRUSTED TYPE_P
  
--- 532,538 ----
  	STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
  	SYMMETRIC SYSID SYSTEM_P
  
! 	TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THAN THEN TIME TIMESTAMP
  	TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
  	TRUNCATE TRUSTED TYPE_P
  
*************** stmt :
*** 678,683 ****
--- 685,691 ----
  			| CreateRoleStmt
  			| CreateUserStmt
  			| CreateUserMappingStmt
+ 			| CreatePartitionStmt
  			| CreatedbStmt
  			| DeallocateStmt
  			| DeclareCursorStmt
*************** schema_stmt:
*** 1136,1141 ****
--- 1144,1150 ----
  			| CreateTrigStmt
  			| GrantStmt
  			| ViewStmt
+ 			| CreatePartitionStmt
  		;
  
  
*************** AlterTableStmt:
*** 1561,1566 ****
--- 1570,1583 ----
  					n->relkind = OBJECT_TABLE;
  					$$ = (Node *)n;
  				}
+ 		|	ALTER PARTITION relation_expr alter_table_cmds
+ 				{
+ 					AlterTableStmt *n = makeNode(AlterTableStmt);
+ 					n->relation = $3;
+ 					n->cmds = $4;
+ 					n->relkind = OBJECT_TABLE;
+ 					$$ = (Node *)n;
+ 				}
  		|	ALTER INDEX qualified_name alter_table_cmds
  				{
  					AlterTableStmt *n = makeNode(AlterTableStmt);
*************** alter_table_cmd:
*** 1884,1889 ****
--- 1901,1922 ----
  					n->def = (Node *)$2;
  					$$ = (Node *)n;
  				}
+ 			/* ALTER TABLE <name> PARTITION BY ... */
+ 			| PartitionBy
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_PartitionBy;
+ 					n->def = (Node *)$1;
+ 					$$ = (Node *)n;
+ 				}
+ 			/* ALTER TABLE <name> NO PARTITION */
+ 			| NO PARTITION
+ 				{
+ 					AlterTableCmd *n = makeNode(AlterTableCmd);
+ 					n->subtype = AT_PartitionBy;
+ 					n->def = NULL;
+ 					$$ = (Node *)n;
+ 				}
  		;
  
  alter_column_default:
*************** copy_generic_opt_arg_list_item:
*** 2171,2177 ****
   *****************************************************************************/
  
  CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
! 			OptInherit OptWith OnCommitOption OptTableSpace
  				{
  					CreateStmt *n = makeNode(CreateStmt);
  					$4->istemp = $2;
--- 2204,2210 ----
   *****************************************************************************/
  
  CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
! 			OptInherit OptWith OnCommitOption OptTableSpace OptPartition
  				{
  					CreateStmt *n = makeNode(CreateStmt);
  					$4->istemp = $2;
*************** CreateStmt:	CREATE OptTemp TABLE qualifi
*** 2182,2191 ****
  					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...
--- 2215,2225 ----
  					n->options = $9;
  					n->oncommit = $10;
  					n->tablespacename = $11;
+ 					n->partitions = $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...
*************** CreateStmt:	CREATE OptTemp TABLE qualifi
*** 2199,2208 ****
--- 2233,2344 ----
  					n->options = $10;
  					n->oncommit = $11;
  					n->tablespacename = $12;
+ 					n->partitions = $13;
  					$$ = (Node *)n;
  				}
  		;
  
+ OptPartition:
+ 			PartitionBy				{ $$ = $1; }
+ 			| /*EMPTY*/				{ $$ = NULL; }
+ 		;
+ 
+ PartitionBy:
+ 			PARTITION BY RANGE '(' a_expr OptUsingOp ')' OptRangePartitions
+ 				{
+ 					PartitionBy *n = makeNode(PartitionBy);
+ 					
+ 					n->kind = PARTITION_BY_RANGE;
+ 					n->key = $5;
+ 					n->opr = ($6 != NIL ? $6 : list_make1(makeString("<")));
+ 					n->defs = $8;
+ 					$$ = n;
+ 				}
+ 			| PARTITION BY LIST '(' a_expr OptUsingOp ')' OptListPartitions
+ 				{
+ 					PartitionBy *n = makeNode(PartitionBy);
+ 					n->kind = PARTITION_BY_LIST;
+ 					n->key = $5;
+ 					n->opr = ($6 != NIL ? $6 : list_make1(makeString("=")));
+ 					n->defs = $8;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ OptUsingOp:
+ 			USING qual_all_Op		{ $$ = $2; }
+ 			| /*EMPTY*/				{ $$ = NIL; }
+ 		;
+ 
+ OptRangePartitions:
+ 			'(' RangePartitions ')'					{ $$ = $2; }
+ 			| /*EMPTY*/								{ $$ = NIL; }
+ 		;
+ 		 
+ 
+ RangePartitions:
+ 			RangePartition							{ $$ = list_make1($1); }
+ 			| RangePartitions ',' RangePartition	{ $$ = lappend($1, $3); }
+ 		;
+ 
+ RangePartition:
+ 			PARTITION qualified_name VALUES LESS THAN RangeUpper OptWith OptTableSpace
+ 				{
+ 					Partition *n = makeNode(Partition);
+ 					n->kind = PARTITION_BY_RANGE;
+ 					n->name = $2;
+ 					n->value = $6;
+ 					n->options = $7;
+ 					n->tablespacename = $8;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ RangeUpper:
+ 			AexprConst						{ $$ = $1; }
+ 			| '(' AexprConst ')'			{ $$ = $2; }
+ 			| MAXVALUE						{ $$ = NULL; }
+ 			| '(' MAXVALUE ')'				{ $$ = NULL; }
+ 		;
+ 
+ OptListPartitions:
+ 			'(' ListPartitions ')'					{ $$ = $2; }
+ 			| /*EMPTY*/								{ $$ = NIL; }
+ 		;
+ 
+ ListPartitions:
+ 			ListPartition							{ $$ = list_make1($1); }
+ 			| ListPartitions ',' ListPartition		{ $$ = lappend($1, $3); }
+ 		;
+ 
+ ListPartition:
+ 			PARTITION qualified_name VALUES opt_in ListValues OptWith OptTableSpace
+ 				{
+ 					Partition *n = makeNode(Partition);
+ 					n->kind = PARTITION_BY_LIST;
+ 					n->name = $2;
+ 					n->value = (Node *) $5;
+ 					n->options = $6;
+ 					n->tablespacename = $7;
+ 					$$ = n;
+ 				}
+ 		;
+ 
+ opt_in:		IN_P									{}
+ 			| /*EMPTY*/								{}
+ 		;
+ 
+ ListValues:
+ 			DEFAULT							{ $$ = NIL; }
+ 			| '(' DEFAULT ')'				{ $$ = NIL; }
+ 			| '(' ConstValues ')'			{ $$ = $2; }
+ 		;
+ 
+ ConstValues:
+ 			AexprConst						{ $$ = list_make1($1); }
+ 			| ConstValues ',' AexprConst	{ $$ = lappend($1, $3); }
+ 		;
+ 
  /*
   * Redundancy here is needed to avoid shift/reduce conflicts,
   * since TEMP is not a reserved word.  See also OptTempTableName.
*************** opt_with_data:
*** 2684,2689 ****
--- 2820,2861 ----
  /*****************************************************************************
   *
   *		QUERY :
+  *				CREATE PARTITION name
+  *
+  *****************************************************************************/
+ 
+ CreatePartitionStmt:
+ 			CREATE PARTITION qualified_name ON qualified_name
+ 				VALUES LESS THAN RangeUpper OptWith OptTableSpace
+ 				{
+ 					CreatePartitionStmt *n = makeNode(CreatePartitionStmt);
+ 					n->parent = $5;
+ 					n->def = makeNode(Partition);
+ 					n->def->kind = PARTITION_BY_RANGE;
+ 					n->def->name = $3;
+ 					n->def->value = $9;
+ 					n->def->options = $10;
+ 					n->def->tablespacename = $11;
+ 					$$ = (Node *)n;
+ 				}
+ 			| CREATE PARTITION qualified_name ON qualified_name
+ 				VALUES opt_in ListValues OptWith OptTableSpace
+ 				{
+ 					CreatePartitionStmt *n = makeNode(CreatePartitionStmt);
+ 					n->parent = $5;
+ 					n->def = makeNode(Partition);
+ 					n->def->kind = PARTITION_BY_RANGE;
+ 					n->def->name = $3;
+ 					n->def->value = (Node *) $8;
+ 					n->def->options = $9;
+ 					n->def->tablespacename = $10;
+ 					$$ = (Node *)n;
+ 				}
+ 		;
+ 
+ /*****************************************************************************
+  *
+  *		QUERY :
   *				CREATE SEQUENCE seqname
   *				ALTER SEQUENCE seqname
   *
*************** DropStmt:	DROP drop_type IF_P EXISTS any
*** 3930,3935 ****
--- 4102,4108 ----
  
  
  drop_type:	TABLE									{ $$ = OBJECT_TABLE; }
+ 			| PARTITION								{ $$ = OBJECT_TABLE; }
  			| SEQUENCE								{ $$ = OBJECT_SEQUENCE; }
  			| VIEW									{ $$ = OBJECT_VIEW; }
  			| INDEX									{ $$ = OBJECT_INDEX; }
*************** RenameStmt: ALTER AGGREGATE func_name ag
*** 5551,5556 ****
--- 5724,5738 ----
  					n->newname = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER PARTITION relation_expr RENAME TO name
+ 				{
+ 					RenameStmt *n = makeNode(RenameStmt);
+ 					n->renameType = OBJECT_TABLE;
+ 					n->relation = $3;
+ 					n->subname = NULL;
+ 					n->newname = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name RENAME TO name
  				{
  					RenameStmt *n = makeNode(RenameStmt);
*************** AlterObjectSchemaStmt:
*** 5711,5716 ****
--- 5893,5906 ----
  					n->newschema = $6;
  					$$ = (Node *)n;
  				}
+ 			| ALTER PARTITION relation_expr SET SCHEMA name
+ 				{
+ 					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
+ 					n->objectType = OBJECT_TABLE;
+ 					n->relation = $3;
+ 					n->newschema = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER SEQUENCE qualified_name SET SCHEMA name
  				{
  					AlterObjectSchemaStmt *n = makeNode(AlterObjectSchemaStmt);
*************** unreserved_keyword:
*** 10628,10634 ****
--- 10818,10826 ----
  			| LAST_P
  			| LC_COLLATE_P
  			| LC_CTYPE_P
+ 			| LESS
  			| LEVEL
+ 			| LIST
  			| LISTEN
  			| LOAD
  			| LOCAL
*************** unreserved_keyword:
*** 10734,10739 ****
--- 10926,10932 ----
  			| TEMPLATE
  			| TEMPORARY
  			| TEXT_P
+ 			| THAN
  			| TRANSACTION
  			| TRIGGER
  			| TRUNCATE
diff -cprN head/src/backend/parser/parse_utilcmd.c work/src/backend/parser/parse_utilcmd.c
*** head/src/backend/parser/parse_utilcmd.c	2009-10-13 09:53:08.000000000 +0900
--- work/src/backend/parser/parse_utilcmd.c	2009-11-02 14:52:58.409860006 +0900
*************** static void transformFKConstraints(Parse
*** 114,123 ****
  					   CreateStmtContext *cxt,
  					   bool skipValidation,
  					   bool isAddConstraint);
  static void transformConstraintAttrs(ParseState *pstate, List *constraintList);
  static void transformColumnType(ParseState *pstate, ColumnDef *column);
  static void setSchemaName(char *context_schema, char **stmt_schema_name);
! 
  
  /*
   * transformCreateStmt -
--- 114,126 ----
  					   CreateStmtContext *cxt,
  					   bool skipValidation,
  					   bool isAddConstraint);
+ static void transformPartitionBy(ParseState *pstate, CreateStmtContext *cxt, PartitionBy *defs);
  static void transformConstraintAttrs(ParseState *pstate, List *constraintList);
  static void transformColumnType(ParseState *pstate, ColumnDef *column);
  static void setSchemaName(char *context_schema, char **stmt_schema_name);
! static Constraint *makeCheckRange(Node *key, List *opr, Node *lower, Node *upper);
! static Constraint *makeCheckList(Node *key, List *opr, Node *values);
! static Node *getCurrentUpper(Relation rel);
  
  /*
   * transformCreateStmt -
*************** transformCreateStmt(CreateStmt *stmt, co
*** 233,238 ****
--- 236,259 ----
  	transformFKConstraints(pstate, &cxt, true, false);
  
  	/*
+ 	 * Postprocess partition related information.
+ 	 */
+ 	if (stmt->partitions)
+ 	{
+ 		AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
+ 		AlterTableCmd  *cmd = makeNode(AlterTableCmd);
+ 
+ 		cmd->subtype = AT_PartitionBy;
+ 		cmd->def = (Node *) stmt->partitions;
+ 
+ 		alterstmt->relation = cxt.relation;
+ 		alterstmt->relkind = OBJECT_TABLE;
+ 		alterstmt->cmds = list_make1(cmd);
+ 
+ 		cxt.alist = lappend(cxt.alist, alterstmt);
+ 	}
+ 
+ 	/*
  	 * Output results.
  	 */
  	stmt->tableElts = cxt.columns;
*************** transformFKConstraints(ParseState *pstat
*** 1421,1426 ****
--- 1442,1601 ----
  	}
  }
  
+ 
+ /*
+  * transformPartition
+  *		handle PARTITION clause
+  */
+ List *
+ transformPartition(Partition *def, RangeVar *parent, Node *key, List *opr)
+ {
+ 	InhRelation	   *like;
+ 	Constraint	   *check = NULL;
+ 	CreateStmt	   *create;
+ 	AlterTableStmt *alter;
+ 	AlterTableCmd  *cmd;
+ 
+ 	Assert(def != NULL);
+ 	Assert(IsA(def, Partition));
+ 	Assert(parent != NULL);
+ 	Assert(key != NULL);
+ 	Assert(opr != NIL);
+ 
+ 	switch (def->kind)
+ 	{
+ 		case PARTITION_BY_RANGE:
+ 			check = makeCheckRange(key, opr, getCurrentUpper(NULL), def->value);
+ 			break;
+ 		case PARTITION_BY_LIST:
+ 			check = makeCheckList(key, opr, def->value);
+ 			break;
+ 		default:
+ 			elog(ERROR, "unknown partition kind: %d", def->kind);
+ 	}
+ 
+ 	/* Use the same schema as the parent if not specified. */
+ 	Assert(def->name != NULL);
+ 	if (def->name->schemaname == NULL)
+ 		def->name->schemaname = parent->schemaname;
+ 	def->name->istemp = parent->istemp;
+ 
+ 	/* CREATE TABLE partition (LIKE parent INCLUDING ALL, CHECK(...) ) */
+ 	like = makeNode(InhRelation);
+ 	like->relation = parent;
+ 	like->options = CREATE_TABLE_LIKE_ALL;
+ 	create = makeNode(CreateStmt);
+ 	create->relation = def->name;
+ 	create->tableElts = list_make1(like);
+ 	if (check != NULL)
+ 		create->tableElts = lappend(create->tableElts, check);
+ 	create->inhRelations = NIL;
+ 	create->constraints = NIL;
+ 	create->options = def->options;
+ 	create->oncommit = ONCOMMIT_NOOP;
+ 	create->tablespacename = def->tablespacename;
+ 	create->partitions = NULL;
+ 
+ 	/* ALTER TABLE partition INHERIT parent */
+ 	cmd = makeNode(AlterTableCmd);
+ 	cmd->subtype = AT_AddInherit;
+ 	cmd->def = (Node *) parent;
+ 	alter = makeNode(AlterTableStmt);
+ 	alter->relation = def->name;
+ 	alter->cmds = list_make1(cmd);
+ 	alter->relkind = OBJECT_TABLE;
+ 
+ 	return list_make2(create, alter);
+ }
+ 
+ /* PARTITION BY / NO PARTITION */
+ static void
+ transformPartitionBy(ParseState *pstate, CreateStmtContext *cxt,
+ 					 PartitionBy *partitions)
+ {
+ 	ListCell	   *cell;
+ 
+ 	if (partitions == NULL)
+ 		return;
+ 
+ 	Assert(partitions->opr != NIL);
+ 
+ 	/* Expand partition clauses to CREATE TABLE. */
+ 	foreach (cell, partitions->defs)
+ 	{
+ 		Partition *def = (Partition *) lfirst(cell);
+ 
+ 		cxt->alist = list_concat(cxt->alist, transformPartition(def,
+ 						cxt->relation, partitions->key, partitions->opr));
+ 	}
+ }
+ 
+ static Node *
+ getCurrentUpper(Relation rel)
+ {
+ 	/* TODO: extract current upper bound from existing paritions */
+ 	elog(DEBUG2, "NOT IMPLEMENTED: %s(%d)", __FUNCTION__, __LINE__);
+ 
+ 	return NULL;
+ }
+ 
+ static Constraint *
+ makeCheckRange(Node *key, List *opr, Node *lower, Node *upper)
+ {
+ 	Constraint	   *check;
+ 	Node		   *lt;
+ 	Node		   *ge;
+ 
+ 	Assert(key != NULL);
+ 	Assert(opr != NULL);
+ 	if (lower == NULL && upper == NULL)
+ 		return NULL;	/* overflow partition no CHECK constraint */
+ 
+ 	/* key < upper */
+ 	if (upper != NULL)
+ 		lt = (Node *) makeA_Expr(AEXPR_OP, opr, key, upper, -1);
+ 
+ 	/* NOT (key < lower) */
+ 	if (lower != NULL)
+ 		ge = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
+ 				(Node *) makeA_Expr(AEXPR_OP, opr, key, lower, -1), -1);
+ 
+ 	/* CHECK ( lower <= key AND key < upper ) */
+ 	check = makeNode(Constraint);
+ 	check->contype = CONSTR_CHECK;
+ 	check->location = -1;
+ 	check->cooked_expr = NULL;
+ 	if (lower == NULL)			/* key < upper */
+ 		check->raw_expr = lt;
+ 	else if (upper == NULL)		/* NOT (key < lower) */
+ 		check->raw_expr = ge;
+ 	else						/* NOT (key < lower) AND key < upper */
+ 		check->raw_expr = (Node *) makeA_Expr(AEXPR_AND, NIL, ge, lt, -1);
+ 
+ 	return check;
+ }
+ 
+ static Constraint *
+ makeCheckList(Node *key, List *opr, Node *values)
+ {
+ 	Constraint	   *check;
+ 
+ 	Assert(key != NULL);
+ 	Assert(opr != NULL);
+ 	if (values == NULL)
+ 		return NULL;	/* overflow partition has no CHECK constraint */
+ 
+ 	check = makeNode(Constraint);
+ 	check->contype = CONSTR_CHECK;
+ 	check->location = -1;
+ 	check->cooked_expr = NULL;
+ 
+ 	/* CHECK ( key = ANY ( values ) ) */
+ 	check->raw_expr = (Node *) makeA_Expr(AEXPR_IN, opr, key, values, -1);
+ 
+ 	return check;
+ }
+ 
  /*
   * transformIndexStmt - parse analysis for CREATE INDEX
   *
*************** transformAlterTableStmt(AlterTableStmt *
*** 1905,1910 ****
--- 2080,2090 ----
  				newcmds = lappend(newcmds, cmd);
  				break;
  
+ 			case AT_PartitionBy:
+ 				newcmds = lappend(newcmds, cmd);
+ 				transformPartitionBy(pstate, &cxt, (PartitionBy *) cmd->def);
+ 				break;
+ 
  			default:
  				newcmds = lappend(newcmds, cmd);
  				break;
diff -cprN head/src/backend/tcop/utility.c work/src/backend/tcop/utility.c
*** head/src/backend/tcop/utility.c	2009-10-26 11:26:40.000000000 +0900
--- work/src/backend/tcop/utility.c	2009-11-02 09:22:16.262471704 +0900
*************** check_xact_readonly(Node *parsetree)
*** 214,219 ****
--- 214,220 ----
  		case T_CreateUserMappingStmt:
  		case T_AlterUserMappingStmt:
  		case T_DropUserMappingStmt:
+ 		case T_CreatePartitionStmt:
  			ereport(ERROR,
  					(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
  					 errmsg("transaction is read-only")));
*************** ProcessUtility(Node *parsetree,
*** 516,521 ****
--- 517,526 ----
  			RemoveUserMapping((DropUserMappingStmt *) parsetree);
  			break;
  
+ 		case T_CreatePartitionStmt:
+ 			CreatePartition((CreatePartitionStmt *) parsetree, queryString);
+ 			break;
+ 
  		case T_DropStmt:
  			{
  				DropStmt   *stmt = (DropStmt *) parsetree;
*************** CreateCommandTag(Node *parsetree)
*** 1422,1427 ****
--- 1427,1436 ----
  			tag = "DROP USER MAPPING";
  			break;
  
+ 		case T_CreatePartitionStmt:
+ 			tag = "CREATE PARTITION";
+ 			break;
+ 
  		case T_DropStmt:
  			switch (((DropStmt *) parsetree)->removeType)
  			{
*************** GetCommandLogLevel(Node *parsetree)
*** 2174,2179 ****
--- 2183,2189 ----
  		case T_CreateUserMappingStmt:
  		case T_AlterUserMappingStmt:
  		case T_DropUserMappingStmt:
+ 		case T_CreatePartitionStmt:
  			lev = LOGSTMT_DDL;
  			break;
  
diff -cprN head/src/backend/utils/cache/lsyscache.c work/src/backend/utils/cache/lsyscache.c
*** head/src/backend/utils/cache/lsyscache.c	2009-08-10 14:46:50.000000000 +0900
--- work/src/backend/utils/cache/lsyscache.c	2009-11-02 14:15:50.967507015 +0900
***************
*** 24,29 ****
--- 24,30 ----
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
+ #include "catalog/pg_partition.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_statistic.h"
  #include "catalog/pg_type.h"
*************** get_opname(Oid opno)
*** 1059,1064 ****
--- 1060,1091 ----
  }
  
  /*
+  * get_opfullname
+  *	  returns the full name of the operator, or NULL if not found.
+  */
+ List *
+ get_opfullname(Oid opno)
+ {
+ 	HeapTuple	tp;
+ 
+ 	tp = SearchSysCache(OPEROID,
+ 						ObjectIdGetDatum(opno),
+ 						0, 0, 0);
+ 	if (HeapTupleIsValid(tp))
+ 	{
+ 		Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ 		List	   *result;
+ 
+ 		result = list_make2(makeString(get_namespace_name(optup->oprnamespace)),
+ 							makeString(pstrdup(NameStr(optup->oprname))));
+ 		ReleaseSysCache(tp);
+ 		return result;
+ 	}
+ 	else
+ 		return NIL;
+ }
+ 
+ /*
   * op_input_types
   *
   *		Returns the left and right input datatypes for an operator
*************** get_roleid_checked(const char *rolname)
*** 2776,2778 ****
--- 2803,2840 ----
  				 errmsg("role \"%s\" does not exist", rolname)));
  	return roleid;
  }
+ 
+ /*
+  * get_partition_key
+  *		Returns the partition key of a given relation
+  */
+ Node *
+ get_partition_key(Oid relid, Oid *opr)
+ {
+ 	HeapTuple			tp;
+ 	Datum				datum;
+ 	bool				isNull;
+ 	Node			   *expr = NULL;
+ 
+ 	if (opr)
+ 		*opr = InvalidOid;
+ 
+ 	tp = SearchSysCache(PARTITIONKEY,
+ 						ObjectIdGetDatum(relid),
+ 						0, 0, 0);
+ 	if (HeapTupleIsValid(tp))
+ 	{
+ 		datum = SysCacheGetAttr(PARTITIONKEY, tp,
+ 								Anum_pg_partition_partkey, &isNull);
+ 		if (!isNull)
+ 			expr = stringToNode(TextDatumGetCString(datum));
+ 
+ 		if (opr)
+ 			*opr = DatumGetObjectId(SysCacheGetAttr(PARTITIONKEY, tp,
+ 								Anum_pg_partition_partopr, &isNull));
+ 
+ 		ReleaseSysCache(tp);
+ 	}
+ 
+ 	return expr;
+ }
diff -cprN head/src/backend/utils/cache/syscache.c work/src/backend/utils/cache/syscache.c
*** head/src/backend/utils/cache/syscache.c	2009-10-06 04:24:45.000000000 +0900
--- work/src/backend/utils/cache/syscache.c	2009-11-02 13:54:19.046445070 +0900
***************
*** 40,45 ****
--- 40,46 ----
  #include "catalog/pg_opclass.h"
  #include "catalog/pg_operator.h"
  #include "catalog/pg_opfamily.h"
+ #include "catalog/pg_partition.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_rewrite.h"
  #include "catalog/pg_statistic.h"
*************** static const struct cachedesc cacheinfo[
*** 764,774 ****
  			0
  		},
  		128
  	}
  };
  
! static CatCache *SysCache[
! 						  lengthof(cacheinfo)];
  static int	SysCacheSize = lengthof(cacheinfo);
  static bool CacheInitialized = false;
  
--- 765,786 ----
  			0
  		},
  		128
+ 	},
+ 	{PartitionRelationId,		/* PARTITIONKEY */
+ 		PartitionRelidIndexId,
+ 		Anum_pg_partition_partrelid,
+ 		1,
+ 		{
+ 			Anum_pg_partition_partrelid,
+ 			0,
+ 			0,
+ 			0
+ 		},
+ 		64
  	}
  };
  
! static CatCache *SysCache[lengthof(cacheinfo)];
  static int	SysCacheSize = lengthof(cacheinfo);
  static bool CacheInitialized = false;
  
diff -cprN head/src/include/catalog/dependency.h work/src/include/catalog/dependency.h
*** head/src/include/catalog/dependency.h	2009-10-08 07:14:24.000000000 +0900
--- work/src/include/catalog/dependency.h	2009-11-02 13:24:58.876494856 +0900
*************** typedef enum ObjectClass
*** 147,152 ****
--- 147,153 ----
  	OCLASS_FOREIGN_SERVER,		/* pg_foreign_server */
  	OCLASS_USER_MAPPING,		/* pg_user_mapping */
  	OCLASS_DEFACL,				/* pg_default_acl */
+ 	OCLASS_PARTITION,			/* pg_partition */
  	MAX_OCLASS					/* MUST BE LAST */
  } ObjectClass;
  
diff -cprN head/src/include/catalog/heap.h work/src/include/catalog/heap.h
*** head/src/include/catalog/heap.h	2009-10-06 04:24:48.000000000 +0900
--- work/src/include/catalog/heap.h	2009-11-02 13:31:37.379468821 +0900
*************** extern void RemoveAttrDefault(Oid relid,
*** 101,106 ****
--- 101,107 ----
  				  DropBehavior behavior, bool complain);
  extern void RemoveAttrDefaultById(Oid attrdefId);
  extern void RemoveStatistics(Oid relid, AttrNumber attnum);
+ extern void RemovePartitionById(Oid relid);
  
  extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno,
  						  bool relhasoids);
diff -cprN head/src/include/catalog/indexing.h work/src/include/catalog/indexing.h
*** head/src/include/catalog/indexing.h	2009-10-08 07:14:25.000000000 +0900
--- work/src/include/catalog/indexing.h	2009-11-02 09:22:16.264474579 +0900
*************** DECLARE_UNIQUE_INDEX(pg_default_acl_oid_
*** 275,280 ****
--- 275,283 ----
  DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops));
  #define DbRoleSettingDatidRolidIndexId	2965
  
+ DECLARE_UNIQUE_INDEX(pg_partition_relid_index, 2337, on pg_partition using btree(partrelid oid_ops));
+ #define PartitionRelidIndexId	2337
+ 
  /* last step of initialization script: build the indexes declared above */
  BUILD_INDICES
  
diff -cprN head/src/include/catalog/pg_partition.h work/src/include/catalog/pg_partition.h
*** head/src/include/catalog/pg_partition.h	1970-01-01 09:00:00.000000000 +0900
--- work/src/include/catalog/pg_partition.h	2009-11-02 09:42:21.773470507 +0900
***************
*** 0 ****
--- 1,55 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pg_partition.h
+  *	  definition of the system "partition" relation (pg_partition)
+  *	  along with the relation's initial contents.
+  *
+  *
+  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
+  *
+  * $PostgreSQL: pgsql/src/include/catalog/pg_partition.h $
+  *
+  * NOTES
+  *	  the genbki.sh script reads this file and generates .bki
+  *	  information from the DATA() statements.
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef PG_PARTITION_H
+ #define PG_PARTITION_H
+ 
+ #include "catalog/genbki.h"
+ 
+ /* ----------------
+  *		pg_partition definition.  cpp turns this into
+  *		typedef struct FormData_pg_partitions
+  * ----------------
+  */
+ #define PartitionRelationId 2336
+ 
+ CATALOG(pg_partition,2336) BKI_WITHOUT_OIDS
+ {
+ 	Oid		partrelid;		/* partitioned table oid */
+ 	Oid		partopr;		/* operator to compare keys */
+ 	char	partkind;		/* kind of partition: RANGE or LIST */
+ 	text	partkey;		/* partition key expression */
+ } FormData_pg_partition;
+ 
+ /* ----------------
+  *      Form_pg_partitions corresponds to a pointer to a tuple with
+  *      the format of pg_partitions relation.
+  * ----------------
+  */
+ typedef FormData_pg_partition *Form_pg_partition;
+ 
+ /* ----------------
+  *      compiler constants for pg_partitions
+  * ----------------
+  */
+ #define Natts_pg_partition				4
+ #define Anum_pg_partition_partrelid		1
+ #define Anum_pg_partition_partopr		2
+ #define Anum_pg_partition_partkind		3
+ #define Anum_pg_partition_partkey		4
+ 
+ #endif   /* PG_PARTITIONS_H */
diff -cprN head/src/include/commands/tablecmds.h work/src/include/commands/tablecmds.h
*** head/src/include/commands/tablecmds.h	2009-07-16 15:33:45.000000000 +0900
--- work/src/include/commands/tablecmds.h	2009-11-02 09:22:16.264474579 +0900
*************** extern void RenameRelationInternal(Oid m
*** 53,58 ****
--- 53,60 ----
  					   const char *newrelname,
  					   Oid namespaceId);
  
+ extern void CreatePartition(CreatePartitionStmt *stmt, const char *queryString);
+ 
  extern void find_composite_type_dependencies(Oid typeOid,
  								 const char *origTblName,
  								 const char *origTypeName);
diff -cprN head/src/include/nodes/nodes.h work/src/include/nodes/nodes.h
*** head/src/include/nodes/nodes.h	2009-10-26 11:26:41.000000000 +0900
--- work/src/include/nodes/nodes.h	2009-11-02 09:22:16.264474579 +0900
*************** typedef enum NodeTag
*** 346,351 ****
--- 346,352 ----
  	T_CreateUserMappingStmt,
  	T_AlterUserMappingStmt,
  	T_DropUserMappingStmt,
+ 	T_CreatePartitionStmt,
  
  	/*
  	 * TAGS FOR PARSE TREE NODES (parsenodes.h)
*************** typedef enum NodeTag
*** 384,389 ****
--- 385,392 ----
  	T_XmlSerialize,
  	T_WithClause,
  	T_CommonTableExpr,
+ 	T_Partition,
+ 	T_PartitionBy,
  
  	/*
  	 * TAGS FOR RANDOM OTHER STUFF
diff -cprN head/src/include/nodes/parsenodes.h work/src/include/nodes/parsenodes.h
*** head/src/include/nodes/parsenodes.h	2009-10-28 23:55:46.000000000 +0900
--- work/src/include/nodes/parsenodes.h	2009-11-02 09:22:16.265497236 +0900
*************** typedef enum AlterTableType
*** 1132,1138 ****
  	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 */
--- 1132,1139 ----
  	AT_EnableReplicaRule,		/* ENABLE REPLICA RULE name */
  	AT_DisableRule,				/* DISABLE RULE name */
  	AT_AddInherit,				/* INHERIT parent */
! 	AT_DropInherit,				/* NO INHERIT parent */
! 	AT_PartitionBy				/* PARTITION BY / NO PARTITION */
  } AlterTableType;
  
  typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
*************** typedef struct VariableShowStmt
*** 1333,1338 ****
--- 1334,1373 ----
  	char	   *name;
  } VariableShowStmt;
  
+ /* ----------
+  * Partitioning definitions
+  * ----------
+  */
+ 
+ #define	PARTITION_BY_RANGE		'R'
+ #define	PARTITION_BY_LIST		'L'
+ 
+ typedef struct Partition
+ {
+ 	NodeTag			type;
+ 	char			kind;			/* PARTITION_BY_xxx */
+ 	RangeVar	   *name;			/* name of partition */
+ 	Node		   *value;			/* for RANGE and LIST */
+ 	List		   *options;		/* options from WITH clause */
+ 	char		   *tablespacename; /* table space to use, or NULL */
+ } Partition;
+ 
+ typedef struct PartitionBy
+ {
+ 	NodeTag			type;
+ 	char			kind;			/* PARTITION_BY_xxx */
+ 	Node		   *key;			/* partition key expr */
+ 	List		   *opr;			/* partition key operator */
+ 	List		   *defs;			/* list of Partition */
+ } PartitionBy;
+ 
+ typedef struct CreatePartitionStmt
+ {
+ 	NodeTag				type;
+ 	RangeVar		   *parent;			/* parent of the partition */
+ 	Partition		   *def;
+ } CreatePartitionStmt;
+ 
  /* ----------------------
   *		Create Table Statement
   *
*************** typedef struct CreateStmt
*** 1355,1360 ****
--- 1390,1396 ----
  	List	   *options;		/* options from WITH clause */
  	OnCommitAction oncommit;	/* what do we do at COMMIT? */
  	char	   *tablespacename; /* table space to use, or NULL */
+ 	PartitionBy *partitions;	/* partitioning definition, or NULL */
  } CreateStmt;
  
  /* ----------
diff -cprN head/src/include/parser/kwlist.h work/src/include/parser/kwlist.h
*** head/src/include/parser/kwlist.h	2009-10-13 05:39:42.000000000 +0900
--- work/src/include/parser/kwlist.h	2009-11-02 09:22:16.266466337 +0900
*************** PG_KEYWORD("lc_ctype", LC_CTYPE_P, UNRES
*** 215,223 ****
--- 215,225 ----
  PG_KEYWORD("leading", LEADING, RESERVED_KEYWORD)
  PG_KEYWORD("least", LEAST, COL_NAME_KEYWORD)
  PG_KEYWORD("left", LEFT, TYPE_FUNC_NAME_KEYWORD)
+ PG_KEYWORD("less", LESS, UNRESERVED_KEYWORD)
  PG_KEYWORD("level", LEVEL, UNRESERVED_KEYWORD)
  PG_KEYWORD("like", LIKE, TYPE_FUNC_NAME_KEYWORD)
  PG_KEYWORD("limit", LIMIT, RESERVED_KEYWORD)
+ PG_KEYWORD("list", LIST, UNRESERVED_KEYWORD)
  PG_KEYWORD("listen", LISTEN, UNRESERVED_KEYWORD)
  PG_KEYWORD("load", LOAD, UNRESERVED_KEYWORD)
  PG_KEYWORD("local", LOCAL, UNRESERVED_KEYWORD)
*************** PG_KEYWORD("temp", TEMP, UNRESERVED_KEYW
*** 365,370 ****
--- 367,373 ----
  PG_KEYWORD("template", TEMPLATE, UNRESERVED_KEYWORD)
  PG_KEYWORD("temporary", TEMPORARY, UNRESERVED_KEYWORD)
  PG_KEYWORD("text", TEXT_P, UNRESERVED_KEYWORD)
+ PG_KEYWORD("than", THAN, UNRESERVED_KEYWORD)
  PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
  PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
  PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
diff -cprN head/src/include/parser/parse_utilcmd.h work/src/include/parser/parse_utilcmd.h
*** head/src/include/parser/parse_utilcmd.h	2009-01-02 02:24:00.000000000 +0900
--- work/src/include/parser/parse_utilcmd.h	2009-11-02 09:22:16.266466337 +0900
*************** extern IndexStmt *transformIndexStmt(Ind
*** 24,28 ****
--- 24,29 ----
  extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
  				  List **actions, Node **whereClause);
  extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
+ extern List *transformPartition(Partition *def, RangeVar *parent, Node *key, List *opr);
  
  #endif   /* PARSE_UTILCMD_H */
diff -cprN head/src/include/utils/lsyscache.h work/src/include/utils/lsyscache.h
*** head/src/include/utils/lsyscache.h	2009-08-10 14:46:50.000000000 +0900
--- work/src/include/utils/lsyscache.h	2009-11-02 10:53:03.724820136 +0900
*************** extern Oid	get_opclass_family(Oid opclas
*** 66,71 ****
--- 66,72 ----
  extern Oid	get_opclass_input_type(Oid opclass);
  extern RegProcedure get_opcode(Oid opno);
  extern char *get_opname(Oid opno);
+ extern List *get_opfullname(Oid opno);
  extern void op_input_types(Oid opno, Oid *lefttype, Oid *righttype);
  extern bool op_mergejoinable(Oid opno);
  extern bool op_hashjoinable(Oid opno);
*************** extern void free_attstatsslot(Oid atttyp
*** 137,142 ****
--- 138,144 ----
  extern char *get_namespace_name(Oid nspid);
  extern Oid	get_roleid(const char *rolname);
  extern Oid	get_roleid_checked(const char *rolname);
+ extern Node *get_partition_key(Oid relid, Oid *opr);
  
  #define type_is_array(typid)  (get_element_type(typid) != InvalidOid)
  
diff -cprN head/src/include/utils/syscache.h work/src/include/utils/syscache.h
*** head/src/include/utils/syscache.h	2009-10-06 04:24:49.000000000 +0900
--- work/src/include/utils/syscache.h	2009-11-02 09:22:16.267490580 +0900
*************** enum SysCacheIdentifier
*** 83,89 ****
  	TYPENAMENSP,
  	TYPEOID,
  	USERMAPPINGOID,
! 	USERMAPPINGUSERSERVER
  };
  
  extern void InitCatalogCache(void);
--- 83,90 ----
  	TYPENAMENSP,
  	TYPEOID,
  	USERMAPPINGOID,
! 	USERMAPPINGUSERSERVER,
! 	PARTITIONKEY
  };
  
  extern void InitCatalogCache(void);
diff -cprN head/src/test/regress/expected/partition.out work/src/test/regress/expected/partition.out
*** head/src/test/regress/expected/partition.out	1970-01-01 09:00:00.000000000 +0900
--- work/src/test/regress/expected/partition.out	2009-11-02 15:03:46.594453000 +0900
***************
*** 0 ****
--- 1,264 ----
+ --
+ -- RANGE PARTITIONING
+ --
+ CREATE TABLE sales_range (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ )
+ PARTITION BY RANGE ( sales_date )
+ (
+   PARTITION sales_2006 VALUES LESS THAN ('2007-01-01'),
+   PARTITION sales_2007 VALUES LESS THAN ('2008-01-01'),
+   PARTITION sales_2008 VALUES LESS THAN ('2009-01-01'),
+   PARTITION sales_max  VALUES LESS THAN (MAXVALUE)
+ );
+ \d+ sales_range
+                             Table "public.sales_range"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Child tables: sales_2006,
+               sales_2007,
+               sales_2008,
+               sales_max
+ Has OIDs: no
+ 
+ \d+ sales_2007
+                             Table "public.sales_2007"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Check constraints:
+     "sales_2007_sales_date_check" CHECK (sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+ 
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+    relname   | partkind 
+ -------------+----------
+  sales_range | R
+ (1 row)
+ 
+ DROP TABLE IF EXISTS sales_range CASCADE;
+ NOTICE:  drop cascades to 4 other objects
+ DETAIL:  drop cascades to table sales_2006
+ drop cascades to table sales_2007
+ drop cascades to table sales_2008
+ drop cascades to table sales_max
+ CREATE TABLE sales_range (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ );
+ ALTER TABLE sales_range PARTITION BY RANGE ( sales_date USING < )
+ (
+   PARTITION sales_2006 VALUES LESS THAN '2007-01-01',
+   PARTITION sales_2007 VALUES LESS THAN '2008-01-01',
+   PARTITION sales_2008 VALUES LESS THAN '2009-01-01',
+   PARTITION sales_max  VALUES LESS THAN MAXVALUE
+ );
+ \d+ sales_range
+                             Table "public.sales_range"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Child tables: sales_2006,
+               sales_2007,
+               sales_2008,
+               sales_max
+ Has OIDs: no
+ 
+ \d+ sales_2007
+                             Table "public.sales_2007"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Check constraints:
+     "sales_2007_sales_date_check" CHECK (sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+ 
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+    relname   | partkind 
+ -------------+----------
+  sales_range | R
+ (1 row)
+ 
+ DROP TABLE IF EXISTS sales_range CASCADE;
+ NOTICE:  drop cascades to 4 other objects
+ DETAIL:  drop cascades to table sales_2006
+ drop cascades to table sales_2007
+ drop cascades to table sales_2008
+ drop cascades to table sales_max
+ CREATE TABLE sales_range (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ );
+ ALTER TABLE sales_range PARTITION BY RANGE ( sales_date );
+ CREATE PARTITION sales_2006 ON sales_range VALUES LESS THAN '2007-01-01';
+ CREATE PARTITION sales_2007 ON sales_range VALUES LESS THAN '2008-01-01';
+ CREATE PARTITION sales_2008 ON sales_range VALUES LESS THAN '2009-01-01';
+ CREATE PARTITION sales_max  ON sales_range VALUES LESS THAN MAXVALUE;
+ \d+ sales_range
+                             Table "public.sales_range"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Child tables: sales_2006,
+               sales_2007,
+               sales_2008,
+               sales_max
+ Has OIDs: no
+ 
+ \d+ sales_2007
+                             Table "public.sales_2007"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Check constraints:
+     "sales_2007_sales_date_check" CHECK (sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+ 
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+    relname   | partkind 
+ -------------+----------
+  sales_range | R
+ (1 row)
+ 
+ DROP TABLE IF EXISTS sales_range CASCADE;
+ NOTICE:  drop cascades to 4 other objects
+ DETAIL:  drop cascades to table sales_2006
+ drop cascades to table sales_2007
+ drop cascades to table sales_2008
+ drop cascades to table sales_max
+ --
+ -- LIST PARTITIONING
+ --
+ CREATE TABLE sales_list (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ )
+ PARTITION BY LIST ( sales_state )
+ (
+   PARTITION sales_asia  VALUES ('asia'),
+   PARTITION sales_euro  VALUES ('eu'),
+   PARTITION sales_us    VALUES ('usa', 'canada'),
+   PARTITION sales_other VALUES (DEFAULT)
+ );
+ \d+ sales_list
+                             Table "public.sales_list"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Child tables: sales_asia,
+               sales_euro,
+               sales_other,
+               sales_us
+ Has OIDs: no
+ 
+ \d+ sales_us
+                              Table "public.sales_us"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Check constraints:
+     "sales_us_sales_state_check" CHECK (sales_state::text = ANY (ARRAY['usa'::character varying, 'canada'::character varying]::text[]))
+ Inherits: sales_list
+ Has OIDs: no
+ 
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+   relname   | partkind 
+ ------------+----------
+  sales_list | L
+ (1 row)
+ 
+ DROP TABLE IF EXISTS sales_list CASCADE;
+ NOTICE:  drop cascades to 4 other objects
+ DETAIL:  drop cascades to table sales_asia
+ drop cascades to table sales_euro
+ drop cascades to table sales_us
+ drop cascades to table sales_other
+ CREATE TABLE sales_list (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ );
+ ALTER TABLE sales_list PARTITION BY LIST ( sales_state USING = )
+ (
+   PARTITION sales_asia  VALUES ('asia'),
+   PARTITION sales_euro  VALUES ('eu'),
+   PARTITION sales_us    VALUES ('usa', 'canada'),
+   PARTITION sales_other VALUES DEFAULT
+ );
+ \d+ sales_list
+                             Table "public.sales_list"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Child tables: sales_asia,
+               sales_euro,
+               sales_other,
+               sales_us
+ Has OIDs: no
+ 
+ \d+ sales_us
+                              Table "public.sales_us"
+     Column     |            Type             | Modifiers | Storage  | Description 
+ ---------------+-----------------------------+-----------+----------+-------------
+  salesman_id   | numeric(5,0)                |           | main     | 
+  salesman_name | character varying(30)       |           | extended | 
+  sales_state   | character varying(20)       |           | extended | 
+  sales_date    | timestamp without time zone |           | plain    | 
+ Check constraints:
+     "sales_us_sales_state_check" CHECK (sales_state::text = ANY (ARRAY['usa'::character varying, 'canada'::character varying]::text[]))
+ Inherits: sales_list
+ Has OIDs: no
+ 
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+   relname   | partkind 
+ ------------+----------
+  sales_list | L
+ (1 row)
+ 
+ DROP TABLE IF EXISTS sales_list CASCADE;
+ NOTICE:  drop cascades to 4 other objects
+ DETAIL:  drop cascades to table sales_asia
+ drop cascades to table sales_euro
+ drop cascades to table sales_us
+ drop cascades to table sales_other
diff -cprN head/src/test/regress/expected/sanity_check.out work/src/test/regress/expected/sanity_check.out
*** head/src/test/regress/expected/sanity_check.out	2009-10-08 07:14:26.000000000 +0900
--- work/src/test/regress/expected/sanity_check.out	2009-11-02 14:53:22.654506000 +0900
*************** SELECT relname, relhasindex
*** 111,116 ****
--- 111,117 ----
   pg_opclass              | t
   pg_operator             | t
   pg_opfamily             | t
+  pg_partition            | t
   pg_pltemplate           | t
   pg_proc                 | t
   pg_rewrite              | t
*************** SELECT relname, relhasindex
*** 153,159 ****
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (142 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 154,160 ----
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (143 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
diff -cprN head/src/test/regress/parallel_schedule work/src/test/regress/parallel_schedule
*** head/src/test/regress/parallel_schedule	2009-08-24 12:10:16.000000000 +0900
--- work/src/test/regress/parallel_schedule	2009-11-02 14:56:03.617468480 +0900
*************** test: copy copyselect
*** 52,58 ****
  # ----------
  # Another group of parallel tests
  # ----------
! test: constraints triggers create_misc create_aggregate create_operator inherit vacuum drop_if_exists create_cast
  
  # Depends on the above
  test: create_index create_view
--- 52,58 ----
  # ----------
  # Another group of parallel tests
  # ----------
! test: constraints triggers create_misc create_aggregate create_operator inherit partition vacuum drop_if_exists create_cast
  
  # Depends on the above
  test: create_index create_view
diff -cprN head/src/test/regress/serial_schedule work/src/test/regress/serial_schedule
*** head/src/test/regress/serial_schedule	2009-08-24 12:10:16.000000000 +0900
--- work/src/test/regress/serial_schedule	2009-11-02 14:56:13.319808016 +0900
*************** test: create_operator
*** 60,65 ****
--- 60,66 ----
  test: create_index
  test: drop_if_exists
  test: inherit
+ test: partition
  test: vacuum
  test: create_view
  test: sanity_check
diff -cprN head/src/test/regress/sql/partition.sql work/src/test/regress/sql/partition.sql
*** head/src/test/regress/sql/partition.sql	1970-01-01 09:00:00.000000000 +0900
--- work/src/test/regress/sql/partition.sql	2009-11-02 15:03:30.816824063 +0900
***************
*** 0 ****
--- 1,93 ----
+ --
+ -- RANGE PARTITIONING
+ --
+ CREATE TABLE sales_range (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ )
+ PARTITION BY RANGE ( sales_date )
+ (
+   PARTITION sales_2006 VALUES LESS THAN ('2007-01-01'),
+   PARTITION sales_2007 VALUES LESS THAN ('2008-01-01'),
+   PARTITION sales_2008 VALUES LESS THAN ('2009-01-01'),
+   PARTITION sales_max  VALUES LESS THAN (MAXVALUE)
+ );
+ \d+ sales_range
+ \d+ sales_2007
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+ DROP TABLE IF EXISTS sales_range CASCADE;
+ 
+ CREATE TABLE sales_range (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ );
+ ALTER TABLE sales_range PARTITION BY RANGE ( sales_date USING < )
+ (
+   PARTITION sales_2006 VALUES LESS THAN '2007-01-01',
+   PARTITION sales_2007 VALUES LESS THAN '2008-01-01',
+   PARTITION sales_2008 VALUES LESS THAN '2009-01-01',
+   PARTITION sales_max  VALUES LESS THAN MAXVALUE
+ );
+ \d+ sales_range
+ \d+ sales_2007
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+ DROP TABLE IF EXISTS sales_range CASCADE;
+ 
+ CREATE TABLE sales_range (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ );
+ ALTER TABLE sales_range PARTITION BY RANGE ( sales_date );
+ CREATE PARTITION sales_2006 ON sales_range VALUES LESS THAN '2007-01-01';
+ CREATE PARTITION sales_2007 ON sales_range VALUES LESS THAN '2008-01-01';
+ CREATE PARTITION sales_2008 ON sales_range VALUES LESS THAN '2009-01-01';
+ CREATE PARTITION sales_max  ON sales_range VALUES LESS THAN MAXVALUE;
+ \d+ sales_range
+ \d+ sales_2007
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+ DROP TABLE IF EXISTS sales_range CASCADE;
+ 
+ --
+ -- LIST PARTITIONING
+ --
+ CREATE TABLE sales_list (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ )
+ PARTITION BY LIST ( sales_state )
+ (
+   PARTITION sales_asia  VALUES ('asia'),
+   PARTITION sales_euro  VALUES ('eu'),
+   PARTITION sales_us    VALUES ('usa', 'canada'),
+   PARTITION sales_other VALUES (DEFAULT)
+ );
+ \d+ sales_list
+ \d+ sales_us
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+ DROP TABLE IF EXISTS sales_list CASCADE;
+ 
+ CREATE TABLE sales_list (
+   salesman_id       numeric(5),
+   salesman_name     varchar(30),
+   sales_state       varchar(20),
+   sales_date        timestamp
+ );
+ ALTER TABLE sales_list PARTITION BY LIST ( sales_state USING = )
+ (
+   PARTITION sales_asia  VALUES ('asia'),
+   PARTITION sales_euro  VALUES ('eu'),
+   PARTITION sales_us    VALUES ('usa', 'canada'),
+   PARTITION sales_other VALUES DEFAULT
+ );
+ \d+ sales_list
+ \d+ sales_us
+ SELECT relname, partkind FROM pg_partition, pg_class WHERE partrelid = oid;
+ DROP TABLE IF EXISTS sales_list CASCADE;