diff -cprN head/doc/src/sgml/ref/alter_table.sgml work/doc/src/sgml/ref/alter_table.sgml
*** head/doc/src/sgml/ref/alter_table.sgml 2009-09-18 14:00:41.000000000 +0900
--- work/doc/src/sgml/ref/alter_table.sgml 2009-11-25 16:12:51.578651746 +0900
*************** ALTER TABLE parent_table
OWNER TO new_owner
SET TABLESPACE new_tablespace
+ PARTITION BY { RANGE | LIST } ( key ) [ opclass ] [ (...) ]
+ NO PARTITION
+ ATTACH PARTITION child_table VALUES ...
+ DETACH PARTITION child_table
*************** ALTER TABLE for more information.
+
+
+
+
+
+ NO PARTITION
+
+
+ This form removes the partition key from the table. If the table has
+ some partitions, partition values are also removed but inheritance and
+ check constraints are kept.
+
+
+
+
+
+ ATTACH PARTITION
+
+
+ This form attaches an existing table as a partition with specified partition values.
+ Inheritance and check constraints are internally added to the partitions.
+ See for more information.
+
+
+
+
+
+ DETACH PARTITION
+
+
+ This form removes the specified partition the list of partitions of
+ the target table. The removed partition can be accessed as a normal table.
+
+
+
+
diff -cprN head/doc/src/sgml/ref/create_table.sgml work/doc/src/sgml/ref/create_table.sgml
*** head/doc/src/sgml/ref/create_table.sgml 2009-10-27 22:58:28.000000000 +0900
--- work/doc/src/sgml/ref/create_table.sgml 2009-11-25 16:12:51.579401528 +0900
*************** CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY
*** 31,36 ****
--- 31,42 ----
[ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE tablespace ]
+ [ PARTITION BY { RANGE | LIST } ( key ) [ opclass ]
+ [ ( {
+ PARTITION partition VALUES LESS THAN { value | MAXVALUE }
+ | PARTITION partition VALUES [ IN ] [ ( ] { value [, ...] | DEFAULT } [ ) ]
+ } ) ]
+ ]
where column_constraint is:
*************** CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY
*** 704,709 ****
--- 710,726 ----
+
+ PARTITION BY
+
+
+ This clause adds a RANGE or LIST
+ partition key and optional partitions into the table.
+ When a named partition exist as a table, it inherits this table.
+ If not exists, a new table is automatically created and used.
+
+
+
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-25 16:12:51.579401528 +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-25 16:12:51.580652040 +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:
+ RemovePartition(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-25 16:12:51.581714464 +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"
*************** static void StoreConstraints(Relation re
*** 91,99 ****
static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
bool allow_merge, bool is_local);
static void SetRelationNumChecks(Relation rel, int numchecks);
- static Node *cookConstraint(ParseState *pstate,
- Node *raw_constraint,
- char *relname);
static List *insert_ordered_unique_oid(List *list, Oid datum);
--- 92,97 ----
*************** cookDefault(ParseState *pstate,
*** 2269,2275 ****
* Parse state must be set up to recognize any vars that might appear
* in the expression.
*/
! static Node *
cookConstraint(ParseState *pstate,
Node *raw_constraint,
char *relname)
--- 2267,2273 ----
* Parse state must be set up to recognize any vars that might appear
* in the expression.
*/
! Node *
cookConstraint(ParseState *pstate,
Node *raw_constraint,
char *relname)
*************** RemoveStatistics(Oid relid, AttrNumber a
*** 2361,2366 ****
--- 2359,2429 ----
/*
+ * Remove a pg_partition entry
+ */
+ void
+ RemovePartition(Oid relid)
+ {
+ Relation rel;
+ HeapScanDesc scan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ /* DELETE FROM pg_partition WHERE partrelid = :relid */
+ 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);
+
+ /* UPDATE pg_inherits SET inhvalues = NULL WHERE inhparent = :relid */
+ rel = heap_open(InheritsRelationId, RowExclusiveLock);
+ ScanKeyInit(&key,
+ Anum_pg_inherits_inhparent,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relid));
+ scan = heap_beginscan(rel, SnapshotNow, 1, &key);
+
+ while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+ {
+ Datum datum;
+ bool isnull;
+
+ datum = heap_getattr(tup, Anum_pg_inherits_inhvalues,
+ RelationGetDescr(rel), &isnull);
+ if (!isnull)
+ {
+ Datum values[Natts_pg_inherits];
+ bool nulls[Natts_pg_inherits];
+ bool replaces[Natts_pg_inherits];
+ HeapTuple newtup;
+
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, false, sizeof(nulls));
+ MemSet(replaces, false, sizeof(replaces));
+
+ nulls[Anum_pg_inherits_inhvalues - 1] = true;
+ replaces[Anum_pg_inherits_inhvalues - 1] = true;
+
+ newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
+ values, nulls, replaces);
+ simple_heap_update(rel, &newtup->t_self, newtup);
+ CatalogUpdateIndexes(rel, newtup);
+
+ heap_freetuple(newtup);
+ }
+ }
+ heap_endscan(scan);
+
+ heap_close(rel, RowExclusiveLock);
+ }
+
+
+ /*
* RelationTruncateIndexes - truncate all indexes associated
* with the heap relation to zero tuples.
*
diff -cprN head/src/backend/catalog/pg_inherits.c work/src/backend/catalog/pg_inherits.c
*** head/src/backend/catalog/pg_inherits.c 2009-06-11 23:48:55.000000000 +0900
--- work/src/backend/catalog/pg_inherits.c 2009-11-25 16:12:51.582397348 +0900
***************
*** 20,34 ****
--- 20,43 ----
#include "postgres.h"
#include "access/heapam.h"
+ #include "access/nbtree.h"
#include "catalog/pg_class.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_inherits_fn.h"
+ #include "catalog/pg_opclass.h"
+ #include "catalog/pg_partition.h"
+ #include "nodes/nodeFuncs.h"
#include "parser/parse_type.h"
#include "storage/lmgr.h"
+ #include "utils/array.h"
+ #include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
+ #include "utils/lsyscache.h"
#include "utils/tqual.h"
+ static List *sort_range_partitions(List *partitions, Oid cmp);
+ static List *sort_list_partitions(List *partitions);
/*
* find_inheritance_children
*************** typeInheritsFrom(Oid subclassTypeId, Oid
*** 287,289 ****
--- 296,474 ----
return result;
}
+
+ /*
+ * find_partitions - Gather information of a partition.
+ *
+ * Returns a list of Partition.
+ */
+ List *
+ find_partitions(Oid parentrelId, char *kind, Node **key, Oid *opclass)
+ {
+ Relation inhrel;
+ HeapScanDesc scan;
+ ScanKeyData skey[1];
+ HeapTuple tp;
+ Datum datum;
+ bool isnull;
+ List *partitions = NIL;
+ Oid opfamily;
+ Oid typid;
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+
+ *kind = 0;
+ *key = NULL;
+ *opclass = InvalidOid;
+
+ /* Get partition key and operator. */
+ tp = SearchSysCache(PARTITIONKEY, ObjectIdGetDatum(parentrelId), 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ return NIL; /* not partitioned */
+
+ *kind = DatumGetChar(SysCacheGetAttr(PARTITIONKEY, tp,
+ Anum_pg_partition_partkind, &isnull));
+ *key = stringToNode(TextDatumGetCString(SysCacheGetAttr(
+ PARTITIONKEY, tp, Anum_pg_partition_partkey, &isnull)));
+ *opclass = DatumGetObjectId(SysCacheGetAttr(PARTITIONKEY, tp,
+ Anum_pg_partition_partopclass, &isnull));
+ ReleaseSysCache(tp);
+
+ tp = SearchSysCache(CLAOID, ObjectIdGetDatum(*opclass), 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for opclass %u", *opclass);
+ opfamily = ((Form_pg_opclass) GETSTRUCT(tp))->opcfamily;
+ ReleaseSysCache(tp);
+
+ typid = exprType(*key);
+ get_typlenbyvalalign(typid, &typlen, &typbyval, &typalign);
+
+ if (has_subclass(parentrelId))
+ {
+ /* Gather values from existing paritition. */
+ inhrel = heap_open(InheritsRelationId, AccessShareLock);
+ ScanKeyInit(&skey[0],
+ Anum_pg_inherits_inhparent,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(parentrelId));
+ scan = heap_beginscan(inhrel, SnapshotNow, 1, skey);
+
+ while ((tp = heap_getnext(scan, ForwardScanDirection)) != NULL)
+ {
+ Form_pg_inherits inh = (Form_pg_inherits) GETSTRUCT(tp);
+ Partition *p;
+
+ datum = heap_getattr(tp, Anum_pg_inherits_inhvalues,
+ RelationGetDescr(inhrel), &isnull);
+ if (isnull)
+ continue; /* non-partition inheritance */
+
+ p = (Partition *) palloc(sizeof(Partition));
+ p->relid = inh->inhrelid;
+ deconstruct_array(DatumGetArrayTypeP(datum), typid, typlen,
+ typbyval, typalign, &p->values, NULL, &p->nvalues);
+
+ partitions = lappend(partitions, p);
+ }
+
+ heap_endscan(scan);
+ heap_close(inhrel, AccessShareLock);
+
+ switch (*kind)
+ {
+ case PARTITION_BY_RANGE:
+ {
+ Oid cmp;
+
+ cmp = get_opfamily_proc(opfamily, typid, typid, BTORDER_PROC);
+ if (!OidIsValid(cmp))
+ elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
+ BTORDER_PROC, typid, typid, opfamily);
+ partitions = sort_range_partitions(partitions, cmp);
+ break;
+ }
+ case PARTITION_BY_LIST:
+ partitions = sort_list_partitions(partitions);
+ break;
+ }
+ }
+
+ return partitions;
+ }
+
+ /* overflow partition is always larger than normal partitions. */
+ static int
+ compare_range_partitions(const Partition *lhs,
+ const Partition *rhs,
+ FmgrInfo *cmpfn)
+ {
+ if (lhs->nvalues == 0 && rhs->nvalues == 0)
+ return 0; /* should not ocuur */
+ else if (rhs->nvalues == 0)
+ return -1; /* rhs is overflow partition */
+ else if (lhs->nvalues == 0)
+ return +1; /* lhs is overflow partition */
+
+ return DatumGetInt32(FunctionCall2(cmpfn, lhs->values[0], rhs->values[0]));
+ }
+
+ static List *
+ sort_range_partitions(List *partitions, Oid cmp)
+ {
+ FmgrInfo cmpfn;
+ Partition **arr;
+ ListCell *cell;
+ int n;
+ int i;
+ List *sorted = NIL;
+
+ if (list_length(partitions) < 2)
+ return partitions; /* no need to sort */
+
+ fmgr_info(cmp, &cmpfn);
+ n = list_length(partitions);
+ arr = (Partition **) palloc(sizeof(Partition *) * n);
+
+ /*
+ * Sort upper range using partition operator. We flatten list to array,
+ * sort items in array, and rebuild a list.
+ */
+ i = 0;
+ foreach(cell, partitions)
+ arr[i++] = (Partition *) lfirst(cell);
+ qsort_arg(arr, n, sizeof(Partition *),
+ (qsort_arg_comparator) compare_range_partitions, &cmpfn);
+ for (i = 0; i < n; i++)
+ sorted = lappend(sorted, arr[i]);
+ pfree(arr);
+
+ return sorted;
+ }
+
+ static List *
+ sort_list_partitions(List *partitions)
+ {
+ ListCell *cell;
+ ListCell *prev;
+
+ if (list_length(partitions) < 2)
+ return partitions; /* no need to sort */
+
+ /* We only have to move the oveflow partition at the end of list. */
+ for (prev = NULL, cell = list_head(partitions);
+ cell != NULL;
+ prev = cell, cell = lnext(prev))
+ {
+ Partition *p = (Partition *) lfirst(cell);
+
+ if (p->nvalues == 0)
+ {
+ partitions = list_delete_cell(partitions, cell, prev);
+ partitions = lappend(partitions, p);
+ break;
+ }
+ }
+
+ return partitions;
+ }
diff -cprN head/src/backend/commands/indexcmds.c work/src/backend/commands/indexcmds.c
*** head/src/backend/commands/indexcmds.c 2009-07-30 05:56:18.000000000 +0900
--- work/src/backend/commands/indexcmds.c 2009-11-25 16:12:51.582397348 +0900
*************** static void ComputeIndexAttrs(IndexInfo
*** 62,69 ****
char *accessMethodName, Oid accessMethodId,
bool amcanorder,
bool isconstraint);
- static Oid GetIndexOpClass(List *opclass, Oid attrType,
- char *accessMethodName, Oid accessMethodId);
static bool relationHasPrimaryKey(Relation rel);
--- 62,67 ----
*************** ComputeIndexAttrs(IndexInfo *indexInfo,
*** 939,947 ****
/*
* Resolve possibly-defaulted operator class specification
*/
! static Oid
GetIndexOpClass(List *opclass, Oid attrType,
! char *accessMethodName, Oid accessMethodId)
{
char *schemaname;
char *opcname;
--- 937,945 ----
/*
* Resolve possibly-defaulted operator class specification
*/
! Oid
GetIndexOpClass(List *opclass, Oid attrType,
! const char *accessMethodName, Oid accessMethodId)
{
char *schemaname;
char *opcname;
diff -cprN head/src/backend/commands/tablecmds.c work/src/backend/commands/tablecmds.c
*** head/src/backend/commands/tablecmds.c 2009-11-21 05:38:10.000000000 +0900
--- work/src/backend/commands/tablecmds.c 2009-11-25 16:20:29.351400090 +0900
***************
*** 32,37 ****
--- 32,39 ----
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
+ #include "catalog/pg_operator.h"
+ #include "catalog/pg_partition.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
***************
*** 65,72 ****
--- 67,76 ----
#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/datum.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
*************** static void MergeAttributesIntoExisting(
*** 230,236 ****
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
! int16 seqNumber, Relation inhRelation);
static int findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
static void AlterIndexNamespaces(Relation classRel, Relation rel,
--- 234,240 ----
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
! int16 seqNumber, ArrayType *values, Relation inhRelation);
static int findAttrByName(const char *attributeName, List *schema);
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
static void AlterIndexNamespaces(Relation classRel, Relation rel,
*************** static void ATExecEnableDisableRule(Rela
*** 331,339 ****
--- 335,359 ----
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 ATExecAttachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel, PartitionDef *def);
+ static void ATExecDetachPartition(Relation rel, RangeVar *child);
static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
ForkNumber forkNum, bool istemp);
static const char *storage_name(char c);
+ static void addInherit(Relation child_rel, Relation parent_rel,
+ List **wqueue, AlteredTableInfo *tab, PartitionDef *def);
+ static void dropInherit(Relation rel, Relation parent_rel);
+ static ArrayType *addPartitionConstraint(List **wqueue, AlteredTableInfo *tab,
+ PartitionDef *def, Relation parent, Relation child);
+ static void findRangePartition(Datum value, List *partitions, FmgrInfo *ltfn,
+ Partition **left, Partition **right);
+ static Partition *findOverlappedListPartition(const Datum *values,
+ int nvalues, List *partitions, FmgrInfo *eqfn);
+ static List *gatherPartitionValues(List *partitions, Oid elmtype, int elmlen,
+ bool elmbyval);
+ static Datum *evaluateValues(Oid typid, int typlen, bool typbyval,
+ List *values, int *length);
/* ----------------------------------------------------------------
*************** StoreCatalogInheritance(Oid relationId,
*** 1767,1773 ****
{
Oid parentOid = lfirst_oid(entry);
! StoreCatalogInheritance1(relationId, parentOid, seqNumber, relation);
seqNumber++;
}
--- 1787,1793 ----
{
Oid parentOid = lfirst_oid(entry);
! StoreCatalogInheritance1(relationId, parentOid, seqNumber, NULL, relation);
seqNumber++;
}
*************** StoreCatalogInheritance(Oid relationId,
*** 1779,1786 ****
* of parentOid. inhRelation is the already-opened pg_inherits catalog.
*/
static void
! StoreCatalogInheritance1(Oid relationId, Oid parentOid,
! int16 seqNumber, Relation inhRelation)
{
TupleDesc desc = RelationGetDescr(inhRelation);
Datum datum[Natts_pg_inherits];
--- 1799,1806 ----
* of parentOid. inhRelation is the already-opened pg_inherits catalog.
*/
static void
! StoreCatalogInheritance1(Oid relationId, Oid parentOid, int16 seqNumber,
! ArrayType *values, Relation inhRelation)
{
TupleDesc desc = RelationGetDescr(inhRelation);
Datum datum[Natts_pg_inherits];
*************** StoreCatalogInheritance1(Oid relationId,
*** 1795,1804 ****
--- 1815,1826 ----
datum[0] = ObjectIdGetDatum(relationId); /* inhrelid */
datum[1] = ObjectIdGetDatum(parentOid); /* inhparent */
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
+ datum[3] = PointerGetDatum(values); /* inhvalues */
nullarr[0] = false;
nullarr[1] = false;
nullarr[2] = false;
+ nullarr[3] = (values == NULL);
tuple = heap_form_tuple(desc, datum, nullarr);
*************** RenameRelationInternal(Oid myrelid, cons
*** 2234,2239 ****
--- 2256,2280 ----
}
/*
+ * CREATE PARTITION partition ON table
+ */
+ void
+ CreatePartition(CreatePartitionStmt *stmt, const char *queryString)
+ {
+ List *stmts;
+ ListCell *cell;
+
+ stmts = transformCreatePartition(stmt->def, stmt->parent);
+
+ foreach(cell, stmts)
+ {
+ ProcessUtility((Node *) lfirst(cell),
+ queryString, NULL, false, NULL, NULL);
+ CommandCounterIncrement();
+ }
+ }
+
+ /*
* 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,2603 ****
--- 2634,2650 ----
case AT_DisableRule:
case AT_AddInherit: /* INHERIT / NO INHERIT */
case AT_DropInherit:
+ case AT_DetachPartition: /* DETACH PARTITION */
ATSimplePermissions(rel, false);
/* These commands never recurse */
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
+ case AT_PartitionBy: /* PARTITION BY / NO PARTITION */
+ case AT_AttachPartition: /* ATTACH PARTITION */
+ ATSimplePermissions(rel, false);
+ pass = AT_PASS_ADD_CONSTR;
+ break;
default: /* oops */
elog(ERROR, "unrecognized alter table type: %d",
(int) cmd->subtype);
*************** ATExecCmd(List **wqueue, AlteredTableInf
*** 2838,2843 ****
--- 2885,2899 ----
case AT_DropInherit:
ATExecDropInherit(rel, (RangeVar *) cmd->def);
break;
+ case AT_PartitionBy: /* PARTITION BY / NO PARTITION */
+ ATExecPartitionBy(rel, (PartitionBy *) cmd->def);
+ break;
+ case AT_AttachPartition:
+ ATExecAttachPartition(wqueue, tab, rel, (PartitionDef *) cmd->def);
+ break;
+ case AT_DetachPartition:
+ ATExecDetachPartition(rel, (RangeVar *) cmd->def);
+ break;
default: /* oops */
elog(ERROR, "unrecognized alter table type: %d",
(int) cmd->subtype);
*************** ATExecAlterColumnType(AlteredTableInfo *
*** 6201,6206 ****
--- 6257,6269 ----
getObjectDescription(&foundObject));
break;
+ case OCLASS_PARTITION:
+ /* TODO: recreate all partitions */
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot alter type of a column used in partition keys")));
+ break;
+
default:
elog(ERROR, "unrecognized object class: %u",
foundObject.classId);
*************** ATExecEnableDisableRule(Relation rel, ch
*** 7168,7174 ****
}
/*
! * ALTER TABLE INHERIT
*
* Add a parent to the child's parents. This verifies that all the columns and
* check constraints of the parent appear in the child and that they have the
--- 7231,7237 ----
}
/*
! * ALTER TABLE INHERIT / ATTACH PARTITION
*
* Add a parent to the child's parents. This verifies that all the columns and
* check constraints of the parent appear in the child and that they have the
*************** ATExecEnableDisableRule(Relation rel, ch
*** 7177,7189 ****
static void
ATExecAddInherit(Relation child_rel, RangeVar *parent)
{
! Relation parent_rel,
! catalogRelation;
! SysScanDesc scan;
! ScanKeyData key;
! HeapTuple inheritsTuple;
! int32 inhseqno;
! List *children;
/*
* AccessShareLock on the parent is what's obtained during normal CREATE
--- 7240,7246 ----
static void
ATExecAddInherit(Relation child_rel, RangeVar *parent)
{
! Relation parent_rel;
/*
* AccessShareLock on the parent is what's obtained during normal CREATE
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7191,7196 ****
--- 7248,7289 ----
*/
parent_rel = heap_openrv(parent, AccessShareLock);
+ addInherit(child_rel, parent_rel, NULL, NULL, NULL);
+
+ /* keep our lock on the parent relation until commit */
+ heap_close(parent_rel, NoLock);
+ }
+
+ static void
+ ATExecAttachPartition(List **wqueue, AlteredTableInfo *tab,
+ Relation parent_rel, PartitionDef *def)
+ {
+ Relation child_rel;
+
+ /*
+ * AccessShareLock on the parent is what's obtained during normal CREATE
+ * TABLE ... INHERITS ..., so should be enough here.
+ */
+ child_rel = heap_openrv(def->name, AccessShareLock);
+
+ addInherit(child_rel, parent_rel, wqueue, tab, def);
+
+ /* keep our lock on the parent relation until commit */
+ heap_close(child_rel, NoLock);
+ }
+
+ static void
+ addInherit(Relation child_rel, Relation parent_rel,
+ List **wqueue, AlteredTableInfo *tab, PartitionDef *def)
+ {
+ Relation catalogRelation;
+ SysScanDesc scan;
+ ScanKeyData key;
+ HeapTuple inheritsTuple;
+ int32 inhseqno;
+ List *children;
+ ArrayType *inhvalues;
+
/*
* Must be owner of both parent and child -- child was checked by
* ATSimplePermissions call in ATPrepCmd
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7258,7264 ****
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("circular inheritance not allowed"),
errdetail("\"%s\" is already a child of \"%s\".",
! parent->relname,
RelationGetRelationName(child_rel))));
/* If parent has OIDs then child must have OIDs */
--- 7351,7357 ----
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("circular inheritance not allowed"),
errdetail("\"%s\" is already a child of \"%s\".",
! RelationGetRelationName(parent_rel),
RelationGetRelationName(child_rel))));
/* If parent has OIDs then child must have OIDs */
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7275,7293 ****
/* Match up the constraints and bump coninhcount as needed */
MergeConstraintsIntoExisting(child_rel, parent_rel);
/*
* OK, it looks valid. Make the catalog entries that show inheritance.
*/
StoreCatalogInheritance1(RelationGetRelid(child_rel),
RelationGetRelid(parent_rel),
inhseqno + 1,
catalogRelation);
/* Now we're done with pg_inherits */
heap_close(catalogRelation, RowExclusiveLock);
! /* keep our lock on the parent relation until commit */
! heap_close(parent_rel, NoLock);
}
/*
--- 7368,7776 ----
/* Match up the constraints and bump coninhcount as needed */
MergeConstraintsIntoExisting(child_rel, parent_rel);
+ /* Add CHECK constraint for partition */
+ if (def != NULL)
+ inhvalues = addPartitionConstraint(
+ wqueue, tab, def, parent_rel, child_rel);
+ else
+ inhvalues = NULL;
+
/*
* OK, it looks valid. Make the catalog entries that show inheritance.
*/
StoreCatalogInheritance1(RelationGetRelid(child_rel),
RelationGetRelid(parent_rel),
inhseqno + 1,
+ inhvalues,
catalogRelation);
/* Now we're done with pg_inherits */
heap_close(catalogRelation, RowExclusiveLock);
+ }
! /*
! * addPartitionConstraint - Add check constraint for partition.
! */
! static ArrayType *
! addPartitionConstraint(List **wqueue, AlteredTableInfo *tab, PartitionDef *def,
! Relation parent, Relation child)
! {
! HeapTuple tp;
! Form_pg_opclass opclassTup;
! char partkind;
! Node *partkey;
! Oid opclass;
! Oid opfamily;
! Oid opcintype;
! List *partitions;
! Oid elmtype;
! int16 elmlen;
! bool elmbyval;
! char elmalign;
! int16 strategy;
! Oid oprid;
! List *opr;
! FmgrInfo opfn;
! Node *check_expr;
! Datum *values;
! int nvalues;
!
! /* Retrieve partition information. */
! partitions = find_partitions(RelationGetRelid(parent),
! &partkind, &partkey, &opclass);
! if (partkind == 0)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! errmsg("table \"%s\" has no partition key",
! RelationGetRelationName(parent))));
! if (partkind != def->kind)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! errmsg("cannot add partition \"%s\" to \"%s\": partition kind mismatch",
! RelationGetRelationName(child),
! RelationGetRelationName(parent))));
!
! /* Check for duplicated overflow partitions */
! if (list_length(partitions) > 0 &&
! ((Partition *) llast(partitions))->nvalues == 0)
! {
! if (def->values == NIL)
! ereport(ERROR,
! (errcode(ERRCODE_DUPLICATE_TABLE),
! errmsg("duplicated overflow partition")));
! else
! ereport(ERROR,
! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("cannot add partition to table that has overflow partition")));
! }
!
! /* Retrieve type information and convert expressions into datum array. */
! elmtype = exprType(partkey);
! get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
! values = evaluateValues(elmtype, elmlen, elmbyval, def->values, &nvalues);
!
! /* Retrieve operator information. */
! tp = SearchSysCache(CLAOID, ObjectIdGetDatum(opclass), 0, 0, 0);
! if (!HeapTupleIsValid(tp))
! elog(ERROR, "cache lookup failed for opclass %u", opclass);
! opclassTup = (Form_pg_opclass) GETSTRUCT(tp);
! opfamily = opclassTup->opcfamily;
! opcintype = opclassTup->opcintype;
! ReleaseSysCache(tp);
!
! if (!OidIsValid(opcintype))
! opcintype = elmtype;
!
! switch (partkind)
! {
! case PARTITION_BY_RANGE:
! strategy = BTLessStrategyNumber;
! break;
! case PARTITION_BY_LIST:
! strategy = BTEqualStrategyNumber;
! break;
! default:
! strategy = 0;
! }
! oprid = get_opfamily_member(opfamily, opcintype, opcintype, strategy);
! if (!OidIsValid(oprid))
! elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
! strategy, opcintype, opcintype, opfamily);
! opr = get_opfullname(oprid);
! fmgr_info(get_opcode(oprid), &opfn);
!
! /* ALTER TABLE ... ADD CHECK */
! switch (partkind)
! {
! case PARTITION_BY_RANGE:
! {
! Partition *left;
! Partition *right;
! Node *lt = NULL;
! Node *ge = NULL;
!
! /* Check for overlapped list partition values. */
! if (nvalues > 0)
! {
! Assert(nvalues == 1);
! lt = (Node *) makeA_Expr(
! AEXPR_OP, opr, partkey, linitial(def->values), -1);
! findRangePartition(values[0], partitions, &opfn, &left, &right);
! }
! else
! {
! left = (list_length(partitions) > 0 ? llast(partitions) : NULL);
! right = NULL;
! }
!
! /* TODO: split overlapped partition */
! if (right != NULL)
! ereport(ERROR,
! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("cannot split partition \"%s\"",
! get_rel_name(right->relid))));
!
! if (left)
! {
! Oid oprle;
! Node *lower;
!
! oprle = get_opfamily_member(opfamily, opcintype, opcintype,
! BTLessEqualStrategyNumber);
! if (!OidIsValid(oprid))
! elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
! BTLessEqualStrategyNumber, opcintype, opcintype, opfamily);
! lower = (Node *) makeConst(elmtype, -1, elmlen,
! left->values[0], false, elmbyval);
! /* lower <= key */
! ge = (Node *) makeA_Expr(AEXPR_OP,
! get_opfullname(oprle), lower, partkey, -1);
! }
!
! if (ge == NULL) /* key < upper */
! check_expr = lt;
! else if (lt == NULL) /* key >= lower */
! check_expr = ge;
! else /* key >= lower AND key < upper */
! check_expr = (Node *) makeA_Expr(AEXPR_AND, NIL, ge, lt, -1);
! break;
! }
! case PARTITION_BY_LIST:
! {
! if (nvalues > 0)
! {
! Partition *overlapped;
!
! /* Check for overlapped list partition values. */
! overlapped = findOverlappedListPartition(
! values, nvalues, partitions, &opfn);
!
! /* TODO: split overlapped partition */
! if (overlapped != NULL)
! ereport(ERROR,
! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("partition values overlapped with \"%s\"",
! get_rel_name(overlapped->relid))));
!
! /* CHECK ( key = ANY ( values ) ) */
! check_expr = (Node *) makeA_Expr(AEXPR_IN, opr, partkey,
! (Node *) def->values, -1);
! }
! else
! {
! List *all_values = gatherPartitionValues(
! partitions, elmtype, elmlen, elmbyval);
!
! /* CHECK ( NOT (key = ANY ( values ) ) ) */
! if (all_values == NIL)
! check_expr = NULL;
! else
! check_expr = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
! (Node *) makeA_Expr(AEXPR_IN, opr,
! partkey, (Node *) all_values, -1), -1);
! }
!
! break;
! }
! default:
! elog(ERROR, "unknown partition kind: %d", partkind);
! check_expr = NULL; /* keep compiler quiet */
! }
!
! /* Add partition constraint if there are no same check constraint. */
! if (check_expr != NULL)
! {
! TupleConstr *constr;
! Node *cooked_expr = NULL;
! bool found = false;
!
! if ((constr = RelationGetDescr(child)->constr) != NULL)
! {
! ParseState *pstate;
! RangeTblEntry *rte;
! int i;
!
! pstate = make_parsestate(NULL);
! rte = addRangeTableEntryForRelation(pstate, child, NULL, false, true);
! addRTEtoQuery(pstate, rte, true, true, true);
! cooked_expr = cookConstraint(pstate, check_expr,
! RelationGetRelationName(child));
! free_parsestate(pstate);
!
! for (i = 0; i < constr->num_check; i++)
! {
! if (equal(cooked_expr, stringToNode(constr->check[i].ccbin)))
! {
! found = true;
! break;
! }
! }
! }
!
! /* Add a new check constraint only when not found. */
! if (!found)
! {
! Constraint *check;
!
! check = makeNode(Constraint);
! check->contype = CONSTR_CHECK;
! check->location = -1;
! check->raw_expr = (cooked_expr ? NULL : check_expr);
! check->cooked_expr = (cooked_expr ? nodeToString(cooked_expr) : NULL);
! ATAddCheckConstraint(wqueue, tab, child, check, false, false);
! }
! }
!
! /* overflow partition has an empty array. */
! return construct_array(values, nvalues, elmtype, elmlen, elmbyval, elmalign);
! }
!
! /*
! * Return left and right range partitions.
! */
! static void
! findRangePartition(Datum value, List *partitions, FmgrInfo *ltfn,
! Partition **left, Partition **right)
! {
! ListCell *cell;
!
! Assert(left != NULL);
! Assert(right != NULL);
!
! *left = *right = NULL;
!
! foreach(cell, partitions)
! {
! Partition *p = (Partition *) lfirst(cell);
!
! if (p->nvalues > 0 &&
! DatumGetBool(FunctionCall2(ltfn, p->values[0], value)))
! {
! /* left < p < value */
! if (*left == NULL || DatumGetBool(FunctionCall2(ltfn,
! (*left)->values[0], p->values[0])))
! *left = p;
! }
! else
! {
! /* value <= p < right */
! if (*right == NULL || (*right)->nvalues == 0 ||
! (p->nvalues > 0 && DatumGetBool(FunctionCall2(ltfn,
! p->values[0], (*right)->values[0]))))
! *right = p;
! }
! }
! }
!
! /*
! * Return an overlapped list partition, or NULL if not found.
! */
! static Partition *
! findOverlappedListPartition(const Datum *values, int nvalues,
! List *partitions, FmgrInfo *eqfn)
! {
! ListCell *cell;
! int i;
! int j;
!
! foreach(cell, partitions)
! {
! Partition *p = (Partition *) lfirst(cell);
!
! for (i = 0; i < p->nvalues; i++)
! for (j = 0; j < nvalues; j++)
! if (DatumGetBool(FunctionCall2(eqfn, p->values[i], values[j])))
! return p;
! }
!
! return NULL;
! }
!
! /*
! * Gather partition values as a list of Const nodes.
! */
! static List *
! gatherPartitionValues(List *partitions, Oid elmtype, int elmlen, bool elmbyval)
! {
! List *all_values = NIL;
! ListCell *cell;
! int i;
!
! foreach(cell, partitions)
! {
! Partition *p = (Partition *) lfirst(cell);
!
! for (i = 0; i < p->nvalues; i++)
! {
! Const *value = makeConst(elmtype, -1, elmlen,
! p->values[i], false, elmbyval);
! all_values = lappend(all_values, value);
! }
! }
!
! return all_values;
! }
!
! /*
! * evaluateValues - evaluate a list of expressions to build a datum array.
! */
! static Datum *
! evaluateValues(Oid typid, int typlen, bool typbyval, List *values, int *length)
! {
! ListCell *cell;
! ParseState *pstate;
! EState *estate;
! ExprContext *econtext;
! int i;
! Datum *datum;
!
! *length = list_length(values);
! if (*length < 1)
! return NULL;
!
! datum = (Datum *) palloc(*length * sizeof(Datum));
! pstate = make_parsestate(NULL);
! estate = CreateExecutorState();
! econtext = GetPerTupleExprContext(estate);
!
! i = 0;
! foreach(cell, values)
! {
! Node *value = (Node *) lfirst(cell);
! bool isnull;
! ExprState *expr;
! MemoryContext oldcxt;
!
! oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
!
! value = transformExpr(pstate, value);
! value = coerce_to_specific_type(pstate, value, typid, "PARTITION");
! expr = ExecPrepareExpr((Expr *) value, estate);
!
! datum[i] = ExecEvalExpr(expr, econtext, &isnull, NULL);
! if (isnull)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! errmsg("partition key must not be NULL")));
!
! MemoryContextSwitchTo(oldcxt);
!
! if (!typbyval)
! {
! if (typlen == -1)
! datum[i] = PointerGetDatum(PG_DETOAST_DATUM_COPY(datum[i]));
! else
! datum[i] = datumCopy(datum[i], false, typlen);
! }
!
! ResetPerTupleExprContext(estate);
! i++;
! }
!
! FreeExecutorState(estate);
! free_parsestate(pstate);
!
! return datum;
}
/*
*************** MergeConstraintsIntoExisting(Relation ch
*** 7520,7526 ****
}
/*
! * ALTER TABLE NO INHERIT
*
* Drop a parent from the child's parents. This just adjusts the attinhcount
* and attislocal of the columns and removes the pg_inherit and pg_depend
--- 8003,8009 ----
}
/*
! * ALTER TABLE NO INHERIT / DETACH PARTITION
*
* Drop a parent from the child's parents. This just adjusts the attinhcount
* and attislocal of the columns and removes the pg_inherit and pg_depend
*************** static void
*** 7539,7544 ****
--- 8022,8057 ----
ATExecDropInherit(Relation rel, RangeVar *parent)
{
Relation parent_rel;
+
+ /*
+ * AccessShareLock on the parent is probably enough, seeing that DROP
+ * TABLE doesn't lock parent tables at all. We need some lock since we'll
+ * be inspecting the parent's schema.
+ */
+ parent_rel = heap_openrv(parent, AccessShareLock);
+
+ dropInherit(rel, parent_rel);
+
+ /* close rel, but keep lock until commit */
+ relation_close(parent_rel, NoLock);
+ }
+
+ static void
+ ATExecDetachPartition(Relation rel, RangeVar *child)
+ {
+ Relation child_rel;
+
+ child_rel = heap_openrv(child, AccessExclusiveLock);
+
+ dropInherit(child_rel, rel);
+
+ /* close rel, but keep lock until commit */
+ relation_close(child_rel, NoLock);
+ }
+
+ static void
+ dropInherit(Relation rel, Relation parent_rel)
+ {
Relation catalogRelation;
SysScanDesc scan;
ScanKeyData key[3];
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7550,7562 ****
bool found = false;
/*
- * AccessShareLock on the parent is probably enough, seeing that DROP
- * TABLE doesn't lock parent tables at all. We need some lock since we'll
- * be inspecting the parent's schema.
- */
- parent_rel = heap_openrv(parent, AccessShareLock);
-
- /*
* We don't bother to check ownership of the parent table --- ownership of
* the child is presumed enough rights.
*/
--- 8063,8068 ----
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7747,7755 ****
systable_endscan(scan);
heap_close(catalogRelation, RowExclusiveLock);
! /* keep our lock on the parent relation until commit */
! heap_close(parent_rel, NoLock);
}
--- 8253,8353 ----
systable_endscan(scan);
heap_close(catalogRelation, RowExclusiveLock);
+ }
!
! /*
! * ALTER TABLE PARTITION BY / NO PARTITION
! */
! static void
! ATExecPartitionBy(Relation rel, PartitionBy *defs)
! {
! Oid relid = RelationGetRelid(rel);
! HeapTuple tp;
! ObjectAddress myself;
!
! tp = SearchSysCache(PARTITIONKEY, ObjectIdGetDatum(relid), 0, 0, 0);
! if (HeapTupleIsValid(tp))
! {
! if (defs != NULL)
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! errmsg("multiple partition keys for table \"%s\" are not allowed",
! RelationGetRelationName(rel))));
! ReleaseSysCache(tp);
! }
! else if (defs == NULL)
! {
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! errmsg("table \"%s\" has no partition key",
! RelationGetRelationName(rel))));
! }
!
! myself.classId = PartitionRelationId;
! myself.objectId = relid;
! myself.objectSubId = 0;
!
! if (defs == NULL)
! {
! /* ALTER TABLE NO PARTITION */
! performDeletion(&myself, DROP_RESTRICT);
! }
! else
! {
! /* ALTER TABLE PARTITION BY ... */
! Relation catalogRel;
! TupleDesc catalogDesc;
! Datum datum[Natts_pg_partition];
! bool nulls[Natts_pg_partition];
! HeapTuple tuple;
! Node *partkey;
! Oid keytype;
! Oid opclass;
! ParseState *pstate;
! RangeTblEntry *rte;
! ObjectAddress opclassObject;
!
! Assert(defs->key != NULL);
!
! /* 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);
! opclass = GetIndexOpClass(defs->opclass, keytype, "btree", BTREE_AM_OID);
!
! /*
! * Make the pg_partition entry
! */
! memset(nulls, 0, sizeof(nulls));
! datum[0] = ObjectIdGetDatum(relid); /* partrelid */
! datum[1] = ObjectIdGetDatum(opclass); /* partopclass */
! 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);
! opclassObject.classId = OperatorClassRelationId;
! opclassObject.objectId = opclass;
! opclassObject.objectSubId = 0;
! recordDependencyOn(&myself, &opclassObject, DEPENDENCY_NORMAL);
!
! heap_close(catalogRel, RowExclusiveLock);
! }
}
diff -cprN head/src/backend/nodes/copyfuncs.c work/src/backend/nodes/copyfuncs.c
*** head/src/backend/nodes/copyfuncs.c 2009-11-21 05:38:10.000000000 +0900
--- work/src/backend/nodes/copyfuncs.c 2009-11-25 16:12:51.585395565 +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
*** 3448,3453 ****
--- 3449,3492 ----
return newnode;
}
+ static PartitionDef *
+ _copyPartitionDef(PartitionDef *from)
+ {
+ PartitionDef *newnode = makeNode(PartitionDef);
+
+ COPY_SCALAR_FIELD(kind);
+ COPY_NODE_FIELD(name);
+ COPY_NODE_FIELD(values);
+ 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(opclass);
+ 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)
*** 4115,4120 ****
--- 4154,4168 ----
case T_AlterTSConfigurationStmt:
retval = _copyAlterTSConfigurationStmt(from);
break;
+ case T_PartitionDef:
+ retval = _copyPartitionDef(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-11-21 05:38:10.000000000 +0900
--- work/src/backend/nodes/equalfuncs.c 2009-11-25 16:12:51.586400236 +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
*** 1898,1903 ****
--- 1899,1936 ----
}
static bool
+ _equalPartitionDef(PartitionDef *a, PartitionDef *b)
+ {
+ COMPARE_SCALAR_FIELD(kind);
+ COMPARE_NODE_FIELD(name);
+ COMPARE_NODE_FIELD(values);
+ 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(opclass);
+ 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)
*** 2808,2813 ****
--- 2841,2855 ----
case T_AlterTSConfigurationStmt:
retval = _equalAlterTSConfigurationStmt(a, b);
break;
+ case T_PartitionDef:
+ retval = _equalPartitionDef(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-11-15 11:45:34.000000000 +0900
--- work/src/backend/nodes/outfuncs.c 2009-11-25 16:12:51.586400236 +0900
*************** _outCreateStmt(StringInfo str, CreateStm
*** 1783,1788 ****
--- 1783,1789 ----
WRITE_NODE_FIELD(options);
WRITE_ENUM_FIELD(oncommit, OnCommitAction);
WRITE_STRING_FIELD(tablespacename);
+ WRITE_NODE_FIELD(partitions);
}
static void
*************** _outConstraint(StringInfo str, Constrain
*** 2420,2425 ****
--- 2421,2449 ----
}
}
+ static void
+ _outPartition(StringInfo str, PartitionDef *node)
+ {
+ WRITE_NODE_TYPE("PARTITIONDEF");
+
+ WRITE_CHAR_FIELD(kind);
+ WRITE_NODE_FIELD(name);
+ WRITE_NODE_FIELD(values);
+ 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(opclass);
+ WRITE_NODE_FIELD(defs);
+ }
+
/*
* _outNode -
*************** _outNode(StringInfo str, void *obj)
*** 2873,2878 ****
--- 2897,2908 ----
case T_XmlSerialize:
_outXmlSerialize(str, obj);
break;
+ case T_PartitionDef:
+ _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-11-21 05:38:10.000000000 +0900
--- work/src/backend/parser/gram.y 2009-11-25 16:12:51.589395492 +0900
*************** static TypeName *TableFuncTypeName(List
*** 178,183 ****
--- 178,185 ----
AccessPriv *accesspriv;
InsertStmt *istmt;
VariableSetStmt *vsetstmt;
+ PartitionDef *partition;
+ PartitionBy *partitionby;
}
%type stmt schema_stmt
*************** static TypeName *TableFuncTypeName(List
*** 193,199 ****
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
--- 195,201 ----
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
*** 432,437 ****
--- 434,443 ----
%type opt_existing_window_name
%type opt_frame_clause frame_extent frame_bound
+ %type RangePartition ListPartition AnyPartition
+ %type PartitionBy OptPartition
+ %type OptRangePartitions RangePartitions RangeUpper
+ OptListPartitions ListPartitions ListValues ConstValues
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
*************** static TypeName *TableFuncTypeName(List
*** 456,462 ****
/* ordinary key words in alphabetical order */
%token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
! ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION
BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
BOOLEAN_P BOTH BY
--- 462,468 ----
/* ordinary key words in alphabetical order */
%token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
! ASSERTION ASSIGNMENT ASYMMETRIC AT ATTACH AUTHORIZATION
BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
BOOLEAN_P BOTH BY
*************** static TypeName *TableFuncTypeName(List
*** 471,477 ****
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
! 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
--- 477,483 ----
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
! DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC DETACH
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
*************** static TypeName *TableFuncTypeName(List
*** 494,500 ****
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
--- 500,506 ----
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
*** 522,528 ****
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
--- 528,534 ----
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 :
*** 676,681 ****
--- 682,688 ----
| CreateRoleStmt
| CreateUserStmt
| CreateUserMappingStmt
+ | CreatePartitionStmt
| CreatedbStmt
| DeallocateStmt
| DeclareCursorStmt
*************** schema_stmt:
*** 1134,1139 ****
--- 1141,1147 ----
| CreateTrigStmt
| GrantStmt
| ViewStmt
+ | CreatePartitionStmt
;
*************** AlterTableStmt:
*** 1559,1564 ****
--- 1567,1580 ----
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:
*** 1882,1887 ****
--- 1898,1935 ----
n->def = (Node *)$2;
$$ = (Node *)n;
}
+ /* ALTER TABLE PARTITION BY ... */
+ | PartitionBy
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_PartitionBy;
+ n->def = (Node *)$1;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE NO PARTITION */
+ | NO PARTITION
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_PartitionBy;
+ n->def = NULL;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE ATTACH PARTITION */
+ | ATTACH AnyPartition
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_AttachPartition;
+ n->def = (Node *) $2;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE DETACH PARTITION */
+ | DETACH PARTITION qualified_name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_DetachPartition;
+ n->def = (Node *) $3;
+ $$ = (Node *)n;
+ }
;
alter_column_default:
*************** copy_generic_opt_arg_list_item:
*** 2169,2175 ****
*****************************************************************************/
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
! OptInherit OptWith OnCommitOption OptTableSpace
{
CreateStmt *n = makeNode(CreateStmt);
$4->istemp = $2;
--- 2217,2223 ----
*****************************************************************************/
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
! OptInherit OptWith OnCommitOption OptTableSpace OptPartition
{
CreateStmt *n = makeNode(CreateStmt);
$4->istemp = $2;
*************** CreateStmt: CREATE OptTemp TABLE qualifi
*** 2180,2189 ****
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 (cols) seems to be satisfied
* by our inheritance capabilities. Let's try it...
--- 2228,2238 ----
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 (cols) seems to be satisfied
* by our inheritance capabilities. Let's try it...
*************** CreateStmt: CREATE OptTemp TABLE qualifi
*** 2197,2206 ****
--- 2246,2371 ----
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 ')' opt_class OptRangePartitions
+ {
+ PartitionBy *n = makeNode(PartitionBy);
+
+ n->kind = PARTITION_BY_RANGE;
+ n->key = $5;
+ n->opclass = $7;
+ n->defs = $8;
+ $$ = n;
+ }
+ | PARTITION BY LIST '(' a_expr ')' opt_class OptListPartitions
+ {
+ PartitionBy *n = makeNode(PartitionBy);
+ n->kind = PARTITION_BY_LIST;
+ n->key = $5;
+ n->opclass = $7;
+ n->defs = $8;
+ $$ = n;
+ }
+ ;
+
+ 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
+ {
+ PartitionDef *n = makeNode(PartitionDef);
+ n->kind = PARTITION_BY_RANGE;
+ n->name = $2;
+ n->values = $6;
+ n->options = $7;
+ n->tablespacename = $8;
+ $$ = n;
+ }
+ ;
+
+ RangeUpper:
+ AexprConst { $$ = list_make1($1); }
+ | '(' AexprConst ')' { $$ = list_make1($2); }
+ | MAXVALUE { $$ = NIL; }
+ | '(' MAXVALUE ')' { $$ = NIL; }
+ ;
+
+ 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
+ {
+ PartitionDef *n = makeNode(PartitionDef);
+ n->kind = PARTITION_BY_LIST;
+ n->name = $2;
+ n->values = $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); }
+ ;
+
+ /* for ALTER TABLE ATTACH PARTITION. No WITH and TABLESPACE supported. */
+ AnyPartition:
+ PARTITION qualified_name VALUES LESS THAN RangeUpper
+ {
+ PartitionDef *n = makeNode(PartitionDef);
+ n->kind = PARTITION_BY_RANGE;
+ n->name = $2;
+ n->values = $6;
+ $$ = n;
+ }
+ | PARTITION qualified_name VALUES opt_in ListValues
+ {
+ PartitionDef *n = makeNode(PartitionDef);
+ n->kind = PARTITION_BY_LIST;
+ n->name = $2;
+ n->values = $5;
+ $$ = n;
+ }
+ ;
+
/*
* Redundancy here is needed to avoid shift/reduce conflicts,
* since TEMP is not a reserved word. See also OptTempTableName.
*************** opt_with_data:
*** 2682,2687 ****
--- 2847,2888 ----
/*****************************************************************************
*
* 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(PartitionDef);
+ n->def->kind = PARTITION_BY_RANGE;
+ n->def->name = $3;
+ n->def->values = $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(PartitionDef);
+ n->def->kind = PARTITION_BY_LIST;
+ n->def->name = $3;
+ n->def->values = $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
*** 3934,3939 ****
--- 4135,4141 ----
drop_type: TABLE { $$ = OBJECT_TABLE; }
+ | PARTITION { $$ = OBJECT_TABLE; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
| VIEW { $$ = OBJECT_VIEW; }
| INDEX { $$ = OBJECT_INDEX; }
*************** RenameStmt: ALTER AGGREGATE func_name ag
*** 5561,5566 ****
--- 5763,5777 ----
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:
*** 5721,5726 ****
--- 5932,5945 ----
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:
*** 10560,10565 ****
--- 10779,10785 ----
| ASSERTION
| ASSIGNMENT
| AT
+ | ATTACH
| BACKWARD
| BEFORE
| BEGIN_P
*************** unreserved_keyword:
*** 10606,10611 ****
--- 10826,10832 ----
| DELETE_P
| DELIMITER
| DELIMITERS
+ | DETACH
| DICTIONARY
| DISABLE_P
| DISCARD
*************** unreserved_keyword:
*** 10661,10667 ****
--- 10882,10890 ----
| LAST_P
| LC_COLLATE_P
| LC_CTYPE_P
+ | LESS
| LEVEL
+ | LIST
| LISTEN
| LOAD
| LOCAL
*************** unreserved_keyword:
*** 10767,10772 ****
--- 10990,10996 ----
| 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-11-14 08:49:23.000000000 +0900
--- work/src/backend/parser/parse_utilcmd.c 2009-11-25 16:12:51.589395492 +0900
*************** static void transformFKConstraints(Parse
*** 114,119 ****
--- 114,120 ----
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);
*************** transformCreateStmt(CreateStmt *stmt, co
*** 233,238 ****
--- 234,257 ----
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
*** 1425,1430 ****
--- 1444,1517 ----
}
}
+ /* CREATE PARTITION */
+ List *
+ transformCreatePartition(PartitionDef *def, RangeVar *parent)
+ {
+ List *result = NIL;
+ CreateStmt *create;
+ InhRelation *like;
+ AlterTableStmt *alter;
+ AlterTableCmd *attach;
+ PartitionDef *partition;
+
+ /* Use the same schema as the parent if not specified. */
+ if (def->name->schemaname == NULL)
+ def->name->schemaname = parent->schemaname;
+ def->name->istemp = parent->istemp;
+
+ /* CREATE TABLE partition (LIKE parent INCLUDING ALL) */
+ like = makeNode(InhRelation);
+ like->relation = parent;
+ like->options = CREATE_TABLE_LIKE_ALL;
+ create = makeNode(CreateStmt);
+ create->relation = def->name;
+ create->tableElts = list_make1(like);
+ create->inhRelations = NIL;
+ create->constraints = NIL;
+ create->options = def->options;
+ create->oncommit = ONCOMMIT_NOOP;
+ create->tablespacename = def->tablespacename;
+ create->partitions = NULL;
+ result = lappend(result, create);
+
+ /* ALTER TABLE partition INHERIT parent (AS PARTITION) */
+ partition = makeNode(PartitionDef);
+ partition->kind = def->kind;;
+ partition->name = def->name;
+ partition->values = def->values;
+ attach = makeNode(AlterTableCmd);
+ attach->subtype = AT_AttachPartition;
+ attach->def = (Node *) partition;
+ alter = makeNode(AlterTableStmt);
+ alter->relation = parent;
+ alter->cmds = list_make1(attach);
+ alter->relkind = OBJECT_TABLE;
+ result = lappend(result, alter);
+
+ return result;
+ }
+
+ /* PARTITION BY / NO PARTITION */
+ static void
+ transformPartitionBy(ParseState *pstate, CreateStmtContext *cxt,
+ PartitionBy *partitions)
+ {
+ ListCell *cell;
+
+ if (partitions == NULL)
+ return;
+
+ /* Expand partition clauses to CREATE TABLE. */
+ foreach (cell, partitions->defs)
+ {
+ PartitionDef *def = (PartitionDef *) lfirst(cell);
+
+ cxt->alist = list_concat(cxt->alist,
+ transformCreatePartition(def, cxt->relation));
+ }
+ }
+
/*
* transformIndexStmt - parse analysis for CREATE INDEX
*
*************** transformAlterTableStmt(AlterTableStmt *
*** 1909,1914 ****
--- 1996,2006 ----
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-11-21 05:38:11.000000000 +0900
--- work/src/backend/tcop/utility.c 2009-11-25 16:12:51.590396315 +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/adt/ruleutils.c work/src/backend/utils/adt/ruleutils.c
*** head/src/backend/utils/adt/ruleutils.c 2009-11-21 05:38:11.000000000 +0900
--- work/src/backend/utils/adt/ruleutils.c 2009-11-25 16:57:09.486451481 +0900
***************
*** 26,31 ****
--- 26,32 ----
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_language.h"
+ #include "catalog/pg_inherits_fn.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
*************** pg_get_function_result(PG_FUNCTION_ARGS)
*** 1804,1809 ****
--- 1805,1945 ----
}
/*
+ * pg_get_partitiondef - Get the definition of a partition
+ */
+ Datum
+ pg_get_partitiondef(PG_FUNCTION_ARGS)
+ {
+ Oid parentOid = PG_GETARG_OID(0);
+ bool alter_fmt = PG_GETARG_OID(1);
+
+ Oid parentNsp = get_rel_namespace(parentOid);
+ char *parentName;
+ char partkind;
+ Node *partkey;
+ Oid partopclass;
+ List *partitions;
+ Oid typid;
+ const char *prefix;
+ const char *suffix;
+ const char *overflow;
+ StringInfoData buf;
+
+ partitions = find_partitions(parentOid, &partkind, &partkey, &partopclass);
+ if (partkind == 0)
+ PG_RETURN_NULL(); /* not partitioned */
+
+ typid = exprType(partkey);
+
+ initStringInfo(&buf);
+
+ /* Append definition of partition key. */
+ if (alter_fmt)
+ {
+ parentName = quote_qualified_identifier(
+ get_namespace_name(parentNsp), get_rel_name(parentOid));
+
+ appendStringInfo(&buf, "ALTER TABLE %s PARTITION BY ", parentName);
+ }
+ else
+ parentName = NULL;
+
+ switch (partkind)
+ {
+ case PARTITION_BY_RANGE:
+ appendStringInfoString(&buf, "RANGE");
+ prefix = "LESS THAN ";
+ suffix = "";
+ overflow = "MAXVALUE";
+ break;
+ case PARTITION_BY_LIST:
+ appendStringInfoString(&buf, "LIST");
+ prefix = "(";
+ suffix = ")";
+ overflow = "DEFAULT";
+ break;
+ default:
+ elog(ERROR, "unknown partition kind: %d", partkind);
+ prefix = suffix = overflow = NULL;
+ break;
+ }
+ appendStringInfoString(&buf, " (");
+ appendStringInfoString(&buf, deparse_expression_pretty(
+ partkey, deparse_context_for(get_rel_name(parentOid), parentOid),
+ false, false, 0, 0));
+ appendStringInfoChar(&buf, ')');
+ get_opclass_name(partopclass, typid, &buf);
+
+ /* Append definitions of partitions. */
+ if (list_length(partitions) > 0)
+ {
+ ListCell *cell;
+ Oid typoutput;
+ bool typIsVarlena;
+ FmgrInfo outfn;
+ bool needcomma = false;
+
+ getTypeOutputInfo(typid, &typoutput, &typIsVarlena);
+ fmgr_info(typoutput, &outfn);
+
+ if (alter_fmt)
+ appendStringInfoString(&buf, ";\n");
+ else
+ appendStringInfoString(&buf, "\n(\n");
+
+ foreach(cell, partitions)
+ {
+ Partition *p = (Partition *) lfirst(cell);
+ Oid childNsp;
+ char *nspname;
+ char *name;
+
+ /* Hide namespace if parent and child are in the same namespace. */
+ if ((childNsp = get_rel_namespace(p->relid)) != parentNsp)
+ nspname = get_namespace_name(childNsp);
+ else
+ nspname = NULL;
+ name = quote_qualified_identifier(nspname, get_rel_name(p->relid));
+
+ if (needcomma)
+ appendStringInfoString(&buf, ",\n");
+
+ if (alter_fmt)
+ appendStringInfo(&buf, "ALTER TABLE %s ATTACH ", parentName);
+ else
+ appendStringInfoString(&buf, " ");
+ appendStringInfo(&buf, "PARTITION %s VALUES ", name);
+
+ appendStringInfoString(&buf, prefix);
+ if (p->nvalues > 0)
+ {
+ int i;
+
+ for (i = 0; i < p->nvalues; i++)
+ {
+ if (i > 0)
+ appendStringInfo(&buf, ", ");
+ simple_quote_literal(&buf, DatumGetCString(
+ OutputFunctionCall(&outfn, p->values[i])));
+ }
+ }
+ else
+ appendStringInfoString(&buf, overflow);
+ appendStringInfoString(&buf, suffix);
+
+ if (alter_fmt)
+ appendStringInfoString(&buf, ";\n");
+ else
+ needcomma = true;
+ }
+ if (!alter_fmt)
+ appendStringInfoString(&buf, "\n)");
+ }
+
+ PG_RETURN_TEXT_P(string_to_text(buf.data));
+ }
+
+ /*
* Guts of pg_get_function_result: append the function's return type
* to the specified buffer.
*/
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-25 16:12:51.591708759 +0900
***************
*** 32,39 ****
--- 32,41 ----
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
+ #include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+ #include "utils/tqual.h"
/* Hook for plugins to get control in get_attavgwidth() */
get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
*************** get_opname(Oid opno)
*** 1058,1063 ****
--- 1060,1088 ----
return NULL;
}
+ 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 NULL;
+ }
+
/*
* op_input_types
*
*************** get_roleid_checked(const char *rolname)
*** 2776,2778 ****
--- 2801,2804 ----
errmsg("role \"%s\" does not exist", rolname)));
return roleid;
}
+
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-25 16:12:51.592708149 +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/bin/pg_dump/common.c work/src/bin/pg_dump/common.c
*** head/src/bin/pg_dump/common.c 2009-10-06 04:24:45.000000000 +0900
--- work/src/bin/pg_dump/common.c 2009-11-25 16:12:51.592708149 +0900
*************** getSchemaData(int *numTablesPtr)
*** 222,227 ****
--- 222,231 ----
write_msg(NULL, "reading triggers\n");
getTriggers(tblinfo, numTables);
+ if (g_verbose)
+ write_msg(NULL, "reading partitions\n");
+ getPartitions(tblinfo, numTables);
+
*numTablesPtr = numTables;
return tblinfo;
}
diff -cprN head/src/bin/pg_dump/pg_dump.c work/src/bin/pg_dump/pg_dump.c
*** head/src/bin/pg_dump/pg_dump.c 2009-11-21 05:38:11.000000000 +0900
--- work/src/bin/pg_dump/pg_dump.c 2009-11-25 16:49:27.735395666 +0900
*************** static void dumpUserMappings(Archive *fo
*** 164,169 ****
--- 164,170 ----
const char *servername, const char *namespace,
const char *owner, CatalogId catalogId, DumpId dumpId);
static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
+ static void dumpPartition(Archive *fout, PartitionInfo *partinfo);
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name, const char *subname,
*************** getInherits(int *numInherits)
*** 3624,3630 ****
/* find all the inheritance information */
! appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
--- 3625,3635 ----
/* find all the inheritance information */
! if (g_fout->remoteVersion >= 80500)
! appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits "
! "WHERE inhvalues IS NULL");
! else
! appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
*************** getDefaultACLs(int *numDefaultACLs)
*** 5793,5798 ****
--- 5798,5871 ----
}
/*
+ * getTriggers
+ * get information about every partition on a dumpable table
+ *
+ * Note: partition data is not returned directly to the caller, but it
+ * does get entered into the DumpableObject tables.
+ */
+ void
+ getPartitions(TableInfo tblinfo[], int numTables)
+ {
+ int i,
+ j;
+ PQExpBuffer query = createPQExpBuffer();
+ PGresult *res;
+ PartitionInfo *partinfo;
+ int i_partrelid,
+ i_partdef;
+ int ntups;
+
+ if (g_fout->remoteVersion < 80500)
+ return;
+
+ appendPQExpBuffer(query,
+ "SELECT "
+ "partrelid, "
+ "pg_get_partitiondef(partrelid, true) AS partdef "
+ "FROM pg_partition");
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ i_partrelid = PQfnumber(res, "partrelid");
+ i_partdef = PQfnumber(res, "partdef");
+
+ ntups = PQntuples(res);
+ partinfo = (PartitionInfo *) malloc(ntups * sizeof(PartitionInfo));
+
+ for (j = 0; j < ntups; j++)
+ {
+ Oid relid = atooid(PQgetvalue(res, j, i_partrelid));
+
+ for (i = 0; i < numTables; i++)
+ {
+ TableInfo *tbinfo = &tblinfo[i];
+
+ if (tbinfo->dobj.catId.oid == relid)
+ {
+ if (g_verbose)
+ write_msg(NULL, "reading partition for table \"%s\"\n",
+ tbinfo->dobj.name);
+
+ partinfo[j].dobj.objType = DO_PARTITION;
+ partinfo[j].dobj.catId.tableoid = 0;
+ partinfo[j].dobj.catId.oid = tbinfo->dobj.catId.oid;
+ AssignDumpId(&partinfo[j].dobj);
+ partinfo[j].dobj.name = tbinfo->dobj.name;
+ partinfo[j].dobj.namespace = tbinfo->dobj.namespace;
+ partinfo[j].dobj.dump = tbinfo->dobj.dump;
+ partinfo[j].parttable = tbinfo;
+ partinfo[j].partdef = strdup(PQgetvalue(res, j, i_partdef));
+ break;
+ }
+ }
+ }
+
+ PQclear(res);
+ destroyPQExpBuffer(query);
+ }
+
+ /*
* dumpComment --
*
* This routine is used to dump any comments associated with the
*************** dumpDumpableObject(Archive *fout, Dumpab
*** 6224,6229 ****
--- 6297,6305 ----
dobj->dependencies, dobj->nDeps,
dumpBlobComments, NULL);
break;
+ case DO_PARTITION:
+ dumpPartition(fout, (PartitionInfo *) dobj);
+ break;
}
}
*************** dumpRule(Archive *fout, RuleInfo *rinfo)
*** 11575,11580 ****
--- 11651,11691 ----
}
/*
+ * dumpPartition
+ * Dump a partition
+ */
+ static void
+ dumpPartition(Archive *fout, PartitionInfo *partinfo)
+ {
+ TableInfo *tbinfo = partinfo->parttable;
+ PQExpBuffer cmd;
+
+ /* Skip if not to be dumped */
+ if (!partinfo->dobj.dump || dataOnly)
+ return;
+
+ cmd = createPQExpBuffer();
+
+ appendPQExpBufferStr(cmd, partinfo->partdef);
+
+ /*
+ * DROP must be fully qualified in case same name appears in pg_catalog
+ */
+ ArchiveEntry(fout, partinfo->dobj.catId, partinfo->dobj.dumpId,
+ partinfo->dobj.name,
+ tbinfo->dobj.namespace->dobj.name,
+ NULL,
+ tbinfo->rolname, false,
+ "PARTITION", SECTION_POST_DATA,
+ cmd->data, "", NULL,
+ partinfo->dobj.dependencies, partinfo->dobj.nDeps,
+ NULL, NULL);
+
+ destroyPQExpBuffer(cmd);
+ }
+
+
+ /*
* getDependencies --- obtain available dependency data
*/
static void
diff -cprN head/src/bin/pg_dump/pg_dump.h work/src/bin/pg_dump/pg_dump.h
*** head/src/bin/pg_dump/pg_dump.h 2009-10-10 06:02:56.000000000 +0900
--- work/src/bin/pg_dump/pg_dump.h 2009-11-25 16:12:51.595396254 +0900
*************** typedef enum
*** 116,122 ****
DO_FOREIGN_SERVER,
DO_DEFAULT_ACL,
DO_BLOBS,
! DO_BLOB_COMMENTS
} DumpableObjectType;
typedef struct _dumpableObject
--- 116,123 ----
DO_FOREIGN_SERVER,
DO_DEFAULT_ACL,
DO_BLOBS,
! DO_BLOB_COMMENTS,
! DO_PARTITION
} DumpableObjectType;
typedef struct _dumpableObject
*************** typedef struct _defaultACLInfo
*** 442,447 ****
--- 443,455 ----
char *defaclacl;
} DefaultACLInfo;
+ typedef struct _partitionInfo
+ {
+ DumpableObject dobj;
+ TableInfo *parttable; /* link to table the partition is for */
+ char *partdef;
+ } PartitionInfo;
+
/* global decls */
extern bool force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose flag */
*************** extern TSConfigInfo *getTSConfigurations
*** 527,531 ****
--- 535,540 ----
extern FdwInfo *getForeignDataWrappers(int *numForeignDataWrappers);
extern ForeignServerInfo *getForeignServers(int *numForeignServers);
extern DefaultACLInfo *getDefaultACLs(int *numDefaultACLs);
+ extern void getPartitions(TableInfo tblinfo[], int numTables);
#endif /* PG_DUMP_H */
diff -cprN head/src/bin/pg_dump/pg_dump_sort.c work/src/bin/pg_dump/pg_dump_sort.c
*** head/src/bin/pg_dump/pg_dump_sort.c 2009-10-06 04:24:46.000000000 +0900
--- work/src/bin/pg_dump/pg_dump_sort.c 2009-11-25 16:12:51.595396254 +0900
*************** static const int oldObjectTypePriority[]
*** 56,62 ****
4, /* DO_FOREIGN_SERVER */
17, /* DO_DEFAULT_ACL */
10, /* DO_BLOBS */
! 11 /* DO_BLOB_COMMENTS */
};
/*
--- 56,63 ----
4, /* DO_FOREIGN_SERVER */
17, /* DO_DEFAULT_ACL */
10, /* DO_BLOBS */
! 11, /* DO_BLOB_COMMENTS */
! 18 /* DO_PARTITION */
};
/*
*************** static const int newObjectTypePriority[]
*** 76,89 ****
9, /* DO_CONVERSION */
16, /* DO_TABLE */
18, /* DO_ATTRDEF */
! 23, /* DO_INDEX */
! 24, /* DO_RULE */
! 25, /* DO_TRIGGER */
! 22, /* DO_CONSTRAINT */
! 26, /* DO_FK_CONSTRAINT */
2, /* DO_PROCLANG */
8, /* DO_CAST */
! 19, /* DO_TABLE_DATA */
17, /* DO_DUMMY_TYPE */
10, /* DO_TSPARSER */
12, /* DO_TSDICT */
--- 77,90 ----
9, /* DO_CONVERSION */
16, /* DO_TABLE */
18, /* DO_ATTRDEF */
! 24, /* DO_INDEX */
! 25, /* DO_RULE */
! 26, /* DO_TRIGGER */
! 23, /* DO_CONSTRAINT */
! 27, /* DO_FK_CONSTRAINT */
2, /* DO_PROCLANG */
8, /* DO_CAST */
! 20, /* DO_TABLE_DATA */
17, /* DO_DUMMY_TYPE */
10, /* DO_TSPARSER */
12, /* DO_TSDICT */
*************** static const int newObjectTypePriority[]
*** 91,99 ****
13, /* DO_TSCONFIG */
14, /* DO_FDW */
15, /* DO_FOREIGN_SERVER */
! 27, /* DO_DEFAULT_ACL */
! 20, /* DO_BLOBS */
! 21 /* DO_BLOB_COMMENTS */
};
--- 92,101 ----
13, /* DO_TSCONFIG */
14, /* DO_FDW */
15, /* DO_FOREIGN_SERVER */
! 28, /* DO_DEFAULT_ACL */
! 21, /* DO_BLOBS */
! 22, /* DO_BLOB_COMMENTS */
! 19 /* DO_PARTITION */
};
*************** describeDumpableObject(DumpableObject *o
*** 1156,1161 ****
--- 1158,1168 ----
"BLOB COMMENTS (ID %d)",
obj->dumpId);
return;
+ case DO_PARTITION:
+ snprintf(buf, bufsize,
+ "PARTITION %s (ID %d OID %u)",
+ obj->name, obj->dumpId, obj->catId.oid);
+ return;
}
/* shouldn't get here */
snprintf(buf, bufsize,
diff -cprN head/src/bin/psql/describe.c work/src/bin/psql/describe.c
*** head/src/bin/psql/describe.c 2009-11-12 06:07:41.000000000 +0900
--- work/src/bin/psql/describe.c 2009-11-25 16:43:16.809459501 +0900
*************** describeOneTableDetails(const char *sche
*** 1935,1942 ****
}
PQclear(result);
/* print child tables */
! if (pset.sversion >= 80300)
printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
else
printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname;", oid);
--- 1935,1958 ----
}
PQclear(result);
+ /* print partitions */
+ if (pset.sversion >= 80500)
+ {
+ printfPQExpBuffer(&buf, "SELECT pg_catalog.pg_get_partitiondef('%s', false);", oid);
+ result = PSQLexec(buf.data, false);
+ if (!result)
+ goto error_return;
+ if (PQntuples(result) > 0 && !PQgetisnull(result, 0, 0))
+ {
+ printfPQExpBuffer(&buf, _("Partitions: %s"), PQgetvalue(result, 0, 0));
+ printTableAddFooter(&cont, buf.data);
+ }
+ }
+
/* print child tables */
! if (pset.sversion >= 80500)
! printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' AND i.inhvalues IS NULL ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
! else if (pset.sversion >= 80300)
printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
else
printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname;", oid);
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-25 16:12:51.596395644 +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-25 16:12:51.596395644 +0900
*************** extern Node *cookDefault(ParseState *pst
*** 93,98 ****
--- 93,101 ----
Oid atttypid,
int32 atttypmod,
char *attname);
+ extern Node *cookConstraint(ParseState *pstate,
+ Node *raw_constraint,
+ char *relname);
extern void DeleteRelationTuple(Oid relid);
extern void DeleteAttributeTuples(Oid relid);
*************** extern void RemoveAttrDefault(Oid relid,
*** 101,106 ****
--- 104,110 ----
DropBehavior behavior, bool complain);
extern void RemoveAttrDefaultById(Oid attrdefId);
extern void RemoveStatistics(Oid relid, AttrNumber attnum);
+ extern void RemovePartition(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-25 16:12:51.596395644 +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, 2996, on pg_partition using btree(partrelid oid_ops));
+ #define PartitionRelidIndexId 2996
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
diff -cprN head/src/include/catalog/pg_inherits.h work/src/include/catalog/pg_inherits.h
*** head/src/include/catalog/pg_inherits.h 2009-05-12 12:11:02.000000000 +0900
--- work/src/include/catalog/pg_inherits.h 2009-11-25 16:12:51.597395977 +0900
***************
*** 21,26 ****
--- 21,29 ----
#include "catalog/genbki.h"
+ /* See comments in pg_statistic.h. */
+ #define anyarray int
+
/* ----------------
* pg_inherits definition. cpp turns this into
* typedef struct FormData_pg_inherits
*************** CATALOG(pg_inherits,2611) BKI_WITHOUT_OI
*** 33,38 ****
--- 36,42 ----
Oid inhrelid;
Oid inhparent;
int4 inhseqno;
+ anyarray inhvalues; /* values for partition */
} FormData_pg_inherits;
/* ----------------
*************** typedef FormData_pg_inherits *Form_pg_in
*** 46,55 ****
* compiler constants for pg_inherits
* ----------------
*/
! #define Natts_pg_inherits 3
#define Anum_pg_inherits_inhrelid 1
#define Anum_pg_inherits_inhparent 2
#define Anum_pg_inherits_inhseqno 3
/* ----------------
* pg_inherits has no initial contents
--- 50,60 ----
* compiler constants for pg_inherits
* ----------------
*/
! #define Natts_pg_inherits 4
#define Anum_pg_inherits_inhrelid 1
#define Anum_pg_inherits_inhparent 2
#define Anum_pg_inherits_inhseqno 3
+ #define Anum_pg_inherits_inhvalues 4
/* ----------------
* pg_inherits has no initial contents
diff -cprN head/src/include/catalog/pg_inherits_fn.h work/src/include/catalog/pg_inherits_fn.h
*** head/src/include/catalog/pg_inherits_fn.h 2009-05-12 12:11:02.000000000 +0900
--- work/src/include/catalog/pg_inherits_fn.h 2009-11-25 16:12:51.597395977 +0900
***************
*** 17,24 ****
--- 17,36 ----
#include "nodes/pg_list.h"
#include "storage/lock.h"
+ /*
+ * Partition - store partition values.
+ */
+ typedef struct Partition
+ {
+ Oid relid;
+ int nvalues;
+ Datum *values;
+ } Partition;
+
extern List *find_inheritance_children(Oid parentrelId, LOCKMODE lockmode);
extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode);
+ extern List *find_partitions(Oid parentrelId,
+ char *kind, Node **key, Oid *opclass);
extern bool has_subclass(Oid relationId);
extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
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-25 16:12:51.597395977 +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 2995
+
+ CATALOG(pg_partition,2995) BKI_WITHOUT_OIDS
+ {
+ Oid partrelid; /* partitioned table oid */
+ Oid partopclass; /* operator class 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_partopclass 2
+ #define Anum_pg_partition_partkind 3
+ #define Anum_pg_partition_partkey 4
+
+ #endif /* PG_PARTITIONS_H */
diff -cprN head/src/include/catalog/pg_proc.h work/src/include/catalog/pg_proc.h
*** head/src/include/catalog/pg_proc.h 2009-10-10 06:02:56.000000000 +0900
--- work/src/include/catalog/pg_proc.h 2009-11-25 16:44:43.549394878 +0900
*************** DATA(insert OID = 2232 ( pg_get_functio
*** 2311,2316 ****
--- 2311,2318 ----
DESCR("identity argument list of a function");
DATA(insert OID = 2165 ( pg_get_function_result PGNSP PGUID 12 1 0 0 f f f t f s 1 0 25 "26" _null_ _null_ _null_ _null_ pg_get_function_result _null_ _null_ _null_ ));
DESCR("result type of a function");
+ DATA(insert OID = 1689 ( pg_get_partitiondef PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "26 16" _null_ _null_ _null_ _null_ pg_get_partitiondef _null_ _null_ _null_ ));
+ DESCR("definition of a partition");
DATA(insert OID = 1686 ( pg_get_keywords PGNSP PGUID 12 10 400 0 f f f t t s 0 0 2249 "" "{25,18,25}" "{o,o,o}" "{word,catcode,catdesc}" _null_ pg_get_keywords _null_ _null_ _null_ ));
DESCR("list of SQL keywords");
diff -cprN head/src/include/commands/defrem.h work/src/include/commands/defrem.h
*** head/src/include/commands/defrem.h 2009-09-23 08:43:41.000000000 +0900
--- work/src/include/commands/defrem.h 2009-11-25 16:12:51.598392773 +0900
*************** extern char *makeObjectName(const char *
*** 45,50 ****
--- 45,52 ----
extern char *ChooseRelationName(const char *name1, const char *name2,
const char *label, Oid namespaceid);
extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
+ extern Oid GetIndexOpClass(List *opclass, Oid attrType,
+ const char *accessMethodName, Oid accessMethodId);
/* commands/functioncmds.c */
extern void CreateFunction(CreateFunctionStmt *stmt, const char *queryString);
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-25 16:12:51.599396097 +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-25 16:12:51.599396097 +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,393 ----
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_PartitionDef,
+ T_PartitionBy,
+ T_AddInherit,
/*
* 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-11-21 05:38:11.000000000 +0900
--- work/src/include/nodes/parsenodes.h 2009-11-25 16:12:51.599396097 +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,1141 ----
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 */
! AT_AttachPartition, /* ATTACH PARTITION */
! AT_DetachPartition /* DETACH PARTITION */
} AlterTableType;
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
*************** typedef struct VariableShowStmt
*** 1333,1338 ****
--- 1336,1375 ----
char *name;
} VariableShowStmt;
+ /* ----------
+ * Partitioning definitions
+ * ----------
+ */
+
+ #define PARTITION_BY_RANGE 'r'
+ #define PARTITION_BY_LIST 'l'
+
+ typedef struct PartitionDef
+ {
+ NodeTag type;
+ char kind; /* PARTITION_BY_xxx */
+ RangeVar *name; /* name of partition */
+ List *values; /* for RANGE and LIST */
+ List *options; /* options from WITH clause */
+ char *tablespacename; /* table space to use, or NULL */
+ } PartitionDef;
+
+ typedef struct PartitionBy
+ {
+ NodeTag type;
+ char kind; /* PARTITION_BY_xxx */
+ Node *key; /* partition key expr */
+ List *opclass; /* partition key operator class */
+ List *defs; /* list of PartitionDef */
+ } PartitionBy;
+
+ typedef struct CreatePartitionStmt
+ {
+ NodeTag type;
+ RangeVar *parent; /* parent of the partition */
+ PartitionDef *def;
+ } CreatePartitionStmt;
+
/* ----------------------
* Create Table Statement
*
*************** typedef struct CreateStmt
*** 1355,1360 ****
--- 1392,1398 ----
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-11-06 08:24:27.000000000 +0900
--- work/src/include/parser/kwlist.h 2009-11-25 16:12:51.600395799 +0900
*************** PG_KEYWORD("assertion", ASSERTION, UNRES
*** 49,54 ****
--- 49,55 ----
PG_KEYWORD("assignment", ASSIGNMENT, UNRESERVED_KEYWORD)
PG_KEYWORD("asymmetric", ASYMMETRIC, RESERVED_KEYWORD)
PG_KEYWORD("at", AT, UNRESERVED_KEYWORD)
+ PG_KEYWORD("attach", ATTACH, UNRESERVED_KEYWORD)
PG_KEYWORD("authorization", AUTHORIZATION, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("backward", BACKWARD, UNRESERVED_KEYWORD)
PG_KEYWORD("before", BEFORE, UNRESERVED_KEYWORD)
*************** PG_KEYWORD("delete", DELETE_P, UNRESERVE
*** 125,130 ****
--- 126,132 ----
PG_KEYWORD("delimiter", DELIMITER, UNRESERVED_KEYWORD)
PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
+ PG_KEYWORD("detach", DETACH, UNRESERVED_KEYWORD)
PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
*************** PG_KEYWORD("lc_ctype", LC_CTYPE_P, UNRES
*** 215,223 ****
--- 217,227 ----
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
*** 363,368 ****
--- 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-25 16:12:51.600395799 +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 *transformCreatePartition(PartitionDef *def, RangeVar *parent);
#endif /* PARSE_UTILCMD_H */
diff -cprN head/src/include/utils/builtins.h work/src/include/utils/builtins.h
*** head/src/include/utils/builtins.h 2009-10-22 05:38:58.000000000 +0900
--- work/src/include/utils/builtins.h 2009-11-25 16:12:51.600395799 +0900
*************** extern Datum pg_get_functiondef(PG_FUNCT
*** 601,606 ****
--- 601,607 ----
extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS);
extern Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS);
extern Datum pg_get_function_result(PG_FUNCTION_ARGS);
+ extern Datum pg_get_partitiondef(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit);
extern List *deparse_context_for(const char *aliasname, Oid relid);
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-25 16:12:51.600395799 +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);
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-25 16:12:51.601396394 +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-25 16:54:08.186645000 +0900
***************
*** 0 ****
--- 1,645 ----
+ --
+ -- 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 |
+ Partitions: RANGE (sales_date)
+ (
+ PARTITION sales_2006 VALUES LESS THAN 'Mon Jan 01 00:00:00 2007',
+ PARTITION sales_2007 VALUES LESS THAN 'Tue Jan 01 00:00:00 2008',
+ PARTITION sales_2008 VALUES LESS THAN 'Thu Jan 01 00:00:00 2009',
+ PARTITION sales_max VALUES LESS THAN MAXVALUE
+ )
+ Has OIDs: no
+
+ \d+ sales_2006
+ Table "public.sales_2006"
+ 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_2006_sales_date_check" CHECK (sales_date < 'Mon Jan 01 00:00:00 2007'::timestamp without time zone)
+ Inherits: sales_range
+ 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 ('Mon Jan 01 00:00:00 2007'::timestamp without time zone <= sales_date AND sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_2008
+ Table "public.sales_2008"
+ 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_2008_sales_date_check" CHECK ('Tue Jan 01 00:00:00 2008'::timestamp without time zone <= sales_date AND sales_date < 'Thu Jan 01 00:00:00 2009'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_max
+ Table "public.sales_max"
+ 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_max_sales_date_check" CHECK ('Thu Jan 01 00:00:00 2009'::timestamp without time zone <= sales_date)
+ Inherits: sales_range
+ Has OIDs: no
+
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ ------------+----------+------------------------------
+ sales_2006 | 1 | {"Mon Jan 01 00:00:00 2007"}
+ sales_2007 | 1 | {"Tue Jan 01 00:00:00 2008"}
+ sales_2008 | 1 | {"Thu Jan 01 00:00:00 2009"}
+ sales_max | 1 | {}
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ -------------+----------+-------------
+ sales_range | r | sales_date
+ (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) timestamp_ops
+ (
+ 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 |
+ Partitions: RANGE (sales_date)
+ (
+ PARTITION sales_2006 VALUES LESS THAN 'Mon Jan 01 00:00:00 2007',
+ PARTITION sales_2007 VALUES LESS THAN 'Tue Jan 01 00:00:00 2008',
+ PARTITION sales_2008 VALUES LESS THAN 'Thu Jan 01 00:00:00 2009',
+ PARTITION sales_max VALUES LESS THAN MAXVALUE
+ )
+ Has OIDs: no
+
+ \d+ sales_2006
+ Table "public.sales_2006"
+ 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_2006_sales_date_check" CHECK (sales_date < 'Mon Jan 01 00:00:00 2007'::timestamp without time zone)
+ Inherits: sales_range
+ 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 ('Mon Jan 01 00:00:00 2007'::timestamp without time zone <= sales_date AND sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_2008
+ Table "public.sales_2008"
+ 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_2008_sales_date_check" CHECK ('Tue Jan 01 00:00:00 2008'::timestamp without time zone <= sales_date AND sales_date < 'Thu Jan 01 00:00:00 2009'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_max
+ Table "public.sales_max"
+ 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_max_sales_date_check" CHECK ('Thu Jan 01 00:00:00 2009'::timestamp without time zone <= sales_date)
+ Inherits: sales_range
+ Has OIDs: no
+
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ ------------+----------+------------------------------
+ sales_2006 | 1 | {"Mon Jan 01 00:00:00 2007"}
+ sales_2007 | 1 | {"Tue Jan 01 00:00:00 2008"}
+ sales_2008 | 1 | {"Thu Jan 01 00:00:00 2009"}
+ sales_max | 1 | {}
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ -------------+----------+-------------
+ sales_range | r | sales_date
+ (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 |
+ Partitions: RANGE (sales_date)
+ (
+ PARTITION sales_2006 VALUES LESS THAN 'Mon Jan 01 00:00:00 2007',
+ PARTITION sales_2007 VALUES LESS THAN 'Tue Jan 01 00:00:00 2008',
+ PARTITION sales_2008 VALUES LESS THAN 'Thu Jan 01 00:00:00 2009',
+ PARTITION sales_max VALUES LESS THAN MAXVALUE
+ )
+ Has OIDs: no
+
+ \d+ sales_2006
+ Table "public.sales_2006"
+ 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_2006_sales_date_check" CHECK (sales_date < 'Mon Jan 01 00:00:00 2007'::timestamp without time zone)
+ Inherits: sales_range
+ 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 ('Mon Jan 01 00:00:00 2007'::timestamp without time zone <= sales_date AND sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_2008
+ Table "public.sales_2008"
+ 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_2008_sales_date_check" CHECK ('Tue Jan 01 00:00:00 2008'::timestamp without time zone <= sales_date AND sales_date < 'Thu Jan 01 00:00:00 2009'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_max
+ Table "public.sales_max"
+ 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_max_sales_date_check" CHECK ('Thu Jan 01 00:00:00 2009'::timestamp without time zone <= sales_date)
+ Inherits: sales_range
+ Has OIDs: no
+
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ ------------+----------+------------------------------
+ sales_2006 | 1 | {"Mon Jan 01 00:00:00 2007"}
+ sales_2007 | 1 | {"Tue Jan 01 00:00:00 2008"}
+ sales_2008 | 1 | {"Thu Jan 01 00:00:00 2009"}
+ sales_max | 1 | {}
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ -------------+----------+-------------
+ sales_range | r | sales_date
+ (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
+ );
+ CREATE TABLE sales_2006 (LIKE sales_range INCLUDING ALL);
+ CREATE TABLE sales_2007 (LIKE sales_range INCLUDING ALL);
+ CREATE TABLE sales_2008 (LIKE sales_range INCLUDING ALL);
+ CREATE TABLE sales_max (LIKE sales_range INCLUDING ALL);
+ ALTER TABLE sales_range PARTITION BY RANGE (sales_date);
+ ALTER TABLE sales_range ATTACH PARTITION sales_2006 VALUES LESS THAN '2007-01-01';
+ ALTER TABLE sales_range ATTACH PARTITION sales_2007 VALUES LESS THAN '2008-01-01';
+ ALTER TABLE sales_range ATTACH PARTITION sales_2008 VALUES LESS THAN '2009-01-01';
+ ALTER TABLE sales_range ATTACH 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 |
+ Partitions: RANGE (sales_date)
+ (
+ PARTITION sales_2006 VALUES LESS THAN 'Mon Jan 01 00:00:00 2007',
+ PARTITION sales_2007 VALUES LESS THAN 'Tue Jan 01 00:00:00 2008',
+ PARTITION sales_2008 VALUES LESS THAN 'Thu Jan 01 00:00:00 2009',
+ PARTITION sales_max VALUES LESS THAN MAXVALUE
+ )
+ Has OIDs: no
+
+ \d+ sales_2006
+ Table "public.sales_2006"
+ 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_2006_sales_date_check" CHECK (sales_date < 'Mon Jan 01 00:00:00 2007'::timestamp without time zone)
+ Inherits: sales_range
+ 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 ('Mon Jan 01 00:00:00 2007'::timestamp without time zone <= sales_date AND sales_date < 'Tue Jan 01 00:00:00 2008'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_2008
+ Table "public.sales_2008"
+ 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_2008_sales_date_check" CHECK ('Tue Jan 01 00:00:00 2008'::timestamp without time zone <= sales_date AND sales_date < 'Thu Jan 01 00:00:00 2009'::timestamp without time zone)
+ Inherits: sales_range
+ Has OIDs: no
+
+ \d+ sales_max
+ Table "public.sales_max"
+ 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_max_sales_date_check" CHECK ('Thu Jan 01 00:00:00 2009'::timestamp without time zone <= sales_date)
+ Inherits: sales_range
+ Has OIDs: no
+
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ ------------+----------+------------------------------
+ sales_2006 | 1 | {"Mon Jan 01 00:00:00 2007"}
+ sales_2007 | 1 | {"Tue Jan 01 00:00:00 2008"}
+ sales_2008 | 1 | {"Thu Jan 01 00:00:00 2009"}
+ sales_max | 1 | {}
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ -------------+----------+-------------
+ sales_range | r | sales_date
+ (1 row)
+
+ -- ERROR: cannot add duplicated partition keys
+ ALTER TABLE sales_range PARTITION BY RANGE (salesman_id);
+ ERROR: multiple partition keys for table "sales_range" are not allowed
+ -- NO PARTITION will drop all inhvalues.
+ ALTER TABLE sales_range NO PARTITION;
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ ------------+----------+-----------
+ sales_2006 | 1 |
+ sales_2007 | 1 |
+ sales_2008 | 1 |
+ sales_max | 1 |
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ -----------+----------+-------------
+ (0 rows)
+
+ 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) varchar_ops
+ (
+ 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 |
+ Partitions: LIST (sales_state) varchar_ops
+ (
+ PARTITION sales_asia VALUES ('asia'),
+ PARTITION sales_euro VALUES ('eu'),
+ PARTITION sales_us VALUES ('usa', 'canada'),
+ PARTITION sales_other VALUES (DEFAULT)
+ )
+ Has OIDs: no
+
+ \d+ sales_asia
+ Table "public.sales_asia"
+ 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_asia_sales_state_check" CHECK (sales_state::text = 'asia'::text)
+ Inherits: sales_list
+ Has OIDs: no
+
+ \d+ sales_euro
+ Table "public.sales_euro"
+ 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_euro_sales_state_check" CHECK (sales_state::text = 'eu'::text)
+ Inherits: sales_list
+ 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
+
+ \d+ sales_other
+ Table "public.sales_other"
+ 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_other_sales_state_check" CHECK (NOT (sales_state::text = ANY (ARRAY['asia'::character varying, 'eu'::character varying, 'usa'::character varying, 'canada'::character varying]::text[])))
+ Inherits: sales_list
+ Has OIDs: no
+
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_list'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ -------------+----------+--------------
+ sales_asia | 1 | {asia}
+ sales_euro | 1 | {eu}
+ sales_us | 1 | {usa,canada}
+ sales_other | 1 | {}
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ ------------+----------+-------------
+ sales_list | l | sales_state
+ (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
+ );
+ CREATE TABLE sales_asia (LIKE sales_list INCLUDING ALL);
+ CREATE TABLE sales_euro (LIKE sales_list INCLUDING ALL);
+ CREATE TABLE sales_us (LIKE sales_list INCLUDING ALL);
+ CREATE TABLE sales_other (LIKE sales_list INCLUDING ALL);
+ ALTER TABLE sales_list PARTITION BY LIST (sales_state) text_ops;
+ ALTER TABLE sales_list ATTACH PARTITION sales_asia VALUES IN ('asia');
+ ALTER TABLE sales_list ATTACH PARTITION sales_euro VALUES IN ('eu');
+ ALTER TABLE sales_list ATTACH PARTITION sales_us VALUES IN ('usa', 'canada');
+ ALTER TABLE sales_list ATTACH 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 |
+ Partitions: LIST (sales_state)
+ (
+ PARTITION sales_asia VALUES ('asia'),
+ PARTITION sales_euro VALUES ('eu'),
+ PARTITION sales_us VALUES ('usa', 'canada'),
+ PARTITION sales_other VALUES (DEFAULT)
+ )
+ Has OIDs: no
+
+ \d+ sales_asia
+ Table "public.sales_asia"
+ 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_asia_sales_state_check" CHECK (sales_state::text = 'asia'::text)
+ Inherits: sales_list
+ Has OIDs: no
+
+ \d+ sales_euro
+ Table "public.sales_euro"
+ 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_euro_sales_state_check" CHECK (sales_state::text = 'eu'::text)
+ Inherits: sales_list
+ 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
+
+ \d+ sales_other
+ Table "public.sales_other"
+ 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_other_sales_state_check" CHECK (NOT (sales_state::text = ANY (ARRAY['asia'::character varying, 'eu'::character varying, 'usa'::character varying, 'canada'::character varying]::text[])))
+ Inherits: sales_list
+ Has OIDs: no
+
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_list'::regclass ORDER BY 1;
+ inhrelid | inhseqno | inhvalues
+ -------------+----------+--------------
+ sales_asia | 1 | {asia}
+ sales_euro | 1 | {eu}
+ sales_us | 1 | {usa,canada}
+ sales_other | 1 | {}
+ (4 rows)
+
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ partrelid | partkind | pg_get_expr
+ ------------+----------+-------------
+ sales_list | l | sales_state
+ (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-25 16:12:51.602764188 +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-25 16:12:51.602764188 +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-25 16:12:51.602764188 +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-25 16:12:51.603395652 +0900
***************
*** 0 ****
--- 1,147 ----
+ --
+ -- 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_2006
+ \d+ sales_2007
+ \d+ sales_2008
+ \d+ sales_max
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ 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) timestamp_ops
+ (
+ 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_2006
+ \d+ sales_2007
+ \d+ sales_2008
+ \d+ sales_max
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ 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_2006
+ \d+ sales_2007
+ \d+ sales_2008
+ \d+ sales_max
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ 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
+ );
+ CREATE TABLE sales_2006 (LIKE sales_range INCLUDING ALL);
+ CREATE TABLE sales_2007 (LIKE sales_range INCLUDING ALL);
+ CREATE TABLE sales_2008 (LIKE sales_range INCLUDING ALL);
+ CREATE TABLE sales_max (LIKE sales_range INCLUDING ALL);
+ ALTER TABLE sales_range PARTITION BY RANGE (sales_date);
+ ALTER TABLE sales_range ATTACH PARTITION sales_2006 VALUES LESS THAN '2007-01-01';
+ ALTER TABLE sales_range ATTACH PARTITION sales_2007 VALUES LESS THAN '2008-01-01';
+ ALTER TABLE sales_range ATTACH PARTITION sales_2008 VALUES LESS THAN '2009-01-01';
+ ALTER TABLE sales_range ATTACH PARTITION sales_max VALUES LESS THAN MAXVALUE;
+ \d+ sales_range
+ \d+ sales_2006
+ \d+ sales_2007
+ \d+ sales_2008
+ \d+ sales_max
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+
+ -- ERROR: cannot add duplicated partition keys
+ ALTER TABLE sales_range PARTITION BY RANGE (salesman_id);
+
+ -- NO PARTITION will drop all inhvalues.
+ ALTER TABLE sales_range NO PARTITION;
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_range'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ 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) varchar_ops
+ (
+ 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_asia
+ \d+ sales_euro
+ \d+ sales_us
+ \d+ sales_other
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_list'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ 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
+ );
+ CREATE TABLE sales_asia (LIKE sales_list INCLUDING ALL);
+ CREATE TABLE sales_euro (LIKE sales_list INCLUDING ALL);
+ CREATE TABLE sales_us (LIKE sales_list INCLUDING ALL);
+ CREATE TABLE sales_other (LIKE sales_list INCLUDING ALL);
+ ALTER TABLE sales_list PARTITION BY LIST (sales_state) text_ops;
+ ALTER TABLE sales_list ATTACH PARTITION sales_asia VALUES IN ('asia');
+ ALTER TABLE sales_list ATTACH PARTITION sales_euro VALUES IN ('eu');
+ ALTER TABLE sales_list ATTACH PARTITION sales_us VALUES IN ('usa', 'canada');
+ ALTER TABLE sales_list ATTACH PARTITION sales_other VALUES DEFAULT;
+ \d+ sales_list
+ \d+ sales_asia
+ \d+ sales_euro
+ \d+ sales_us
+ \d+ sales_other
+ SELECT inhrelid::regclass, inhseqno, inhvalues FROM pg_inherits WHERE inhparent = 'sales_list'::regclass ORDER BY 1;
+ SELECT partrelid::regclass, partkind, pg_get_expr(partkey, partrelid) FROM pg_partition;
+ DROP TABLE IF EXISTS sales_list CASCADE;