From 277807bd9eba1645d8dfc9252fa29220c4a83751 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sun, 2 Jul 2006 02:23:23 +0000 Subject: [PATCH] Add FILLFACTOR to CREATE INDEX. ITAGAKI Takahiro --- doc/src/sgml/ref/alter_index.sgml | 24 ++- doc/src/sgml/ref/alter_table.sgml | 24 ++- doc/src/sgml/ref/create_index.sgml | 12 +- doc/src/sgml/ref/create_table.sgml | 12 +- doc/src/sgml/ref/create_table_as.sgml | 12 +- src/backend/access/common/heaptuple.c | 53 ++++- src/backend/access/gin/ginutil.c | 16 +- src/backend/access/gist/gist.c | 17 +- src/backend/access/gist/gistutil.c | 20 +- src/backend/access/gist/gistvacuum.c | 4 +- src/backend/access/gist/gistxlog.c | 4 +- src/backend/access/hash/hashpage.c | 5 +- src/backend/access/hash/hashutil.c | 15 +- src/backend/access/heap/heapam.c | 62 +++++- src/backend/access/heap/hio.c | 16 +- src/backend/access/index/genam.c | 47 ++++- src/backend/access/nbtree/nbtinsert.c | 21 +- src/backend/access/nbtree/nbtsort.c | 26 ++- src/backend/access/nbtree/nbtutils.c | 15 +- src/backend/access/transam/xlogutils.c | 4 +- src/backend/bootstrap/bootparse.y | 12 +- src/backend/catalog/heap.c | 40 ++-- src/backend/catalog/index.c | 70 +++++- src/backend/catalog/indexing.c | 5 +- src/backend/commands/cluster.c | 29 ++- src/backend/commands/define.c | 36 +++- src/backend/commands/indexcmds.c | 6 +- src/backend/commands/prepare.c | 3 +- src/backend/commands/sequence.c | 16 +- src/backend/commands/tablecmds.c | 164 ++++++++++++--- src/backend/commands/typecmds.c | 4 +- src/backend/commands/vacuum.c | 28 ++- src/backend/commands/vacuumlazy.c | 4 +- src/backend/commands/view.c | 5 +- src/backend/executor/execMain.c | 10 +- src/backend/nodes/copyfuncs.c | 11 +- src/backend/nodes/equalfuncs.c | 11 +- src/backend/nodes/outfuncs.c | 10 +- src/backend/nodes/readfuncs.c | 3 +- src/backend/parser/analyze.c | 10 +- src/backend/parser/gram.y | 80 ++++--- src/backend/parser/parse_clause.c | 281 +++++++++++++++++++++++-- src/backend/tcop/utility.c | 3 +- src/backend/utils/adt/ruleutils.c | 60 +++++- src/backend/utils/cache/relcache.c | 171 ++++++++++----- src/bin/pg_dump/pg_dump.c | 106 ++++++++-- src/bin/pg_dump/pg_dump.h | 4 +- src/include/access/genam.h | 12 +- src/include/access/gin.h | 3 +- src/include/access/gist_private.h | 6 +- src/include/access/hash.h | 3 +- src/include/access/heapam.h | 31 ++- src/include/access/hio.h | 4 +- src/include/access/nbtree.h | 3 +- src/include/catalog/catversion.h | 4 +- src/include/catalog/heap.h | 6 +- src/include/catalog/index.h | 6 +- src/include/catalog/pg_am.h | 14 +- src/include/catalog/pg_attribute.h | 8 +- src/include/catalog/pg_class.h | 20 +- src/include/catalog/pg_proc.h | 10 +- src/include/commands/defrem.h | 5 +- src/include/nodes/parsenodes.h | 23 +- src/include/parser/parse_clause.h | 9 +- src/include/utils/rel.h | 9 +- 65 files changed, 1458 insertions(+), 309 deletions(-) diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml index 929f8709ba..d497dd47af 100644 --- a/doc/src/sgml/ref/alter_index.sgml +++ b/doc/src/sgml/ref/alter_index.sgml @@ -1,5 +1,5 @@ @@ -22,6 +22,8 @@ PostgreSQL documentation ALTER INDEX name RENAME TO new_name ALTER INDEX name SET TABLESPACE tablespace_name +ALTER INDEX name SET (FILLFACTOR = fillfactor) +ALTER INDEX name RESET (FILLFACTOR) @@ -56,6 +58,26 @@ ALTER INDEX name SET TABLESPACE + + SET (FILLFACTOR) + + + This form changes the index's fillfactor to the specified percentage. + Index structure is not modified immediately; use REINDEX + to ensure reflection of the change. + + + + + + RESET (FILLFACTOR) + + + This form changes the index's fillfactor to the default value. + + + + diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index ee501a1a37..ef8e803d6f 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -1,5 +1,5 @@ @@ -46,6 +46,8 @@ where action is one of: CLUSTER ON index_name SET WITHOUT CLUSTER SET WITHOUT OIDS + SET (FILLFACTOR = fillfactor) + RESET (FILLFACTOR) INHERIT parent_table NO INHERIT parent_table OWNER TO new_owner @@ -321,6 +323,26 @@ where action is one of: + + SET (FILLFACTOR) + + + This form changes the table's fillfactor to the specified percentage. + Table structure is not modified immediately; use CLUSTER + to ensure reflection of the change. + + + + + + RESET + + + This form changes the table's fillfactor to the default value. + + + + RENAME diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index 676fa8b4e6..787184a5e2 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -1,5 +1,5 @@ @@ -22,6 +22,7 @@ PostgreSQL documentation CREATE [ UNIQUE ] INDEX name ON table [ USING method ] ( { column | ( expression ) } [ opclass ] [, ...] ) + [ WITH (FILLFACTOR = fillfactor) ] [ TABLESPACE tablespace ] [ WHERE predicate ] @@ -171,6 +172,15 @@ CREATE [ UNIQUE ] INDEX name ON + + fillfactor + + + The index's fillfactor in percentage. + + + + tablespace diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 0276dc7ad2..c40c37c19c 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -1,5 +1,5 @@ @@ -28,6 +28,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE tablespace ] @@ -303,6 +304,15 @@ and table_constraint is: + + WITH (FILLFACTOR = fillfactor) + + + This optional clause specifies the table's fillfactor in percentage. + + + + CONSTRAINT constraint_name diff --git a/doc/src/sgml/ref/create_table_as.sgml b/doc/src/sgml/ref/create_table_as.sgml index 7e7fa7b673..53fb6c0971 100644 --- a/doc/src/sgml/ref/create_table_as.sgml +++ b/doc/src/sgml/ref/create_table_as.sgml @@ -1,5 +1,5 @@ @@ -23,6 +23,7 @@ PostgreSQL documentation CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name [ (column_name [, ...] ) ] [ WITH OIDS | WITHOUT OIDS ] + [ WITH (FILLFACTOR = fillfactor) ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ TABLESPACE tablespace ] AS query @@ -116,6 +117,15 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name + + WITH (FILLFACTOR = fillfactor) + + + This optional clause specifies the table's fillfactor in percentage. + + + + ON COMMIT diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 7ec314379b..edd90c8a56 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.107 2006/06/27 02:51:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.108 2006/07/02 02:23:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1738,3 +1738,54 @@ heap_addheader(int natts, /* max domain index */ return tuple; } + +/* + * build_class_tuple + * + * XXX Natts_pg_class_fixed is a hack - see pg_class.h + */ +HeapTuple +build_class_tuple(Form_pg_class pgclass, ArrayType *options) +{ + HeapTuple tuple; + HeapTupleHeader td; + Form_pg_class data; /* contents of tuple */ + Size len; + Size size; + int hoff; + + /* size of pg_class tuple with options */ + if (options) + size = offsetof(FormData_pg_class, reloptions) + VARATT_SIZE(options); + else + size = CLASS_TUPLE_SIZE; + + /* header needs no null bitmap */ + hoff = offsetof(HeapTupleHeaderData, t_bits); + hoff += sizeof(Oid); + hoff = MAXALIGN(hoff); + len = hoff + size; + + tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len); + tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); + + tuple->t_len = len; + ItemPointerSetInvalid(&(tuple->t_self)); + tuple->t_tableOid = InvalidOid; + + /* we don't bother to fill the Datum fields */ + + td->t_natts = Natts_pg_class_fixed; + td->t_hoff = hoff; + td->t_infomask = HEAP_HASOID; + + data = (Form_pg_class) ((char *) td + hoff); + memcpy(data, pgclass, CLASS_TUPLE_SIZE); + if (options) + { + td->t_natts++; + memcpy(data->reloptions, options, VARATT_SIZE(options)); + } + + return tuple; +} diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index b9cb80a6cf..17e041bc4a 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.1 2006/05/02 11:28:54 teodor Exp $ + * $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.2 2006/07/02 02:23:18 momjian Exp $ *------------------------------------------------------------------------- */ @@ -201,3 +201,17 @@ GinPageGetCopyPage( Page page ) { return tmppage; } + +Datum +ginoption(PG_FUNCTION_ARGS) +{ + ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); + + if (options != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("GIN does not support parameters at all"))); + + /* Do not use PG_RETURN_NULL. */ + PG_RETURN_BYTEA_P(NULL); +} diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 39ff702c3d..4137ab4426 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.139 2006/06/28 12:00:14 teodor Exp $ + * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.140 2006/07/02 02:23:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,7 @@ static void gistbuildCallback(Relation index, void *state); static void gistdoinsert(Relation r, IndexTuple itup, + Size freespace, GISTSTATE *GISTstate); static void gistfindleaf(GISTInsertState *state, GISTSTATE *giststate); @@ -197,7 +198,8 @@ gistbuildCallback(Relation index, * you're inserting single tups, but not when you're initializing the * whole index at once. */ - gistdoinsert(index, itup, &buildstate->giststate); + gistdoinsert(index, itup, IndexGetPageFreeSpace(index), + &buildstate->giststate); buildstate->indtuples += 1; MemoryContextSwitchTo(oldCtx); @@ -236,7 +238,7 @@ gistinsert(PG_FUNCTION_ARGS) values, isnull, true /* size is currently bogus */); itup->t_tid = *ht_ctid; - gistdoinsert(r, itup, &giststate); + gistdoinsert(r, itup, 0, &giststate); /* cleanup */ freeGISTstate(&giststate); @@ -253,7 +255,7 @@ gistinsert(PG_FUNCTION_ARGS) * so it does not bother releasing palloc'd allocations. */ static void -gistdoinsert(Relation r, IndexTuple itup, GISTSTATE *giststate) +gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate) { GISTInsertState state; @@ -263,6 +265,7 @@ gistdoinsert(Relation r, IndexTuple itup, GISTSTATE *giststate) state.itup[0] = (IndexTuple) palloc(IndexTupleSize(itup)); memcpy(state.itup[0], itup, IndexTupleSize(itup)); state.ituplen = 1; + state.freespace = freespace; state.r = r; state.key = itup->t_tid; state.needInsertComplete = true; @@ -294,7 +297,11 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) */ - if (gistnospace(state->stack->page, state->itup, state->ituplen, (is_leaf) ? InvalidOffsetNumber : state->stack->childoffnum)) + /* + * XXX: If we want to change fillfactors between node and leaf, + * fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor) + */ + if (gistnospace(state->stack->page, state->itup, state->ituplen, (is_leaf) ? InvalidOffsetNumber : state->stack->childoffnum, state->freespace)) { /* no space for insertion */ IndexTuple *itvec; diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 3be4fd31f5..ae1fbc7320 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.16 2006/06/28 12:00:14 teodor Exp $ + * $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.17 2006/07/02 02:23:18 momjian Exp $ *------------------------------------------------------------------------- */ #include "postgres.h" @@ -58,9 +58,9 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup, * Check space for itup vector on page */ bool -gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete) +gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace) { - unsigned int size = 0, deleted = 0; + unsigned int size = freespace, deleted = 0; int i; for (i = 0; i < len; i++) @@ -82,6 +82,7 @@ gistfitpage(IndexTuple *itvec, int len) { for(i=0;iattrs[0]->atttypmod); item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) + sizeof(ItemIdData); /* include the line pointer */ - ffactor = (BLCKSZ * 3 / 4) / item_width; + ffactor = BLCKSZ * IndexGetFillFactor(rel) / 100 / item_width; /* keep to a sane range */ if (ffactor < 10) ffactor = 10; diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 65b8ef948c..fbee1fdc2a 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.47 2006/03/05 15:58:21 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.48 2006/07/02 02:23:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -173,3 +173,16 @@ _hash_checkpage(Relation rel, Buffer buf, int flags) errhint("Please REINDEX it."))); } } + +Datum +hashoption(PG_FUNCTION_ARGS) +{ +#define HASH_MIN_FILLFACTOR 50 +#define HASH_DEFAULT_FILLFACTOR 75 + + ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); + + /* Use index common routine. */ + PG_RETURN_BYTEA_P(genam_option(options, + HASH_MIN_FILLFACTOR, HASH_DEFAULT_FILLFACTOR)); +} diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 15556fda53..cf3344c200 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.213 2006/05/28 02:27:08 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.214 2006/07/02 02:23:18 momjian Exp $ * * * INTERFACE ROUTINES @@ -46,9 +46,13 @@ #include "access/xlogutils.h" #include "catalog/catalog.h" #include "catalog/namespace.h" +#include "commands/defrem.h" #include "miscadmin.h" +#include "nodes/parsenodes.h" +#include "parser/parse_clause.h" #include "pgstat.h" #include "storage/procarray.h" +#include "utils/catcache.h" #include "utils/inval.h" #include "utils/relcache.h" @@ -3588,3 +3592,59 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec) else appendStringInfo(buf, "UNKNOWN"); } + +/* + * Parse options for heaps. + * + * relkind Kind of relation + * options Options as text[] + */ +bytea * +heap_option(char relkind, ArrayType *options) +{ + /* + * XXX: What fillfactor should be default? + * overriding databases: + * - Oracle, DB2 = 90% + * - SQL Server = 100% + * non-overriding database: + * - Firebird = 70% + */ +#define HEAP_MIN_FILLFACTOR 50 +#define HEAP_DEFAULT_FILLFACTOR 100 + + int fillfactor; + HeapOption *result; + + DefElem kwds[] = + { + { T_DefElem, "fillfactor" }, + }; + + /* + * parse options + */ + OptionParse(options, lengthof(kwds), kwds, true); + + /* 0: fillfactor */ + if (kwds[0].arg) + fillfactor = (int) defGetInt64(&kwds[0]); + else + fillfactor = HEAP_DEFAULT_FILLFACTOR; + if (fillfactor < HEAP_MIN_FILLFACTOR || 100 < fillfactor) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("fillfactor=%d should be between %d and 100", + fillfactor, HEAP_MIN_FILLFACTOR))); + } + + /* + * build option + */ + result = (HeapOption *) + MemoryContextAlloc(CacheMemoryContext, sizeof(HeapOption)); + VARATT_SIZEP(result) = sizeof(HeapOption); + result->fillfactor = fillfactor; + return (bytea *) result; +} diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index ccaaacefea..82fb0a3268 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.61 2006/03/05 15:58:21 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.62 2006/07/02 02:23:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -102,12 +102,18 @@ RelationGetBufferForTuple(Relation relation, Size len, { Buffer buffer = InvalidBuffer; Page pageHeader; - Size pageFreeSpace; + Size pageFreeSpace, + freespace; BlockNumber targetBlock, otherBlock; bool needLock; + if (relation->rd_options == NULL) + elog(ERROR, "RelationGetBufferForTuple %s IS NULL", RelationGetRelationName(relation)); + Assert(relation->rd_options != NULL); + len = MAXALIGN(len); /* be conservative */ + freespace = HeapGetPageFreeSpace(relation); /* * If we're gonna fail for oversize tuple, do it right away @@ -146,7 +152,7 @@ RelationGetBufferForTuple(Relation relation, Size len, * We have no cached target page, so ask the FSM for an initial * target. */ - targetBlock = GetPageWithFreeSpace(&relation->rd_node, len); + targetBlock = GetPageWithFreeSpace(&relation->rd_node, len + freespace); /* * If the FSM knows nothing of the rel, try the last page before we @@ -202,7 +208,7 @@ RelationGetBufferForTuple(Relation relation, Size len, */ pageHeader = (Page) BufferGetPage(buffer); pageFreeSpace = PageGetFreeSpace(pageHeader); - if (len <= pageFreeSpace) + if (len + freespace <= pageFreeSpace) { /* use this page as future insert target, too */ relation->rd_targblock = targetBlock; @@ -235,7 +241,7 @@ RelationGetBufferForTuple(Relation relation, Size len, targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node, targetBlock, pageFreeSpace, - len); + len + freespace); } /* diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index 56eabbaf42..cfc2a833cd 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.55 2006/05/07 01:21:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.56 2006/07/02 02:23:18 momjian Exp $ * * NOTES * many of the old access method routines have been turned into @@ -21,8 +21,12 @@ #include "access/genam.h" #include "access/heapam.h" +#include "commands/defrem.h" #include "miscadmin.h" +#include "nodes/parsenodes.h" +#include "parser/parse_clause.h" #include "pgstat.h" +#include "utils/catcache.h" /* ---------------------------------------------------------------- @@ -260,3 +264,44 @@ systable_endscan(SysScanDesc sysscan) pfree(sysscan); } + +/* + * Parse options for generic indexes. + */ +bytea * +genam_option(ArrayType *options, + int minFillfactor, int defaultFillfactor) +{ + int fillfactor; + IndexOption *result; + + DefElem kwds[] = + { + { T_DefElem, "fillfactor" }, + }; + + /* + * parse options + */ + OptionParse(options, lengthof(kwds), kwds, true); + + /* 0: fillfactor */ + if (kwds[0].arg) + fillfactor = (int) defGetInt64(&kwds[0]); + else + fillfactor = defaultFillfactor; + if (fillfactor < minFillfactor || 100 < fillfactor) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("fillfactor=%d should be between %d and 100", + fillfactor, minFillfactor))); + + /* + * build options + */ + result = (IndexOption *) + MemoryContextAlloc(CacheMemoryContext, sizeof(IndexOption)); + VARATT_SIZEP(result) = sizeof(IndexOption); + result->fillfactor = fillfactor; + return (bytea *) result; +} diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 89f8810bde..3b78843101 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -8,13 +8,14 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.137 2006/05/08 00:00:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.138 2006/07/02 02:23:18 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "access/genam.h" #include "access/heapam.h" #include "access/nbtree.h" #include "miscadmin.h" @@ -25,6 +26,7 @@ typedef struct { /* context data for _bt_checksplitloc */ Size newitemsz; /* size of new item to be inserted */ + int fillfactor; /* used when insert at right most */ bool is_leaf; /* T if splitting a leaf page */ bool is_rightmost; /* T if splitting a rightmost page */ @@ -986,14 +988,11 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright, * it needs to go into!) * * If the page is the rightmost page on its level, we instead try to arrange - * for twice as much free space on the right as on the left. In this way, + * for reserving (100-fillfactor)% of free space on left page. In this way, * when we are inserting successively increasing keys (consider sequences, - * timestamps, etc) we will end up with a tree whose pages are about 67% full, + * timestamps, etc) we will end up with a tree whose pages are about fillfactor% full, * instead of the 50% full result that we'd get without this special case. - * (We could bias it even further to make the initially-loaded tree more full. - * But since the steady-state load for a btree is about 70%, we'd likely just - * be making more page-splitting work for ourselves later on, when we start - * seeing updates to existing tuples.) + * This is the same as initially-loaded tree. * * We are passed the intended insert position of the new tuple, expressed as * the offsetnumber of the tuple it must go in front of. (This could be @@ -1027,6 +1026,7 @@ _bt_findsplitloc(Relation rel, /* Passed-in newitemsz is MAXALIGNED but does not include line pointer */ newitemsz += sizeof(ItemIdData); state.newitemsz = newitemsz; + state.fillfactor = IndexGetFillFactor(rel); state.is_leaf = P_ISLEAF(opaque); state.is_rightmost = P_RIGHTMOST(opaque); state.have_split = false; @@ -1157,10 +1157,11 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright, if (state->is_rightmost) { /* - * On a rightmost page, try to equalize right free space with - * twice the left free space. See comments for _bt_findsplitloc. + * On a rightmost page, try to reserve (100-fillfactor)% of + * free space on left page. See comments for _bt_findsplitloc. */ - delta = (2 * leftfree) - rightfree; + delta = (state->fillfactor * leftfree) + - ((100 - state->fillfactor) * rightfree); } else { diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index e7293b47b0..05785d98eb 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -56,13 +56,14 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.102 2006/06/27 16:53:02 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.103 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "access/genam.h" #include "access/nbtree.h" #include "access/xlog.h" #include "miscadmin.h" @@ -120,6 +121,7 @@ typedef struct BTWriteState static Page _bt_blnewpage(uint32 level); +static Size _bt_full_threshold(Relation index, Size pagesize, bool leaf); static BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level); static void _bt_slideleft(Page page); static void _bt_sortaddtup(Page page, Size itemsize, @@ -327,6 +329,22 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno) pfree(page); } +/* + * The steady-state load factor for btrees is usually estimated at 70%. + * We choose to pack leaf pages to 90% and upper pages to 70% as defaults. + */ +static Size +_bt_full_threshold(Relation index, Size pagesize, bool leaf) +{ + int fillfactor = IndexGetFillFactor(index); + if (!leaf) + { + /* XXX: Is this reasonable? */ + fillfactor = Max(70, 3 * fillfactor - 200); + } + return pagesize * (100 - fillfactor) / 100; +} + /* * allocate and initialize a new BTPageState. the returned structure * is suitable for immediate use by _bt_buildadd. @@ -347,10 +365,8 @@ _bt_pagestate(BTWriteState *wstate, uint32 level) state->btps_lastoff = P_HIKEY; state->btps_level = level; /* set "full" threshold based on level. See notes at head of file. */ - if (level > 0) - state->btps_full = (PageGetPageSize(state->btps_page) * 3) / 10; - else - state->btps_full = PageGetPageSize(state->btps_page) / 10; + state->btps_full = _bt_full_threshold(wstate->index, + PageGetPageSize(state->btps_page), level == 0); /* no parent level, yet */ state->btps_next = NULL; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 5db8f55288..93a9b0df65 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.74 2006/05/08 00:00:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.75 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1079,3 +1079,16 @@ BTreeShmemInit(void) else Assert(found); } + +Datum +btoption(PG_FUNCTION_ARGS) +{ +#define BTREE_MIN_FILLFACTOR 50 +#define BTREE_DEFAULT_FILLFACTOR 90 + + ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); + + /* Use index common routine. */ + PG_RETURN_BYTEA_P(genam_option(options, + BTREE_MIN_FILLFACTOR, BTREE_DEFAULT_FILLFACTOR)); +} diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 39d3e041e4..da30e39b42 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.44 2006/04/14 20:27:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.45 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -337,7 +337,7 @@ _xl_remove_hash_entry(XLogRelDesc *rdesc) RelationCloseSmgr(&(rdesc->reldata)); memset(rdesc, 0, sizeof(XLogRelDesc)); - memset(tpgc, 0, sizeof(FormData_pg_class)); + memset(tpgc, 0, CLASS_TUPLE_SIZE); rdesc->reldata.rd_rel = tpgc; } diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index 8b8645bd60..901c392d7e 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.80 2006/03/07 01:03:12 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.81 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include #include "access/attnum.h" +#include "access/heapam.h" #include "access/htup.h" #include "access/itup.h" #include "access/skey.h" @@ -192,6 +193,8 @@ Boot_CreateStmt: RELKIND_RELATION, $3, true); + boot_reldesc->rd_options = + heap_option(RELKIND_RELATION, NULL); elog(DEBUG4, "bootstrap relation created"); } else @@ -209,7 +212,8 @@ Boot_CreateStmt: true, 0, ONCOMMIT_NOOP, - true); + true, + NULL); elog(DEBUG4, "relation created with oid %u", id); } do_end(); @@ -252,7 +256,7 @@ Boot_DeclareIndexStmt: LexIDStr($8), NULL, $10, - NULL, NIL, + NULL, NIL, NIL, false, false, false, false, false, true, false); do_end(); @@ -270,7 +274,7 @@ Boot_DeclareUniqueIndexStmt: LexIDStr($9), NULL, $11, - NULL, NIL, + NULL, NIL, NIL, true, false, false, false, false, true, false); do_end(); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 85d1cb5d13..e2eed023e0 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.302 2006/06/29 16:07:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.303 2006/07/02 02:23:19 momjian Exp $ * * * INTERFACE ROUTINES @@ -44,20 +44,24 @@ #include "catalog/pg_type.h" #include "commands/tablecmds.h" #include "commands/trigger.h" +#include "commands/defrem.h" #include "miscadmin.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/planmain.h" #include "optimizer/var.h" #include "parser/parse_coerce.h" +#include "parser/parse_clause.h" #include "parser/parse_expr.h" #include "parser/parse_relation.h" #include "rewrite/rewriteRemove.h" #include "storage/smgr.h" +#include "utils/catcache.h" #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/inval.h" #include "utils/lsyscache.h" +#include "utils/memutils.h" #include "utils/relcache.h" #include "utils/syscache.h" @@ -66,7 +70,8 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid, Oid relowner, - char relkind); + char relkind, + ArrayType *options); static Oid AddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, @@ -558,7 +563,8 @@ AddNewRelationTuple(Relation pg_class_desc, Oid new_rel_oid, Oid new_type_oid, Oid relowner, - char relkind) + char relkind, + ArrayType *options) { Form_pg_class new_rel_reltup; HeapTuple tup; @@ -596,15 +602,8 @@ AddNewRelationTuple(Relation pg_class_desc, new_rel_desc->rd_att->tdtypeid = new_type_oid; - /* ---------------- - * now form a tuple to add to pg_class - * XXX Natts_pg_class_fixed is a hack - see pg_class.h - * ---------------- - */ - tup = heap_addheader(Natts_pg_class_fixed, - true, - CLASS_TUPLE_SIZE, - (void *) new_rel_reltup); + /* now form a tuple to add to pg_class */ + tup = build_class_tuple(new_rel_reltup, options); /* force tuple to have the desired OID */ HeapTupleSetOid(tup, new_rel_oid); @@ -661,6 +660,8 @@ AddNewRelationType(const char *typeName, * heap_create_with_catalog * * creates a new cataloged relation. see comments above. + * + * if opaque is specified, it must be allocated in CacheMemoryContext. * -------------------------------- */ Oid @@ -675,10 +676,12 @@ heap_create_with_catalog(const char *relname, bool oidislocal, int oidinhcount, OnCommitAction oncommit, - bool allow_system_table_mods) + bool allow_system_table_mods, + ArrayType *options) { Relation pg_class_desc; Relation new_rel_desc; + bytea *new_rel_options; Oid new_type_oid; pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); @@ -695,6 +698,13 @@ heap_create_with_catalog(const char *relname, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("relation \"%s\" already exists", relname))); + /* + * Parse options to check if option is valid. + */ + new_rel_options = heap_option(relkind, options); + Assert(!new_rel_options || + GetMemoryChunkContext(new_rel_options) == CacheMemoryContext); + /* * Allocate an OID for the relation, unless we were told what to use. * @@ -718,6 +728,7 @@ heap_create_with_catalog(const char *relname, relkind, shared_relation, allow_system_table_mods); + new_rel_desc->rd_options = new_rel_options; Assert(relid == RelationGetRelid(new_rel_desc)); @@ -745,7 +756,8 @@ heap_create_with_catalog(const char *relname, relid, new_type_oid, ownerid, - relkind); + relkind, + options); /* * now add tuples to pg_attribute for the attributes in our new relation. diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index d0f216475e..9143f6068a 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.266 2006/05/10 23:18:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.267 2006/07/02 02:23:19 momjian Exp $ * * * INTERFACE ROUTINES @@ -37,6 +37,7 @@ #include "executor/executor.h" #include "miscadmin.h" #include "optimizer/clauses.h" +#include "parser/parse_clause.h" #include "parser/parse_expr.h" #include "storage/procarray.h" #include "storage/smgr.h" @@ -53,7 +54,8 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation, IndexInfo *indexInfo, Oid *classObjectId); -static void UpdateRelationRelation(Relation pg_class, Relation indexRelation); +static void UpdateRelationRelation(Relation pg_class, Relation indexRelation, + ArrayType *options); static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid); static void AppendAttributeTuples(Relation indexRelation, int numatts); @@ -241,15 +243,12 @@ ConstructTupleDescriptor(Relation heapRelation, * ---------------------------------------------------------------- */ static void -UpdateRelationRelation(Relation pg_class, Relation indexRelation) +UpdateRelationRelation(Relation pg_class, Relation indexRelation, + ArrayType *options) { HeapTuple tuple; - /* XXX Natts_pg_class_fixed is a hack - see pg_class.h */ - tuple = heap_addheader(Natts_pg_class_fixed, - true, - CLASS_TUPLE_SIZE, - (void *) indexRelation->rd_rel); + tuple = build_class_tuple(indexRelation->rd_rel, options); /* * the new tuple must have the oid already chosen for the index. sure @@ -467,6 +466,7 @@ index_create(Oid heapRelationId, Oid accessMethodObjectId, Oid tableSpaceId, Oid *classObjectId, + List *options, bool isprimary, bool istoast, bool isconstraint, @@ -481,6 +481,9 @@ index_create(Oid heapRelationId, Oid namespaceId; int i; + ArrayType *array; + RegProcedure amoption; + pg_class = heap_open(RelationRelationId, RowExclusiveLock); /* @@ -578,12 +581,41 @@ index_create(Oid heapRelationId, indexRelation->rd_rel->relkind = RELKIND_INDEX; indexRelation->rd_rel->relhasoids = false; + /* + * AM specific options. + */ + array = OptionBuild(NULL, options); + if (indexRelation->rd_am) + { + amoption = indexRelation->rd_am->amoption; + } + else + { + HeapTuple tuple; + + /* + * We may use the access method before initializing relation, + * so we pick up AM from syscache directly. + */ + tuple = SearchSysCache(AMOID, + ObjectIdGetDatum(accessMethodObjectId), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for access method %u", + accessMethodObjectId); + amoption = ((Form_pg_am) GETSTRUCT(tuple))->amoption; + ReleaseSysCache(tuple); + } + indexRelation->rd_options = index_option(amoption, array); + /* * store index's pg_class entry */ - UpdateRelationRelation(pg_class, indexRelation); + UpdateRelationRelation(pg_class, indexRelation, array); /* done with pg_class */ + if (array) + pfree(array); heap_close(pg_class, RowExclusiveLock); /* @@ -1751,3 +1783,23 @@ reindex_relation(Oid relid, bool toast_too) return result; } + +/* + * Parse options for indexes. + * + * amoption Oid of option parser. + * options Options as text[] + */ +bytea *index_option(RegProcedure amoption, ArrayType *options) +{ + Datum datum; + + Assert(RegProcedureIsValid(amoption)); + + datum = OidFunctionCall1(amoption, PointerGetDatum(options)); + + if (DatumGetPointer(datum) == NULL) + return NULL; + + return DatumGetByteaP(datum); +} diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 8b96dbe5a6..2ed1a156a4 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -9,16 +9,19 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/indexing.c,v 1.111 2006/03/05 15:58:22 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/indexing.c,v 1.112 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/genam.h" +#include "access/heapam.h" #include "catalog/index.h" #include "catalog/indexing.h" #include "executor/executor.h" +#include "utils/syscache.h" +#include "commands/defrem.h" /* diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 381b6ed596..08b76e96d5 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.147 2006/05/02 22:25:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.148 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -566,6 +566,8 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace) tupdesc; Oid OIDNewHeap; Relation OldHeap; + HeapTuple tuple; + ArrayType *options; OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock); OldHeapDesc = RelationGetDescr(OldHeap); @@ -576,6 +578,26 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace) */ tupdesc = CreateTupleDescCopyConstr(OldHeapDesc); + /* + * Use options of the old heap for new heap. + */ + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(OIDOldHeap), + 0, 0, 0); + if (tuple) + { + Datum datum; + bool isNull; + datum = SysCacheGetAttr(RELOID, tuple, + Anum_pg_class_reloptions, &isNull); + options = isNull ? NULL : DatumGetArrayTypeP(datum); + } + else + { + /* should not happen */ + options = NULL; + } + OIDNewHeap = heap_create_with_catalog(NewName, RelationGetNamespace(OldHeap), NewTableSpace, @@ -587,7 +609,10 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace) true, 0, ONCOMMIT_NOOP, - allowSystemTableMods); + allowSystemTableMods, + options); + + ReleaseSysCache(tuple); /* * Advance command counter so that the newly-created relation's catalog diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 98cded67cc..ebde8f1095 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.95 2006/03/14 22:48:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.96 2006/07/02 02:23:19 momjian Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -110,6 +110,7 @@ defGetNumeric(DefElem *def) case T_Integer: return (double) intVal(def->arg); case T_Float: + case T_String: /* XXX: needs strict check? */ return floatVal(def->arg); default: ereport(ERROR, @@ -127,14 +128,30 @@ bool defGetBoolean(DefElem *def) { /* - * Presently, boolean flags must simply be present or absent. Later we - * could allow 'flag = t', 'flag = f', etc. + * Presently, boolean flags must simply be present/absent or + * integer 0/1. Later we could allow 'flag = t', 'flag = f', etc. */ if (def->arg == NULL) return true; + switch (nodeTag(def->arg)) + { + case T_Integer: + switch (intVal(def->arg)) + { + case 0: + return false; + case 1: + return true; + } + break; + default: + break; + } + + /* on error */ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("%s does not take a parameter", + errmsg("%s requires a boolean value", def->defname))); return false; /* keep compiler quiet */ } @@ -155,7 +172,7 @@ defGetInt64(DefElem *def) case T_Integer: return (int64) intVal(def->arg); case T_Float: - + case T_String: /* XXX: needs strict check? */ /* * Values too large for int4 will be represented as Float * constants by the lexer. Accept these if they are valid int8 @@ -275,3 +292,12 @@ defGetTypeLength(DefElem *def) def->defname, defGetString(def)))); return 0; /* keep compiler quiet */ } + +DefElem * +defWithOids(bool value) +{ + DefElem *f = makeNode(DefElem); + f->defname = "oids"; + f->arg = (Node *)makeInteger(value); + return f; +} diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index e3813a2ca5..7e35258ac0 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.141 2006/06/07 17:20:17 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.142 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -77,6 +77,7 @@ static bool relationHasPrimaryKey(Relation rel); * 'isconstraint': index is for a PRIMARY KEY or UNIQUE constraint, * so build a pg_constraint entry for it. * 'is_alter_table': this is due to an ALTER rather than a CREATE operation. + * 'options': options passed by WITH. * 'check_rights': check for CREATE rights in the namespace. (This should * be true except when ALTER is deleting/recreating an index.) * 'skip_build': make the catalog entries but leave the index file empty; @@ -92,6 +93,7 @@ DefineIndex(RangeVar *heapRelation, List *attributeList, Expr *predicate, List *rangetable, + List *options, bool unique, bool primary, bool isconstraint, @@ -397,7 +399,7 @@ DefineIndex(RangeVar *heapRelation, index_create(relationId, indexRelationName, indexRelationId, indexInfo, accessMethodId, tablespaceId, classObjectId, - primary, false, isconstraint, + options, primary, false, isconstraint, allowSystemTableMods, skip_build); } diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index d89c01a62e..27ccb3fb87 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2006, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.53 2006/06/20 22:51:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.54 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -196,6 +196,7 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); query->into = copyObject(stmt->into); + query->intoOptions = copyObject(stmt->intoOptions); query->intoHasOids = stmt->into_has_oids; query->intoOnCommit = stmt->into_on_commit; if (stmt->into_tbl_space) diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 10ebe56b6a..65712c2092 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.132 2006/03/31 23:32:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.133 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -180,7 +180,7 @@ DefineSequence(CreateSeqStmt *seq) stmt->relation = seq->sequence; stmt->inhRelations = NIL; stmt->constraints = NIL; - stmt->hasoids = MUST_NOT_HAVE_OIDS; + stmt->options = list_make1(defWithOids(false)); stmt->oncommit = ONCOMMIT_NOOP; stmt->tablespacename = NULL; @@ -205,7 +205,17 @@ DefineSequence(CreateSeqStmt *seq) /* Now form & insert sequence tuple */ tuple = heap_formtuple(tupDesc, value, null); - simple_heap_insert(rel, tuple); + + { + /* + * HACK: Sequences insert only one tuple during initialize. + * We treat sequences as heaps then. + */ + HeapOption opaque = { sizeof(HeapOption), 100 }; + rel->rd_options = (bytea *) &opaque; + simple_heap_insert(rel, tuple); + rel->rd_options = NULL; + } Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index d22db6e45b..f3331c6904 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.189 2006/07/02 01:58:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.190 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -62,7 +62,6 @@ #include "utils/relcache.h" #include "utils/syscache.h" - /* * ON COMMIT action list */ @@ -196,6 +195,7 @@ static void ATRewriteTables(List **wqueue); static void ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap); static AlteredTableInfo *ATGetQueueEntry(List **wqueue, Relation rel); static void ATSimplePermissions(Relation rel, bool allowView); +static void ATSimplePermissionsRelationOrIndex(Relation rel); static void ATSimpleRecursion(List **wqueue, Relation rel, AlterTableCmd *cmd, bool recurse); static void ATOneLevelRecursion(List **wqueue, Relation rel, @@ -248,6 +248,7 @@ static void ATExecDropCluster(Relation rel); static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace); +static void ATExecSetOptions(Relation rel, List *newOptions); static void ATExecEnableDisableTrigger(Relation rel, char *trigname, bool enable, bool skip_system); static void ATExecAddInherits(Relation rel, RangeVar *parent); @@ -285,6 +286,7 @@ DefineRelation(CreateStmt *stmt, char relkind) ListCell *listptr; int i; AttrNumber attnum; + ArrayType *options; /* * Truncate relname to appropriate length (probably a waste of time, as @@ -366,7 +368,7 @@ DefineRelation(CreateStmt *stmt, char relkind) */ descriptor = BuildDescForRelation(schema); - localHasOids = interpretOidsOption(stmt->hasoids); + localHasOids = interpretOidsOption(stmt->options); descriptor->tdhasoid = (localHasOids || parentOidCount > 0); if (old_constraints != NIL) @@ -426,6 +428,7 @@ DefineRelation(CreateStmt *stmt, char relkind) } } + options = OptionBuild(NULL, stmt->options); relationId = heap_create_with_catalog(relname, namespaceId, tablespaceId, @@ -437,7 +440,10 @@ DefineRelation(CreateStmt *stmt, char relkind) localHasOids, parentOidCount, stmt->oncommit, - allowSystemTableMods); + allowSystemTableMods, + options); + if (options) + pfree(options); StoreCatalogInheritance(relationId, inheritOids); @@ -2092,10 +2098,17 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_DROP; break; case AT_SetTableSpace: /* SET TABLESPACE */ + ATSimplePermissionsRelationOrIndex(rel); /* This command never recurses */ ATPrepSetTableSpace(tab, rel, cmd->name); pass = AT_PASS_MISC; /* doesn't actually matter */ break; + case AT_SetOptions: /* SET (...) */ + ATSimplePermissionsRelationOrIndex(rel); + /* This command never recurses */ + /* No command-specific prep needed */ + pass = AT_PASS_MISC; + break; case AT_EnableTrig: /* ENABLE TRIGGER variants */ case AT_EnableTrigAll: case AT_EnableTrigUser: @@ -2266,6 +2279,9 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd) * Nothing to do here; Phase 3 does the work */ break; + case AT_SetOptions: /* SET (...) */ + ATExecSetOptions(rel, (List *) cmd->def); + break; case AT_EnableTrig: /* ENABLE TRIGGER name */ ATExecEnableDisableTrigger(rel, cmd->name, true, false); break; @@ -2776,6 +2792,35 @@ ATSimplePermissions(Relation rel, bool allowView) RelationGetRelationName(rel)))); } +/* + * ATSimplePermissionsRelationOrIndex + * + * - Ensure that it is a relation or an index + * - Ensure this user is the owner + * - Ensure that it is not a system table + */ +static void +ATSimplePermissionsRelationOrIndex(Relation rel) +{ + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or index", + RelationGetRelationName(rel)))); + + /* Permissions checks */ + if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + + if (!allowSystemTableMods && IsSystemRelation(rel)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + RelationGetRelationName(rel)))); +} + /* * ATSimpleRecursion * @@ -3804,6 +3849,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, stmt->indexParams, /* parameters */ (Expr *) stmt->whereClause, stmt->rangetable, + stmt->options, stmt->unique, stmt->primary, stmt->isconstraint, @@ -5690,28 +5736,6 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename) Oid tablespaceId; AclResult aclresult; - /* - * We do our own permission checking because we want to allow this on - * indexes. - */ - if (rel->rd_rel->relkind != RELKIND_RELATION && - rel->rd_rel->relkind != RELKIND_INDEX) - ereport(ERROR, - (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a table or index", - RelationGetRelationName(rel)))); - - /* Permissions checks */ - if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(rel)); - - if (!allowSystemTableMods && IsSystemRelation(rel)) - ereport(ERROR, - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), - errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(rel)))); - /* Check that the tablespace exists */ tablespaceId = get_tablespace_oid(tablespacename); if (!OidIsValid(tablespaceId)) @@ -5732,6 +5756,89 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename) tab->newTableSpace = tablespaceId; } +/* + * ALTER TABLE/INDEX SET (...) + */ +static void +ATExecSetOptions(Relation rel, List *newOptions) +{ + Oid relid; + Relation pgclass; + HeapTuple tuple; + Datum datum; + bool isnull; + ArrayType *mergedOptions; + bytea *options; + + if (list_length(newOptions) == 0) + return; /* do nothing */ + + relid = RelationGetRelid(rel); + pgclass = heap_open(RelationRelationId, RowExclusiveLock); + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", relid); + + datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull); + + mergedOptions = OptionBuild( + isnull ? NULL : DatumGetArrayTypeP(datum), newOptions); + + switch (rel->rd_rel->relkind) + { + case RELKIND_RELATION: + case RELKIND_TOASTVALUE: + options = heap_option(rel->rd_rel->relkind, mergedOptions); + break; + case RELKIND_INDEX: + options = index_option(rel->rd_am->amoption, mergedOptions); + break; + default: + elog(ERROR, "unexpected RELKIND=%c", rel->rd_rel->relkind); + options = NULL; /* keep compiler quiet */ + break; + } + + if (rel->rd_options != options) + { + HeapTuple newtuple; + Datum repl_val[Natts_pg_class]; + char repl_null[Natts_pg_class]; + char repl_repl[Natts_pg_class]; + + /* XXX: This is not necessarily required. */ + if (rel->rd_options) + pfree(rel->rd_options); + rel->rd_options = options; + + memset(repl_repl, ' ', sizeof(repl_repl)); + memset(repl_null, ' ', sizeof(repl_null)); + repl_repl[Anum_pg_class_reloptions - 1] = 'r'; + + if (mergedOptions) + repl_val[Anum_pg_class_reloptions - 1] = + PointerGetDatum(mergedOptions); + else + repl_null[Anum_pg_class_reloptions - 1] = 'n'; + + newtuple = heap_modifytuple(tuple, RelationGetDescr(pgclass), + repl_val, repl_null, repl_repl); + + simple_heap_update(pgclass, &newtuple->t_self, newtuple); + CatalogUpdateIndexes(pgclass, newtuple); + + heap_freetuple(newtuple); + } + + if (mergedOptions) + pfree(mergedOptions); + + ReleaseSysCache(tuple); + heap_close(pgclass, RowExclusiveLock); +} + /* * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple * rewriting to be done, so we just want to copy the data as fast as possible. @@ -6553,7 +6660,8 @@ AlterTableCreateToastTable(Oid relOid, bool silent) true, 0, ONCOMMIT_NOOP, - true); + true, + NULL); /* make the toast relation visible, else index creation will fail */ CommandCounterIncrement(); @@ -6587,7 +6695,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent) indexInfo, BTREE_AM_OID, rel->rd_rel->reltablespace, - classObjectId, + classObjectId, NIL, true, true, false, true, false); /* diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index b907d677e0..0387d050cd 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.91 2006/06/21 18:09:53 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.92 2006/07/02 02:23:19 momjian Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -1130,7 +1130,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist) createStmt->tableElts = coldeflist; createStmt->inhRelations = NIL; createStmt->constraints = NIL; - createStmt->hasoids = MUST_NOT_HAVE_OIDS; + createStmt->options = list_make1(defWithOids(false)); createStmt->oncommit = ONCOMMIT_NOOP; createStmt->tablespacename = NULL; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 4381369bc0..24a93e998d 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.330 2006/05/10 23:18:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.331 2006/07/02 02:23:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -242,6 +242,7 @@ static int vac_cmp_blk(const void *left, const void *right); static int vac_cmp_offno(const void *left, const void *right); static int vac_cmp_vtlinks(const void *left, const void *right); static bool enough_space(VacPage vacpage, Size len); +static Size PageGetFreeSpaceWithFillFactor(Relation relation, Page page); /**************************************************************************** @@ -1282,7 +1283,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, relname, blkno))); PageInit(page, BufferGetPageSize(buf), 0); MarkBufferDirty(buf); - vacpage->free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower; + vacpage->free = PageGetFreeSpaceWithFillFactor(onerel, page); free_space += vacpage->free; empty_pages++; empty_end_pages++; @@ -1297,7 +1298,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, { VacPage vacpagecopy; - vacpage->free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower; + vacpage->free = PageGetFreeSpaceWithFillFactor(onerel, page); free_space += vacpage->free; empty_pages++; empty_end_pages++; @@ -1465,14 +1466,14 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, { /* Some tuples are removable; figure free space after removal */ PageRepairFragmentation(tempPage, NULL); - vacpage->free = ((PageHeader) tempPage)->pd_upper - ((PageHeader) tempPage)->pd_lower; + vacpage->free = PageGetFreeSpaceWithFillFactor(onerel, tempPage); pfree(tempPage); do_reap = true; } else { /* Just use current available space */ - vacpage->free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower; + vacpage->free = PageGetFreeSpaceWithFillFactor(onerel, page); /* Need to reap the page if it has ~LP_USED line pointers */ do_reap = (vacpage->offsets_free > 0); } @@ -2709,8 +2710,7 @@ move_plain_tuple(Relation rel, END_CRIT_SECTION(); - dst_vacpage->free = ((PageHeader) dst_page)->pd_upper - - ((PageHeader) dst_page)->pd_lower; + dst_vacpage->free = PageGetFreeSpaceWithFillFactor(rel, dst_page); LockBuffer(dst_buf, BUFFER_LOCK_UNLOCK); LockBuffer(old_buf, BUFFER_LOCK_UNLOCK); @@ -3119,6 +3119,8 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages, * vacuumlazy.c does, we'd be skewing that statistic. */ threshold = GetAvgFSMRequestSize(&onerel->rd_node); + if (threshold < HeapGetPageFreeSpace(onerel)) + threshold = HeapGetPageFreeSpace(onerel); pageSpaces = (PageFreeSpaceInfo *) palloc(nPages * sizeof(PageFreeSpaceInfo)); @@ -3385,6 +3387,18 @@ enough_space(VacPage vacpage, Size len) return false; } +static Size +PageGetFreeSpaceWithFillFactor(Relation relation, Page page) +{ + PageHeader pd = (PageHeader) page; + Size pagefree = HeapGetPageFreeSpace(relation); + Size freespace = pd->pd_upper - pd->pd_lower; + + if (freespace > pagefree) + return freespace - pagefree; + else + return 0; +} /* * vacuum_delay_point --- check for interrupts and cost-based delay. diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 00fda19231..8e97fa4756 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -31,7 +31,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.70 2006/05/02 22:25:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.71 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -149,6 +149,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt) /* Set threshold for interesting free space = average request size */ /* XXX should we scale it up or down? Adjust vacuum.c too, if so */ vacrelstats->threshold = GetAvgFSMRequestSize(&onerel->rd_node); + if (vacrelstats->threshold < HeapGetPageFreeSpace(onerel)) + vacrelstats->threshold = HeapGetPageFreeSpace(onerel); /* Open all indexes of the relation */ vac_open_indexes(onerel, ShareUpdateExclusiveLock, &nindexes, &Irel); diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 490e0aa351..12f06b0b24 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.94 2006/03/14 22:48:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.95 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/heapam.h" #include "catalog/dependency.h" #include "catalog/namespace.h" +#include "commands/defrem.h" #include "commands/tablecmds.h" #include "commands/view.h" #include "miscadmin.h" @@ -195,7 +196,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) createStmt->tableElts = attrList; createStmt->inhRelations = NIL; createStmt->constraints = NIL; - createStmt->hasoids = MUST_NOT_HAVE_OIDS; + createStmt->options = list_make1(defWithOids(false)); createStmt->oncommit = ONCOMMIT_NOOP; createStmt->tablespacename = NULL; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index b39e7a587b..bb03b9358c 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.271 2006/06/16 18:42:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.272 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -45,6 +45,7 @@ #include "miscadmin.h" #include "optimizer/clauses.h" #include "optimizer/var.h" +#include "parser/parse_clause.h" #include "parser/parsetree.h" #include "storage/smgr.h" #include "utils/acl.h" @@ -729,6 +730,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) AclResult aclresult; Oid intoRelationId; TupleDesc tupdesc; + ArrayType *options; /* * Check consistency of arguments @@ -786,6 +788,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) */ tupdesc = CreateTupleDescCopy(tupType); + options = OptionBuild(NULL, parseTree->intoOptions); intoRelationId = heap_create_with_catalog(intoName, namespaceId, tablespaceId, @@ -797,7 +800,10 @@ InitPlan(QueryDesc *queryDesc, int eflags) true, 0, parseTree->intoOnCommit, - allowSystemTableMods); + allowSystemTableMods, + options); + if (options) + pfree(options); FreeTupleDesc(tupdesc); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 7277e539e8..4e1a098c5e 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.339 2006/07/02 01:58:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.340 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1640,6 +1640,7 @@ _copyConstraint(Constraint *from) COPY_NODE_FIELD(raw_expr); COPY_STRING_FIELD(cooked_expr); COPY_NODE_FIELD(keys); + COPY_NODE_FIELD(options); COPY_STRING_FIELD(indexspace); return newnode; @@ -1680,6 +1681,7 @@ _copyQuery(Query *from) COPY_SCALAR_FIELD(resultRelation); COPY_NODE_FIELD(into); COPY_SCALAR_FIELD(intoHasOids); + COPY_NODE_FIELD(intoOptions); COPY_SCALAR_FIELD(intoOnCommit); COPY_STRING_FIELD(intoTableSpaceName); COPY_SCALAR_FIELD(hasAggs); @@ -1746,7 +1748,7 @@ _copySelectStmt(SelectStmt *from) COPY_NODE_FIELD(distinctClause); COPY_NODE_FIELD(into); COPY_NODE_FIELD(intoColNames); - COPY_SCALAR_FIELD(intoHasOids); + COPY_NODE_FIELD(intoOptions); COPY_SCALAR_FIELD(intoOnCommit); COPY_STRING_FIELD(intoTableSpaceName); COPY_NODE_FIELD(targetList); @@ -1929,7 +1931,7 @@ _copyCreateStmt(CreateStmt *from) COPY_NODE_FIELD(tableElts); COPY_NODE_FIELD(inhRelations); COPY_NODE_FIELD(constraints); - COPY_SCALAR_FIELD(hasoids); + COPY_NODE_FIELD(options); COPY_SCALAR_FIELD(oncommit); COPY_STRING_FIELD(tablespacename); @@ -2021,6 +2023,7 @@ _copyIndexStmt(IndexStmt *from) COPY_STRING_FIELD(accessMethod); COPY_STRING_FIELD(tableSpace); COPY_NODE_FIELD(indexParams); + COPY_NODE_FIELD(options); COPY_NODE_FIELD(whereClause); COPY_NODE_FIELD(rangetable); COPY_SCALAR_FIELD(unique); @@ -2638,8 +2641,8 @@ _copyExecuteStmt(ExecuteStmt *from) COPY_STRING_FIELD(name); COPY_NODE_FIELD(into); - COPY_SCALAR_FIELD(into_contains_oids); COPY_SCALAR_FIELD(into_has_oids); + COPY_NODE_FIELD(intoOptions); COPY_SCALAR_FIELD(into_on_commit); COPY_STRING_FIELD(into_tbl_space); COPY_NODE_FIELD(params); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 56d8d09a02..3af0acb10a 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.273 2006/06/27 03:43:20 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.274 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -659,6 +659,7 @@ _equalQuery(Query *a, Query *b) COMPARE_SCALAR_FIELD(resultRelation); COMPARE_NODE_FIELD(into); COMPARE_SCALAR_FIELD(intoHasOids); + COMPARE_NODE_FIELD(intoOptions); COMPARE_SCALAR_FIELD(intoOnCommit); COMPARE_STRING_FIELD(intoTableSpaceName); COMPARE_SCALAR_FIELD(hasAggs); @@ -717,7 +718,7 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b) COMPARE_NODE_FIELD(distinctClause); COMPARE_NODE_FIELD(into); COMPARE_NODE_FIELD(intoColNames); - COMPARE_SCALAR_FIELD(intoHasOids); + COMPARE_NODE_FIELD(intoOptions); COMPARE_SCALAR_FIELD(intoOnCommit); COMPARE_STRING_FIELD(intoTableSpaceName); COMPARE_NODE_FIELD(targetList); @@ -873,7 +874,7 @@ _equalCreateStmt(CreateStmt *a, CreateStmt *b) COMPARE_NODE_FIELD(tableElts); COMPARE_NODE_FIELD(inhRelations); COMPARE_NODE_FIELD(constraints); - COMPARE_SCALAR_FIELD(hasoids); + COMPARE_NODE_FIELD(options); COMPARE_SCALAR_FIELD(oncommit); COMPARE_STRING_FIELD(tablespacename); @@ -951,6 +952,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b) COMPARE_STRING_FIELD(accessMethod); COMPARE_STRING_FIELD(tableSpace); COMPARE_NODE_FIELD(indexParams); + COMPARE_NODE_FIELD(options); COMPARE_NODE_FIELD(whereClause); COMPARE_NODE_FIELD(rangetable); COMPARE_SCALAR_FIELD(unique); @@ -1471,8 +1473,8 @@ _equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b) { COMPARE_STRING_FIELD(name); COMPARE_NODE_FIELD(into); - COMPARE_SCALAR_FIELD(into_contains_oids); COMPARE_SCALAR_FIELD(into_has_oids); + COMPARE_NODE_FIELD(intoOptions); COMPARE_SCALAR_FIELD(into_on_commit); COMPARE_STRING_FIELD(into_tbl_space); COMPARE_NODE_FIELD(params); @@ -1673,6 +1675,7 @@ _equalConstraint(Constraint *a, Constraint *b) COMPARE_NODE_FIELD(raw_expr); COMPARE_STRING_FIELD(cooked_expr); COMPARE_NODE_FIELD(keys); + COMPARE_NODE_FIELD(options); COMPARE_STRING_FIELD(indexspace); return true; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 7444001acb..d865360563 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.275 2006/07/01 18:38:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.276 2006/07/02 02:23:20 momjian Exp $ * * NOTES * Every node type that can appear in stored rules' parsetrees *must* @@ -1325,7 +1325,7 @@ _outCreateStmt(StringInfo str, CreateStmt *node) WRITE_NODE_FIELD(tableElts); WRITE_NODE_FIELD(inhRelations); WRITE_NODE_FIELD(constraints); - WRITE_ENUM_FIELD(hasoids, ContainsOids); + WRITE_NODE_FIELD(options); WRITE_ENUM_FIELD(oncommit, OnCommitAction); WRITE_STRING_FIELD(tablespacename); } @@ -1340,6 +1340,7 @@ _outIndexStmt(StringInfo str, IndexStmt *node) WRITE_STRING_FIELD(accessMethod); WRITE_STRING_FIELD(tableSpace); WRITE_NODE_FIELD(indexParams); + WRITE_NODE_FIELD(options); WRITE_NODE_FIELD(whereClause); WRITE_NODE_FIELD(rangetable); WRITE_BOOL_FIELD(unique); @@ -1373,7 +1374,7 @@ _outSelectStmt(StringInfo str, SelectStmt *node) WRITE_NODE_FIELD(distinctClause); WRITE_NODE_FIELD(into); WRITE_NODE_FIELD(intoColNames); - WRITE_ENUM_FIELD(intoHasOids, ContainsOids); + WRITE_NODE_FIELD(intoOptions); WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction); WRITE_STRING_FIELD(intoTableSpaceName); WRITE_NODE_FIELD(targetList); @@ -1509,6 +1510,7 @@ _outQuery(StringInfo str, Query *node) WRITE_INT_FIELD(resultRelation); WRITE_NODE_FIELD(into); WRITE_BOOL_FIELD(intoHasOids); + WRITE_NODE_FIELD(intoOptions); WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction); WRITE_STRING_FIELD(intoTableSpaceName); WRITE_BOOL_FIELD(hasAggs); @@ -1762,12 +1764,14 @@ _outConstraint(StringInfo str, Constraint *node) case CONSTR_PRIMARY: appendStringInfo(str, "PRIMARY_KEY"); WRITE_NODE_FIELD(keys); + WRITE_NODE_FIELD(options); WRITE_STRING_FIELD(indexspace); break; case CONSTR_UNIQUE: appendStringInfo(str, "UNIQUE"); WRITE_NODE_FIELD(keys); + WRITE_NODE_FIELD(options); WRITE_STRING_FIELD(indexspace); break; diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index dd6995a172..0e061c44c5 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.189 2006/04/30 18:30:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.190 2006/07/02 02:23:20 momjian Exp $ * * NOTES * Path and Plan nodes do not have any readfuncs support, because we @@ -141,6 +141,7 @@ _readQuery(void) READ_INT_FIELD(resultRelation); READ_NODE_FIELD(into); READ_BOOL_FIELD(intoHasOids); + READ_NODE_FIELD(intoOptions); READ_ENUM_FIELD(intoOnCommit, OnCommitAction); READ_STRING_FIELD(intoTableSpaceName); READ_BOOL_FIELD(hasAggs); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 8b9b9eab53..9e66ca1ab6 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.336 2006/06/27 03:43:20 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.337 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -757,7 +757,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt, cxt.blist = NIL; cxt.alist = NIL; cxt.pkey = NULL; - cxt.hasoids = interpretOidsOption(stmt->hasoids); + cxt.hasoids = interpretOidsOption(stmt->options); /* * Run through each primary element in the table creation clause. Separate @@ -1282,6 +1282,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) index->relation = cxt->relation; index->accessMethod = DEFAULT_INDEX_TYPE; + index->options = constraint->options; index->tableSpace = constraint->indexspace; index->indexParams = NIL; index->whereClause = NULL; @@ -1881,7 +1882,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) if (stmt->intoColNames) applyColumnNames(qry->targetList, stmt->intoColNames); - qry->intoHasOids = interpretOidsOption(stmt->intoHasOids); + qry->intoHasOids = interpretOidsOption(stmt->intoOptions); + qry->intoOptions = copyObject(stmt->intoOptions); qry->intoOnCommit = stmt->intoOnCommit; qry->intoTableSpaceName = stmt->intoTableSpaceName; @@ -2752,7 +2754,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt) paramtypes = FetchPreparedStatementParams(stmt->name); - stmt->into_has_oids = interpretOidsOption(stmt->into_contains_oids); + stmt->into_has_oids = interpretOidsOption(stmt->intoOptions); if (stmt->params || paramtypes) { diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 9ad722528e..f09a7a6b2d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.549 2006/07/02 01:58:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.550 2006/07/02 02:23:21 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -53,6 +53,7 @@ #include "catalog/index.h" #include "catalog/namespace.h" +#include "commands/defrem.h" #include "nodes/makefuncs.h" #include "parser/gramparse.h" #include "storage/lmgr.h" @@ -123,7 +124,6 @@ static void doNegateFloat(Value *v); JoinType jtype; DropBehavior dbehavior; OnCommitAction oncommit; - ContainsOids withoids; List *list; Node *node; Value *value; @@ -228,11 +228,11 @@ static void doNegateFloat(Value *v); %type stmtblock stmtmulti OptTableElementList TableElementList OptInherit definition - opt_distinct opt_definition func_args func_args_list + OptWith opt_distinct opt_definition func_args func_args_list func_as createfunc_opt_list alterfunc_opt_list aggr_args aggr_args_list old_aggr_definition old_aggr_list oper_argtypes RuleActionList RuleActionMulti - opt_column_list columnList opt_name_list + opt_column_list columnList opt_name_list sort_clause opt_sort_clause sortby_list index_params name_list from_clause from_list opt_array_bounds qualified_name_list any_name any_name_list @@ -255,7 +255,6 @@ static void doNegateFloat(Value *v); %type TriggerForType OptTemp %type OnCommitOption -%type OptWithOids %type for_locking_item %type for_locking_clause opt_for_locking_clause for_locking_items @@ -1559,6 +1558,32 @@ alter_rel_cmd: n->name = $3; $$ = (Node *)n; } + /* ALTER [TABLE|INDEX] SET (...) */ + | SET definition + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetOptions; + n->def = (Node *)$2; + $$ = (Node *)n; + } + | RESET definition + { + AlterTableCmd *n; + ListCell *cell; + + foreach(cell, $2) + { + if (((DefElem *) lfirst(cell))->arg != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("parameters for RESET should not take values"))); + } + + n = makeNode(AlterTableCmd); + n->subtype = AT_SetOptions; + n->def = (Node *)$2; + $$ = (Node *)n; + } ; alter_column_default: @@ -1744,7 +1769,7 @@ opt_using: *****************************************************************************/ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' - OptInherit OptWithOids OnCommitOption OptTableSpace + OptInherit OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->istemp = $2; @@ -1752,13 +1777,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tableElts = $6; n->inhRelations = $8; n->constraints = NIL; - n->hasoids = $9; + n->options = $9; n->oncommit = $10; n->tablespacename = $11; $$ = (Node *)n; } | CREATE OptTemp TABLE qualified_name OF qualified_name - '(' OptTableElementList ')' OptWithOids OnCommitOption OptTableSpace + '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace { /* SQL99 CREATE TABLE OF (cols) seems to be satisfied * by our inheritance capabilities. Let's try it... @@ -1769,7 +1794,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tableElts = $8; n->inhRelations = list_make1($6); n->constraints = NIL; - n->hasoids = $10; + n->options = $10; n->oncommit = $11; n->tablespacename = $12; $$ = (Node *)n; @@ -1905,7 +1930,7 @@ ColConstraintElem: n->indexspace = $2; $$ = (Node *)n; } - | PRIMARY KEY OptConsTableSpace + | PRIMARY KEY opt_definition OptConsTableSpace { Constraint *n = makeNode(Constraint); n->contype = CONSTR_PRIMARY; @@ -1913,7 +1938,8 @@ ColConstraintElem: n->raw_expr = NULL; n->cooked_expr = NULL; n->keys = NULL; - n->indexspace = $3; + n->options = $3; + n->indexspace = $4; $$ = (Node *)n; } | CHECK '(' a_expr ')' @@ -2085,7 +2111,7 @@ ConstraintElem: n->indexspace = $5; $$ = (Node *)n; } - | PRIMARY KEY '(' columnList ')' OptConsTableSpace + | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace { Constraint *n = makeNode(Constraint); n->contype = CONSTR_PRIMARY; @@ -2093,7 +2119,8 @@ ConstraintElem: n->raw_expr = NULL; n->cooked_expr = NULL; n->keys = $4; - n->indexspace = $6; + n->options = $6; + n->indexspace = $7; $$ = (Node *)n; } | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name @@ -2187,10 +2214,13 @@ OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; -OptWithOids: - WITH OIDS { $$ = MUST_HAVE_OIDS; } - | WITHOUT OIDS { $$ = MUST_NOT_HAVE_OIDS; } - | /*EMPTY*/ { $$ = DEFAULT_OIDS; } +OptWith: + WITH OIDS { $$ = list_make1(defWithOids(true)); } + | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); } + | WITH definition { $$ = $2; } + | WITH OIDS WITH definition { $$ = lappend($4, defWithOids(true)); } + | WITHOUT OIDS WITH definition { $$ = lappend($4, defWithOids(false)); } + | /*EMPTY*/ { $$ = NIL; } ; OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; } @@ -2215,7 +2245,7 @@ OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; } CreateAsStmt: CREATE OptTemp TABLE qualified_name OptCreateAs - OptWithOids OnCommitOption OptTableSpace AS SelectStmt + OptWith OnCommitOption OptTableSpace AS SelectStmt { /* * When the SelectStmt is a set-operation tree, we must @@ -2232,7 +2262,7 @@ CreateAsStmt: $4->istemp = $2; n->into = $4; n->intoColNames = $5; - n->intoHasOids = $6; + n->intoOptions = $6; n->intoOnCommit = $7; n->intoTableSpaceName = $8; $$ = $10; @@ -3630,7 +3660,7 @@ opt_granted_by: GRANTED BY RoleId { $$ = $3; } *****************************************************************************/ IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name - access_method_clause '(' index_params ')' OptTableSpace where_clause + access_method_clause '(' index_params ')' opt_definition OptTableSpace where_clause { IndexStmt *n = makeNode(IndexStmt); n->unique = $2; @@ -3638,8 +3668,9 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name n->relation = $6; n->accessMethod = $7; n->indexParams = $9; - n->tableSpace = $11; - n->whereClause = $12; + n->options = $11; + n->tableSpace = $12; + n->whereClause = $13; $$ = (Node *)n; } ; @@ -5264,7 +5295,7 @@ ExecuteStmt: EXECUTE name execute_param_clause $$ = (Node *) n; } | CREATE OptTemp TABLE qualified_name OptCreateAs - OptWithOids OnCommitOption OptTableSpace AS + OptWith OnCommitOption OptTableSpace AS EXECUTE name execute_param_clause { ExecuteStmt *n = makeNode(ExecuteStmt); @@ -5272,7 +5303,7 @@ ExecuteStmt: EXECUTE name execute_param_clause n->params = $12; $4->istemp = $2; n->into = $4; - n->into_contains_oids = $6; + n->intoOptions = $6; n->into_on_commit = $7; n->into_tbl_space = $8; if ($5) @@ -5606,7 +5637,6 @@ simple_select: n->targetList = $3; n->into = $4; n->intoColNames = NIL; - n->intoHasOids = DEFAULT_OIDS; n->fromClause = $5; n->whereClause = $6; n->groupClause = $7; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 9bdb91b474..a4fe1999fe 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.149 2006/03/16 00:31:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.150 2006/07/02 02:23:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/heapam.h" #include "catalog/heap.h" +#include "commands/defrem.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/tlist.h" @@ -33,6 +34,7 @@ #include "rewrite/rewriteManip.h" #include "utils/builtins.h" #include "utils/guc.h" +#include "utils/memutils.h" #define ORDER_CLAUSE 0 @@ -64,6 +66,8 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, Var *l_colvar, Var *r_colvar); static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause); +static bool OptionMatches(text *t, const char* kw, char **str, Size *len); +static Datum OptionToText(DefElem *def); /* @@ -212,29 +216,280 @@ interpretInhOption(InhOption inhOpt) } /* - * Given an enum that indicates whether WITH / WITHOUT OIDS was + * Given a List that indicates whether WITH / WITHOUT OIDS was * specified by the user, return true iff the specified table/result * set should be created with OIDs. This needs to be done after * parsing the query string because the return value can depend upon * the default_with_oids GUC var. */ bool -interpretOidsOption(ContainsOids opt) +interpretOidsOption(List *options) { - switch (opt) + ListCell *cell; + + foreach(cell, options) { - case MUST_HAVE_OIDS: - return true; + DefElem *def = (DefElem *) lfirst(cell); - case MUST_NOT_HAVE_OIDS: - return false; - - case DEFAULT_OIDS: - return default_with_oids; + if (pg_strcasecmp(def->defname, "oids") == 0) + return defGetBoolean(def); } - elog(ERROR, "bogus ContainsOids value: %d", opt); - return false; /* keep compiler quiet */ + /* oids option is not specified. */ + return default_with_oids; +} + +/* + * Test if t is start with 'kw='. + */ +static bool +OptionMatches(text *t, const char* kw, char **str, Size *len) +{ + char *text_str = (char *) VARATT_DATA(t); + int text_len = VARATT_SIZE(t) - VARHDRSZ; + Size kwlen = strlen(kw); + + if (text_len > kwlen && text_str[kwlen] == '=' && + pg_strncasecmp(text_str, kw, kwlen) == 0) + { + *str = text_str + kwlen + 1; + *len = text_len - kwlen - 1; + return true; + } + + return false; +} + +/* + * Flatten a DefElem to a text like as 'defname=arg'. + */ +static Datum +OptionToText(DefElem *def) +{ + text *t; + char *value = defGetString(def); + Size len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value); + + t = palloc(len + 1); + VARATT_SIZEP(t) = len; + sprintf((char *) VARATT_DATA(t), "%s=%s", def->defname, value); + + return PointerGetDatum(t); +} + +/* + * Merge option array and option list. + * + * array Existing option, or NULL if new option. + * list List of DefElems to be added to array. + */ +ArrayType * +OptionBuild(ArrayType *array, List *list) +{ + ListCell *cell; + bool *used; + int index; + int o; + ArrayType *result; + ArrayBuildState *astate; + MemoryContext myContext; + MemoryContext oldContext; + + if (list_length(list) == 0) + { + /* no additinal elements, so just clone. */ + if (array == NULL) + return NULL; + result = palloc(VARATT_SIZE(array)); + memcpy(result, array, VARATT_SIZE(array)); + return result; + } + + /* Make a temporary context to hold all the junk */ + myContext = AllocSetContextCreate(CurrentMemoryContext, + "OptionBuild", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldContext = MemoryContextSwitchTo(myContext); + + astate = NULL; + used = (bool *) palloc0(sizeof(bool) * list_length(list)); + + if (array) + { + Assert(ARR_ELEMTYPE(array) == TEXTOID); + Assert(ARR_NDIM(array) == 1); + Assert(ARR_LBOUND(array)[0] == 1); + + for (o = 1; o <= ARR_DIMS(array)[0]; o++) + { + bool isnull; + Datum datum; + + datum = array_ref(array, 1, &o, + -1 /* varlenarray */ , + -1 /* TEXT's typlen */ , + false /* TEXT's typbyval */ , + 'i' /* TEXT's typalign */ , + &isnull); + if (isnull) + continue; + + index = 0; + foreach(cell, list) + { + DefElem *def = lfirst(cell); + + /* + * We ignore 'oids' item because it is stored + * in pg_class.relhasoids. + */ + if (!used[index] && + pg_strcasecmp(def->defname, "oids") != 0) + { + char *value_str; + Size value_len; + if (OptionMatches(DatumGetTextP(datum), + def->defname, &value_str, &value_len)) + { + used[index] = true; + if (def->arg) + { + /* Replace an existing option. */ + datum = OptionToText(def); + goto next; /* skip remain items in list */ + } + else + { + /* Remove the option from array. */ + goto skip; + } + } + } + + index++; + } + + /* + * The datum is an existing parameter and is not modified. + * Fall down. + */ + +next: + astate = accumArrayResult(astate, datum, false, TEXTOID, myContext); +skip: + ; + } + } + + /* + * add options not in array + */ + index = 0; + foreach(cell, list) + { + DefElem *def = lfirst(cell); + + if (!used[index] && def->arg && + pg_strcasecmp(def->defname, "oids") != 0) + { + astate = accumArrayResult(astate, OptionToText(def), + false, TEXTOID, myContext); + } + + index++; + } + + if (astate) + result = DatumGetArrayTypeP(makeArrayResult(astate, oldContext)); + else + result = NULL; + + MemoryContextSwitchTo(oldContext); + MemoryContextDelete(myContext); + return result; +} + +/* + * Support routine to parse options. + * + * options List of DefElems + * num length of kwds + * kwds supported keywords + * strict Throw error if unsupported option is found. + * + * FIXME: memory is leaked in kwds[].arg. + */ +void +OptionParse(ArrayType *options, Size num, DefElem kwds[], bool strict) +{ + Size k; + int o; + + for (k = 0; k < num; k++) + { + Assert(kwds[k].defname); + kwds[k].arg = NULL; + } + + if (options == NULL) + return; /* use default for all */ + + Assert(ARR_ELEMTYPE(options) == TEXTOID); + Assert(ARR_NDIM(options) == 1); + Assert(ARR_LBOUND(options)[0] == 1); + + for (o = 1; o <= ARR_DIMS(options)[0]; o++) + { + bool isnull; + Datum datum; + + datum = array_ref(options, 1, &o, + -1 /* varlenarray */ , + -1 /* TEXT's typlen */ , + false /* TEXT's typbyval */ , + 'i' /* TEXT's typalign */ , + &isnull); + if (isnull) + continue; + + for (k = 0; k < num; k++) + { + char *value_str; + Size value_len; + + if (OptionMatches(DatumGetTextP(datum), + kwds[k].defname, &value_str, &value_len)) + { + char *value; + + if (kwds[k].arg != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("duplicated parameter %s", + kwds[k].defname))); + + /* copy value as Value node */ + value = (char *) palloc(value_len + 1); + strncpy(value, value_str, value_len); + value[value_len] = '\0'; + kwds[k].arg = (Node *) makeString(value); + goto next; /* skip remain keywords */ + } + } + + /* parameter is not in kwds */ + if (strict) + { + char *c = DatumGetCString(DirectFunctionCall1(textout, datum)); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unsupported parameter %s", c))); + } +next:; + } } /* diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 749b96cb45..23bc8537a1 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.258 2006/06/16 20:23:44 adunstan Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.259 2006/07/02 02:23:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -794,6 +794,7 @@ ProcessUtility(Node *parsetree, stmt->indexParams, /* parameters */ (Expr *) stmt->whereClause, stmt->rangetable, + stmt->options, stmt->unique, stmt->primary, stmt->isconstraint, diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 182d3cf107..2ddbb64763 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -2,7 +2,7 @@ * ruleutils.c - Functions to convert stored expressions/querytrees * back to source text * - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.224 2006/06/16 18:42:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.225 2006/07/02 02:23:21 momjian Exp $ **********************************************************************/ #include "postgres.h" @@ -187,6 +187,7 @@ static char *generate_relation_name(Oid relid); static char *generate_function_name(Oid funcid, int nargs, Oid *argtypes); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); static text *string_to_text(char *str); +static char *flatten_reloptions(Oid relid); #define only_marker(rte) ((rte)->inh ? "" : "ONLY ") @@ -756,9 +757,20 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) } if (!colno) - { appendStringInfoChar(&buf, ')'); + /* + * If it has options, append "WITH (options)" + */ + str = flatten_reloptions(indexrelid); + if (str) + { + appendStringInfo(&buf, " WITH (%s)", str); + pfree(str); + } + + if (!colno) + { /* * If it's a partial index, decompile and append the predicate */ @@ -1004,6 +1016,17 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand, decompile_column_index_array(val, conForm->conrelid, &buf); appendStringInfo(&buf, ")"); + + if (fullCommand && OidIsValid(conForm->conrelid)) + { + char *options = flatten_reloptions(conForm->conrelid); + if (options) + { + appendStringInfo(&buf, " WITH (%s)", options); + pfree(options); + } + } + break; } case CONSTRAINT_CHECK: @@ -4913,3 +4936,36 @@ string_to_text(char *str) return result; } + +static char * +flatten_reloptions(Oid relid) +{ + HeapTuple tuple; + char *result = NULL; + + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(relid), + 0, 0, 0); + if (tuple) + { + bool isnull; + Datum reloptions; + reloptions = SysCacheGetAttr(RELOID, tuple, + Anum_pg_class_reloptions, &isnull); + if (!isnull) + { + Datum sep, + txt; + sep = DirectFunctionCall1(textin, CStringGetDatum(", ")); + /* + * OID 395 = array_to_text. + * DirectFunctionCall2(array_to_text) is not available here. + */ + txt = OidFunctionCall2(395, reloptions, sep); + result = DatumGetCString(DirectFunctionCall1(textout, txt)); + } + ReleaseSysCache(tuple); + } + + return result; +} diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 82de42020e..50edf7691a 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.242 2006/06/16 18:42:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.243 2006/07/02 02:23:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -47,6 +47,8 @@ #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_type.h" +#include "catalog/heap.h" +#include "catalog/index.h" #include "commands/trigger.h" #include "miscadmin.h" #include "optimizer/clauses.h" @@ -54,6 +56,7 @@ #include "optimizer/prep.h" #include "storage/fd.h" #include "storage/smgr.h" +#include "utils/array.h" #include "utils/builtins.h" #include "utils/catcache.h" #include "utils/fmgroids.h" @@ -71,7 +74,7 @@ */ #define RELCACHE_INIT_FILENAME "pg_internal.init" -#define RELCACHE_INIT_FILEMAGIC 0x573262 /* version ID value */ +#define RELCACHE_INIT_FILEMAGIC 0x573263 /* version ID value */ /* * hardcoded tuple descriptors. see include/catalog/pg_attribute.h @@ -183,6 +186,7 @@ static void RelationClearRelation(Relation relation, bool rebuild); static void RelationReloadClassinfo(Relation relation); static void RelationFlushRelation(Relation relation); static bool load_relcache_init_file(void); +static void write_item(const void *data, Size len, FILE *fp); static void write_relcache_init_file(void); static void formrdesc(const char *relationName, Oid relationReltype, @@ -206,6 +210,7 @@ static void IndexSupportInitialize(oidvector *indclass, static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid, StrategyNumber numStrats, StrategyNumber numSupport); +static void RelationParseOptions(Relation relation, HeapTuple tuple); /* @@ -309,6 +314,7 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp) /* initialize relation tuple form */ relation->rd_rel = relationForm; + relation->rd_options = NULL; /* and allocate attribute tuple form storage */ relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts, @@ -321,6 +327,53 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp) return relation; } +/* + * RelationParseOptions + */ +static void +RelationParseOptions(Relation relation, HeapTuple tuple) +{ + ArrayType *options; + + Assert(tuple); + + switch (relation->rd_rel->relkind) + { + case RELKIND_RELATION: + case RELKIND_TOASTVALUE: + case RELKIND_UNCATALOGED: + case RELKIND_INDEX: + break; + default: + /* other relation should not have options. */ + relation->rd_options = NULL; + return; + } + + /* SysCacheGetAttr is not available here. */ + if (heap_attisnull(tuple, Anum_pg_class_reloptions)) + options = NULL; + else + options = (ArrayType *) ((Form_pg_class) GETSTRUCT(tuple))->reloptions; + + switch (relation->rd_rel->relkind) + { + case RELKIND_RELATION: + case RELKIND_TOASTVALUE: + case RELKIND_UNCATALOGED: + relation->rd_options = heap_option( + relation->rd_rel->relkind, options); + break; + case RELKIND_INDEX: + relation->rd_options = index_option( + relation->rd_am->amoption, options); + break; + default: + /* should not happen */ + break; + } +} + /* * RelationBuildTupleDesc * @@ -725,11 +778,6 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation) */ relation = AllocateRelationDesc(oldrelation, relp); - /* - * now we can free the memory allocated for pg_class_tuple - */ - heap_freetuple(pg_class_tuple); - /* * initialize the relation's relation id (relation->rd_id) */ @@ -785,6 +833,14 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation) /* make sure relation is marked as having no open file yet */ relation->rd_smgr = NULL; + /* Build AM-specific fields. */ + RelationParseOptions(relation, pg_class_tuple); + + /* + * now we can free the memory allocated for pg_class_tuple + */ + heap_freetuple(pg_class_tuple); + /* * Insert newly created relation into relcache hash tables. */ @@ -1210,6 +1266,7 @@ formrdesc(const char *relationName, Oid relationReltype, * data from pg_class and replace what we've done here. */ relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); + relation->rd_options = NULL; namestrcpy(&relation->rd_rel->relname, relationName); relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE; @@ -1297,6 +1354,11 @@ formrdesc(const char *relationName, Oid relationReltype, relation->rd_rel->relhasindex = true; } + /* + * initialize the rd_options field to default value + */ + relation->rd_options = heap_option(RELKIND_RELATION, NULL); + /* * add new reldesc to relcache */ @@ -1475,6 +1537,9 @@ RelationReloadClassinfo(Relation relation) RelationGetRelid(relation)); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE); + if (relation->rd_options) + pfree(relation->rd_options); + RelationParseOptions(relation, pg_class_tuple); heap_freetuple(pg_class_tuple); /* We must recalculate physical address in case it changed */ RelationInitPhysicalAddr(relation); @@ -1581,6 +1646,8 @@ RelationClearRelation(Relation relation, bool rebuild) pfree(relation->rd_am); if (relation->rd_rel) pfree(relation->rd_rel); + if (relation->rd_options) + pfree(relation->rd_options); list_free(relation->rd_indexlist); if (relation->rd_indexcxt) MemoryContextDelete(relation->rd_indexcxt); @@ -2111,6 +2178,7 @@ RelationBuildLocalRelation(const char *relname, * initialize relation tuple form (caller may add/override data later) */ rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); + rel->rd_options = NULL; namestrcpy(&rel->rd_rel->relname, relname); rel->rd_rel->relnamespace = relnamespace; @@ -3032,6 +3100,22 @@ load_relcache_init_file(void) has_not_null |= rel->rd_att->attrs[i]->attnotnull; } + /* next read the access method specific field */ + if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) + goto read_failed; + if (len > 0) + { + rel->rd_options = palloc(len); + if ((nread = fread(rel->rd_options, 1, len, fp)) != len) + goto read_failed; + if (len != VARATT_SIZE(rel->rd_options)) + goto read_failed; + } + else + { + rel->rd_options = NULL; + } + /* mark not-null status */ if (has_not_null) { @@ -3215,6 +3299,15 @@ read_failed: return false; } +static void +write_item(const void *data, Size len, FILE *fp) +{ + if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) + elog(FATAL, "could not write init file"); + if (fwrite(data, 1, len, fp) != len) + elog(FATAL, "could not write init file"); +} + /* * Write out a new initialization file with the current contents * of the relcache. @@ -3277,39 +3370,24 @@ write_relcache_init_file(void) { Relation rel = idhentry->reldesc; Form_pg_class relform = rel->rd_rel; - Size len; - /* - * first write the relcache entry proper - */ - len = sizeof(RelationData); - - /* first, write the relation descriptor length */ - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - - /* next, write out the Relation structure */ - if (fwrite(rel, 1, len, fp) != len) - elog(FATAL, "could not write init file"); + /* first write the relcache entry proper */ + write_item(rel, sizeof(RelationData), fp); /* next write the relation tuple form */ - len = sizeof(FormData_pg_class); - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - - if (fwrite(relform, 1, len, fp) != len) - elog(FATAL, "could not write init file"); + write_item(relform, CLASS_TUPLE_SIZE, fp); /* next, do all the attribute tuple form data entries */ for (i = 0; i < relform->relnatts; i++) { - len = ATTRIBUTE_TUPLE_SIZE; - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - if (fwrite(rel->rd_att->attrs[i], 1, len, fp) != len) - elog(FATAL, "could not write init file"); + write_item(rel->rd_att->attrs[i], + ATTRIBUTE_TUPLE_SIZE, fp); } + /* next, do the access method specific field */ + write_item(rel->rd_options, + (rel->rd_options ? VARATT_SIZE(rel->rd_options) : 0), fp); + /* If it's an index, there's more to do */ if (rel->rd_rel->relkind == RELKIND_INDEX) { @@ -3317,36 +3395,19 @@ write_relcache_init_file(void) /* write the pg_index tuple */ /* we assume this was created by heap_copytuple! */ - len = HEAPTUPLESIZE + rel->rd_indextuple->t_len; - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - - if (fwrite(rel->rd_indextuple, 1, len, fp) != len) - elog(FATAL, "could not write init file"); + write_item(rel->rd_indextuple, + HEAPTUPLESIZE + rel->rd_indextuple->t_len, fp); /* next, write the access method tuple form */ - len = sizeof(FormData_pg_am); - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - - if (fwrite(am, 1, len, fp) != len) - elog(FATAL, "could not write init file"); + write_item(am, sizeof(FormData_pg_am), fp); /* next, write the vector of operator OIDs */ - len = relform->relnatts * (am->amstrategies * sizeof(Oid)); - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - - if (fwrite(rel->rd_operator, 1, len, fp) != len) - elog(FATAL, "could not write init file"); + write_item(rel->rd_operator, relform->relnatts * + (am->amstrategies * sizeof(Oid)), fp); /* finally, write the vector of support procedures */ - len = relform->relnatts * (am->amsupport * sizeof(RegProcedure)); - if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len)) - elog(FATAL, "could not write init file"); - - if (fwrite(rel->rd_support, 1, len, fp) != len) - elog(FATAL, "could not write init file"); + write_item(rel->rd_support, relform->relnatts * + (am->amsupport * sizeof(RegProcedure)), fp); } /* also make a list of their OIDs, for RelationIdIsInInitFile */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 4f76eae146..6afa917f6b 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.438 2006/06/09 19:46:09 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.439 2006/07/02 02:23:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -2594,6 +2594,7 @@ getTables(int *numTables) int i_owning_tab; int i_owning_col; int i_reltablespace; + int i_reloptions; /* Make sure we are in proper schema */ selectSourceSchema("pg_catalog"); @@ -2618,7 +2619,7 @@ getTables(int *numTables) * we cannot correctly identify inherited columns, serial columns, etc. */ - if (g_fout->remoteVersion >= 80000) + if (g_fout->remoteVersion >= 80200) { /* * Left join to pick up dependency info linking sequences to their @@ -2632,7 +2633,37 @@ getTables(int *numTables) "relhasindex, relhasrules, relhasoids, " "d.refobjid as owning_tab, " "d.refobjsubid as owning_col, " - "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "array_to_string(c.reloptions, ', ') as reloptions " + "from pg_class c " + "left join pg_depend d on " + "(c.relkind = '%c' and " + "d.classid = c.tableoid and d.objid = c.oid and " + "d.objsubid = 0 and " + "d.refclassid = c.tableoid and d.deptype = 'i') " + "where relkind in ('%c', '%c', '%c', '%c') " + "order by c.oid", + username_subquery, + RELKIND_SEQUENCE, + RELKIND_RELATION, RELKIND_SEQUENCE, + RELKIND_VIEW, RELKIND_COMPOSITE_TYPE); + } + else if (g_fout->remoteVersion >= 80000) + { + /* + * Left join to pick up dependency info linking sequences to their + * serial column, if any + */ + appendPQExpBuffer(query, + "SELECT c.tableoid, c.oid, relname, " + "relacl, relkind, relnamespace, " + "(%s relowner) as rolname, " + "relchecks, reltriggers, " + "relhasindex, relhasrules, relhasoids, " + "d.refobjid as owning_tab, " + "d.refobjsubid as owning_col, " + "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, " + "NULL as reloptions " "from pg_class c " "left join pg_depend d on " "(c.relkind = '%c' and " @@ -2660,7 +2691,8 @@ getTables(int *numTables) "relhasindex, relhasrules, relhasoids, " "d.refobjid as owning_tab, " "d.refobjsubid as owning_col, " - "NULL as reltablespace " + "NULL as reltablespace, " + "NULL as reloptions " "from pg_class c " "left join pg_depend d on " "(c.relkind = '%c' and " @@ -2684,7 +2716,8 @@ getTables(int *numTables) "relhasindex, relhasrules, relhasoids, " "NULL::oid as owning_tab, " "NULL::int4 as owning_col, " - "NULL as reltablespace " + "NULL as reltablespace, " + "NULL as reloptions " "from pg_class " "where relkind in ('%c', '%c', '%c') " "order by oid", @@ -2703,7 +2736,8 @@ getTables(int *numTables) "'t'::bool as relhasoids, " "NULL::oid as owning_tab, " "NULL::int4 as owning_col, " - "NULL as reltablespace " + "NULL as reltablespace, " + "NULL as reloptions " "from pg_class " "where relkind in ('%c', '%c', '%c') " "order by oid", @@ -2732,7 +2766,8 @@ getTables(int *numTables) "'t'::bool as relhasoids, " "NULL::oid as owning_tab, " "NULL::int4 as owning_col, " - "NULL as reltablespace " + "NULL as reltablespace, " + "NULL as reloptions " "from pg_class c " "where relkind in ('%c', '%c') " "order by oid", @@ -2774,6 +2809,7 @@ getTables(int *numTables) i_owning_tab = PQfnumber(res, "owning_tab"); i_owning_col = PQfnumber(res, "owning_col"); i_reltablespace = PQfnumber(res, "reltablespace"); + i_reloptions = PQfnumber(res, "reloptions"); for (i = 0; i < ntups; i++) { @@ -2803,6 +2839,7 @@ getTables(int *numTables) tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col)); } tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace)); + tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions)); /* other fields were zeroed above */ @@ -2952,7 +2989,8 @@ getIndexes(TableInfo tblinfo[], int numTables) i_conname, i_contableoid, i_conoid, - i_tablespace; + i_tablespace, + i_options; int ntups; for (i = 0; i < numTables; i++) @@ -2981,7 +3019,7 @@ getIndexes(TableInfo tblinfo[], int numTables) * assume an index won't have more than one internal dependency. */ resetPQExpBuffer(query); - if (g_fout->remoteVersion >= 80000) + if (g_fout->remoteVersion >= 80200) { appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, " @@ -2992,7 +3030,34 @@ getIndexes(TableInfo tblinfo[], int numTables) "c.contype, c.conname, " "c.tableoid as contableoid, " "c.oid as conoid, " - "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace " + "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace, " + "array_to_string(t.reloptions, ', ') as options " + "FROM pg_catalog.pg_index i " + "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " + "LEFT JOIN pg_catalog.pg_depend d " + "ON (d.classid = t.tableoid " + "AND d.objid = t.oid " + "AND d.deptype = 'i') " + "LEFT JOIN pg_catalog.pg_constraint c " + "ON (d.refclassid = c.tableoid " + "AND d.refobjid = c.oid) " + "WHERE i.indrelid = '%u'::pg_catalog.oid " + "ORDER BY indexname", + tbinfo->dobj.catId.oid); + } + else if (g_fout->remoteVersion >= 80000) + { + appendPQExpBuffer(query, + "SELECT t.tableoid, t.oid, " + "t.relname as indexname, " + "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, " + "t.relnatts as indnkeys, " + "i.indkey, i.indisclustered, " + "c.contype, c.conname, " + "c.tableoid as contableoid, " + "c.oid as conoid, " + "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) as tablespace, " + "null as options " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "LEFT JOIN pg_catalog.pg_depend d " @@ -3017,7 +3082,8 @@ getIndexes(TableInfo tblinfo[], int numTables) "c.contype, c.conname, " "c.tableoid as contableoid, " "c.oid as conoid, " - "NULL as tablespace " + "NULL as tablespace, " + "null as options " "FROM pg_catalog.pg_index i " "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) " "LEFT JOIN pg_catalog.pg_depend d " @@ -3044,7 +3110,8 @@ getIndexes(TableInfo tblinfo[], int numTables) "t.relname as conname, " "0::oid as contableoid, " "t.oid as conoid, " - "NULL as tablespace " + "NULL as tablespace, " + "null as options " "FROM pg_index i, pg_class t " "WHERE t.oid = i.indexrelid " "AND i.indrelid = '%u'::oid " @@ -3066,7 +3133,8 @@ getIndexes(TableInfo tblinfo[], int numTables) "t.relname as conname, " "0::oid as contableoid, " "t.oid as conoid, " - "NULL as tablespace " + "NULL as tablespace, " + "null as options " "FROM pg_index i, pg_class t " "WHERE t.oid = i.indexrelid " "AND i.indrelid = '%u'::oid " @@ -3091,6 +3159,7 @@ getIndexes(TableInfo tblinfo[], int numTables) i_contableoid = PQfnumber(res, "contableoid"); i_conoid = PQfnumber(res, "conoid"); i_tablespace = PQfnumber(res, "tablespace"); + i_options = PQfnumber(res, "options"); indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo)); constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo)); @@ -3109,6 +3178,7 @@ getIndexes(TableInfo tblinfo[], int numTables) indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef)); indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys)); indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace)); + indxinfo[j].options = strdup(PQgetvalue(res, j, i_options)); /* * In pre-7.4 releases, indkeys may contain more entries than @@ -7245,6 +7315,9 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) appendPQExpBuffer(q, ")"); } + if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) + appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions); + appendPQExpBuffer(q, ";\n"); /* Loop dumping statistics and storage statements */ @@ -7542,7 +7615,12 @@ dumpConstraint(Archive *fout, ConstraintInfo *coninfo) fmtId(attname)); } - appendPQExpBuffer(q, ");\n"); + appendPQExpBuffer(q, ")"); + + if (indxinfo->options && strlen(indxinfo->options) > 0) + appendPQExpBuffer(q, " WITH (%s)", indxinfo->options); + + appendPQExpBuffer(q, ";\n"); /* If the index is clustered, we need to record that. */ if (indxinfo->indisclustered) diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 66e7e7798b..33b0fbf058 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.125 2006/03/05 15:58:51 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.126 2006/07/02 02:23:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -180,6 +180,7 @@ typedef struct _tableInfo char *relacl; char relkind; char *reltablespace; /* relation tablespace */ + char *reloptions; /* options specified by WITH (...) */ bool hasindex; /* does it have any indexes? */ bool hasrules; /* does it have any rules? */ bool hasoids; /* does it have OIDs? */ @@ -247,6 +248,7 @@ typedef struct _indxInfo TableInfo *indextable; /* link to table the index is for */ char *indexdef; char *tablespace; /* tablespace in which index is stored */ + char *options; /* options specified by WITH (...) */ int indnkeys; Oid *indkeys; bool indisclustered; diff --git a/src/include/access/genam.h b/src/include/access/genam.h index c1859a0c6d..c7ebae9931 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -7,13 +7,14 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.60 2006/05/10 23:18:39 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.61 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ #ifndef GENAM_H #define GENAM_H +#include "access/heapam.h" #include "access/itup.h" #include "access/relscan.h" #include "access/sdir.h" @@ -144,4 +145,13 @@ extern SysScanDesc systable_beginscan(Relation heapRelation, extern HeapTuple systable_getnext(SysScanDesc sysscan); extern void systable_endscan(SysScanDesc sysscan); + +typedef HeapOption IndexOption; + +extern bytea *genam_option(ArrayType *options, + int minFillfactor, int defaultFillfactor); + +#define IndexGetFillFactor(relation) HeapGetFillFactor(relation) +#define IndexGetPageFreeSpace(relation) HeapGetPageFreeSpace(relation) + #endif /* GENAM_H */ diff --git a/src/include/access/gin.h b/src/include/access/gin.h index 8fff7f4232..4749eca192 100644 --- a/src/include/access/gin.h +++ b/src/include/access/gin.h @@ -3,7 +3,7 @@ * header file for postgres inverted index access method implementation. * * Copyright (c) 2006, PostgreSQL Global Development Group - * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.1 2006/05/02 11:28:55 teodor Exp $ + * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.2 2006/07/02 02:23:22 momjian Exp $ *-------------------------------------------------------------------------- */ @@ -213,6 +213,7 @@ typedef struct ginxlogDeletePage { } ginxlogDeletePage; /* ginutil.c */ +extern Datum ginoption(PG_FUNCTION_ARGS); extern void initGinState( GinState *state, Relation index ); extern Buffer GinNewBuffer(Relation index); extern void GinInitBuffer(Buffer b, uint32 f); diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 7a55a31216..5be99712b0 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.18 2006/06/28 12:00:14 teodor Exp $ + * $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.19 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -202,6 +202,7 @@ typedef struct Relation r; IndexTuple *itup; /* in/out, points to compressed entry */ int ituplen; /* length of itup */ + Size freespace; /* free space to be left */ GISTInsertStack *stack; bool needInsertComplete; @@ -271,8 +272,9 @@ extern Datum gistgetmulti(PG_FUNCTION_ARGS); #define GiSTPageSize \ ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) ) +extern Datum gistoption(PG_FUNCTION_ARGS); extern bool gistfitpage(IndexTuple *itvec, int len); -extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete); +extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace); extern void gistcheckpage(Relation rel, Buffer buf); extern Buffer gistNewBuffer(Relation r); extern OffsetNumber gistfillbuffer(Relation r, Page page, IndexTuple *itup, diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 226b164ac8..59cf5c9961 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.69 2006/05/02 22:25:10 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.70 2006/07/02 02:23:22 momjian Exp $ * * NOTES * modeled after Margo Seltzer's hash implementation for unix. @@ -234,6 +234,7 @@ extern Datum hashmarkpos(PG_FUNCTION_ARGS); extern Datum hashrestrpos(PG_FUNCTION_ARGS); extern Datum hashbulkdelete(PG_FUNCTION_ARGS); extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS); +extern Datum hashoption(PG_FUNCTION_ARGS); /* * Datatype-specific hash functions in hashfunc.c. diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 7301be4ae3..085501be7d 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.112 2006/06/27 02:51:39 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.113 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,7 @@ #include "nodes/primnodes.h" #include "storage/block.h" #include "storage/lmgr.h" +#include "utils/array.h" #include "utils/rel.h" #include "utils/tqual.h" @@ -227,4 +228,32 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup); extern HeapTuple heap_addheader(int natts, bool withoid, Size structlen, void *structure); +extern HeapTuple build_class_tuple(Form_pg_class pgclass, ArrayType *options); + +/* + * HeapOption + * Internal data of heaps. + */ +typedef struct HeapOption +{ + int32 vl_len; + int fillfactor; +} HeapOption; + +extern bytea *heap_option(char relkind, ArrayType *options); + +/* + * HeapGetFillFactor + * Returns the heap's fillfactor. + */ +#define HeapGetFillFactor(relation) \ + (((HeapOption*)(relation)->rd_options)->fillfactor) + +/* + * HeapGetPageFreeSpace + * Returns the heap's freespace per page in bytes. + */ +#define HeapGetPageFreeSpace(relation) \ + (BLCKSZ * (100 - HeapGetFillFactor(relation)) / 100) + #endif /* HEAPAM_H */ diff --git a/src/include/access/hio.h b/src/include/access/hio.h index a18d6934d5..ab03fd4a64 100644 --- a/src/include/access/hio.h +++ b/src/include/access/hio.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/hio.h,v 1.30 2006/03/05 15:58:53 momjian Exp $ + * $PostgreSQL: pgsql/src/include/access/hio.h,v 1.31 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,6 @@ extern void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple); extern Buffer RelationGetBufferForTuple(Relation relation, Size len, - Buffer otherBuffer, bool use_fsm); + Buffer otherBuffer, bool use_fsm); #endif /* HIO_H */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index a58048ace9..e5981d092c 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.98 2006/05/08 00:00:10 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.99 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -453,6 +453,7 @@ extern Datum btmarkpos(PG_FUNCTION_ARGS); extern Datum btrestrpos(PG_FUNCTION_ARGS); extern Datum btbulkdelete(PG_FUNCTION_ARGS); extern Datum btvacuumcleanup(PG_FUNCTION_ARGS); +extern Datum btoption(PG_FUNCTION_ARGS); /* * prototypes for functions in nbtinsert.c diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 06f0a125bf..10e71559bc 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.334 2006/05/24 11:01:39 teodor Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.335 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200605241 +#define CATALOG_VERSION_NO 200607011 #endif diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 9edcdb21fb..23604ec2ee 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.82 2006/06/27 18:35:05 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.83 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "catalog/pg_attribute.h" #include "nodes/parsenodes.h" #include "parser/parse_node.h" +#include "utils/array.h" #include "utils/rel.h" @@ -54,7 +55,8 @@ extern Oid heap_create_with_catalog(const char *relname, bool oidislocal, int oidinhcount, OnCommitAction oncommit, - bool allow_system_table_mods); + bool allow_system_table_mods, + ArrayType *options); extern void heap_drop_with_catalog(Oid relid); diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 6819426d49..f4b1bc9830 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.66 2006/05/10 23:18:39 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.67 2006/07/02 02:23:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/itup.h" #include "catalog/pg_index.h" #include "nodes/execnodes.h" +#include "utils/array.h" #define DEFAULT_INDEX_TYPE "btree" @@ -37,6 +38,7 @@ extern Oid index_create(Oid heapRelationId, Oid accessMethodObjectId, Oid tableSpaceId, Oid *classObjectId, + List *options, bool isprimary, bool istoast, bool isconstraint, @@ -70,4 +72,6 @@ extern double IndexBuildHeapScan(Relation heapRelation, extern void reindex_index(Oid indexId); extern bool reindex_relation(Oid relid, bool toast_too); +extern bytea *index_option(RegProcedure amoption, ArrayType *options); + #endif /* INDEX_H */ diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index 141b42e02d..5e0d1cf4b6 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.43 2006/05/24 11:01:39 teodor Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.44 2006/07/02 02:23:22 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -65,6 +65,7 @@ CATALOG(pg_am,2601) regproc ambulkdelete; /* bulk-delete function */ regproc amvacuumcleanup; /* post-VACUUM cleanup function */ regproc amcostestimate; /* estimate cost of an indexscan */ + regproc amoption; /* parse AM-specific parameters */ } FormData_pg_am; /* ---------------- @@ -78,7 +79,7 @@ typedef FormData_pg_am *Form_pg_am; * compiler constants for pg_am * ---------------- */ -#define Natts_pg_am 23 +#define Natts_pg_am 24 #define Anum_pg_am_amname 1 #define Anum_pg_am_amstrategies 2 #define Anum_pg_am_amsupport 3 @@ -102,22 +103,23 @@ typedef FormData_pg_am *Form_pg_am; #define Anum_pg_am_ambulkdelete 21 #define Anum_pg_am_amvacuumcleanup 22 #define Anum_pg_am_amcostestimate 23 +#define Anum_pg_am_amoption 24 /* ---------------- * initial contents of pg_am * ---------------- */ -DATA(insert OID = 403 ( btree 5 1 1 t t t t f t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate )); +DATA(insert OID = 403 ( btree 5 1 1 t t t t f t t btinsert btbeginscan btgettuple btgetmulti btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoption )); DESCR("b-tree index access method"); #define BTREE_AM_OID 403 -DATA(insert OID = 405 ( hash 1 1 0 f f f f f t f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate )); +DATA(insert OID = 405 ( hash 1 1 0 f f f f f t f hashinsert hashbeginscan hashgettuple hashgetmulti hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoption )); DESCR("hash index access method"); #define HASH_AM_OID 405 -DATA(insert OID = 783 ( gist 100 7 0 f t t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate )); +DATA(insert OID = 783 ( gist 100 7 0 f t t t t t t gistinsert gistbeginscan gistgettuple gistgetmulti gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoption )); DESCR("GiST index access method"); #define GIST_AM_OID 783 -DATA(insert OID = 2742 ( gin 100 4 0 f f f f t t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate )); +DATA(insert OID = 2742 ( gin 100 4 0 f f f f t t f gininsert ginbeginscan gingettuple gingetmulti ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoption )); DESCR("GIN index access method"); #define GIN_AM_OID 2742 diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 327e9544d7..c0be03ac4d 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.120 2006/03/05 15:58:54 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.121 2006/07/02 02:23:22 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -404,7 +404,8 @@ DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); { 1259, {"relhaspkey"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relhasrules"}, 16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relhassubclass"},16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ -{ 1259, {"relacl"}, 1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } +{ 1259, {"reloptions"}, 1009, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 1259, {"relacl"}, 1034, -1, -1, 26, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); @@ -430,7 +431,8 @@ DATA(insert ( 1259 relhasoids 16 -1 1 21 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhaspkey 16 -1 1 22 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhasrules 16 -1 1 23 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhassubclass 16 -1 1 24 0 -1 -1 t p c t f f t 0)); -DATA(insert ( 1259 relacl 1034 -1 -1 25 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1259 reloptions 1009 -1 -1 25 1 -1 -1 f x i f f f t 0)); +DATA(insert ( 1259 relacl 1034 -1 -1 26 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index a059ae9ddc..32b3406aa8 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.92 2006/05/28 02:27:08 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.93 2006/07/02 02:23:22 momjian Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -75,9 +75,8 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP bool relhasrules; /* has associated rules */ bool relhassubclass; /* has derived classes */ - /* - * relacl may or may not be present, see note above! - */ + /* following fields may or may not be present, see note above! */ + text reloptions[1]; /* access method specific data */ aclitem relacl[1]; /* we declare this just for the catalog */ } FormData_pg_class; @@ -104,7 +103,7 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ #define Natts_pg_class_fixed 24 -#define Natts_pg_class 25 +#define Natts_pg_class 26 #define Anum_pg_class_relname 1 #define Anum_pg_class_relnamespace 2 #define Anum_pg_class_reltype 3 @@ -129,7 +128,8 @@ typedef FormData_pg_class *Form_pg_class; #define Anum_pg_class_relhaspkey 22 #define Anum_pg_class_relhasrules 23 #define Anum_pg_class_relhassubclass 24 -#define Anum_pg_class_relacl 25 +#define Anum_pg_class_reloptions 25 +#define Anum_pg_class_relacl 26 /* ---------------- * initial contents of pg_class @@ -139,13 +139,13 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ -DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ )); +DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ _null_ )); DESCR(""); -DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f _null_ )); +DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f _null_ _null_ )); DESCR(""); -DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 18 0 0 0 0 0 t f f f _null_ )); +DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 18 0 0 0 0 0 t f f f _null_ _null_ )); DESCR(""); -DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f _null_ )); +DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 26 0 0 0 0 0 t f f f _null_ _null_ )); DESCR(""); #define RELKIND_INDEX 'i' /* secondary index */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index e0aa6ec3f3..aba5eee5fe 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.413 2006/06/06 17:59:57 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.414 2006/07/02 02:23:22 momjian Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -680,6 +680,8 @@ DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 DESCR("btree(internal)"); DATA(insert OID = 1268 ( btcostestimate PGNSP PGUID 12 f f t f v 8 2278 "2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ btcostestimate - _null_ )); DESCR("btree(internal)"); +DATA(insert OID = 2785 ( btoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ btoption - _null_ )); +DESCR("btree(internal)"); DATA(insert OID = 339 ( poly_same PGNSP PGUID 12 f f t f i 2 16 "604 604" _null_ _null_ _null_ poly_same - _null_ )); DESCR("same as?"); @@ -797,6 +799,8 @@ DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 DESCR("hash(internal)"); DATA(insert OID = 438 ( hashcostestimate PGNSP PGUID 12 f f t f v 8 2278 "2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ hashcostestimate - _null_ )); DESCR("hash(internal)"); +DATA(insert OID = 2786 ( hashoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ hashoption - _null_ )); +DESCR("hash(internal)"); DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 f f t f i 1 23 "21" _null_ _null_ _null_ hashint2 - _null_ )); DESCR("hash"); @@ -1063,6 +1067,8 @@ DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2 DESCR("gist(internal)"); DATA(insert OID = 772 ( gistcostestimate PGNSP PGUID 12 f f t f v 8 2278 "2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gistcostestimate - _null_ )); DESCR("gist(internal)"); +DATA(insert OID = 2787 ( gistoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ gistoption - _null_ )); +DESCR("gist(internal)"); DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 f f t f i 2 16 "704 704" _null_ _null_ _null_ tintervaleq - _null_ )); DESCR("equal"); @@ -3849,6 +3855,8 @@ DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281 DESCR("gin(internal)"); DATA(insert OID = 2741 ( gincostestimate PGNSP PGUID 12 f f t f v 8 2278 "2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ gincostestimate - _null_ )); DESCR("gin(internal)"); +DATA(insert OID = 2788 ( ginoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ ginoption - _null_ )); +DESCR("gin(internal)"); /* GIN array support */ DATA(insert OID = 2743 ( ginarrayextract PGNSP PGUID 12 f f t f i 2 2281 "2277 2281" _null_ _null_ _null_ ginarrayextract - _null_ )); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index f6ed06f3db..e0678db4cf 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.72 2006/04/15 17:45:41 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.73 2006/07/02 02:23:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -26,6 +26,7 @@ extern void DefineIndex(RangeVar *heapRelation, List *attributeList, Expr *predicate, List *rangetable, + List *options, bool unique, bool primary, bool isconstraint, @@ -95,4 +96,6 @@ extern List *defGetQualifiedName(DefElem *def); extern TypeName *defGetTypeName(DefElem *def); extern int defGetTypeLength(DefElem *def); +extern DefElem *defWithOids(bool value); + #endif /* DEFREM_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f9c1524bc9..6cda429d3e 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.313 2006/07/02 01:58:36 momjian Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.314 2006/07/02 02:23:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -93,6 +93,7 @@ typedef struct Query RangeVar *into; /* target relation for SELECT INTO */ bool intoHasOids; /* should target relation contain OIDs? */ + List *intoOptions; /* options passed by WITH */ OnCommitAction intoOnCommit; /* what do we do at COMMIT? */ char *intoTableSpaceName; /* table space to use, or NULL */ @@ -693,15 +694,6 @@ typedef enum SetOperation SETOP_EXCEPT } SetOperation; -typedef enum ContainsOids -{ - MUST_HAVE_OIDS, /* WITH OIDS explicitly specified */ - MUST_NOT_HAVE_OIDS, /* WITHOUT OIDS explicitly specified */ - DEFAULT_OIDS /* neither specified; use the default, which - * is the value of the default_with_oids GUC - * var */ -} ContainsOids; - typedef struct SelectStmt { NodeTag type; @@ -709,14 +701,14 @@ typedef struct SelectStmt /* * These fields are used only in "leaf" SelectStmts. * - * into, intoColNames, intoHasOids, intoOnCommit, and + * into, intoColNames, intoOptions, intoOnCommit, and * intoTableSpaceName are a kluge; they belong somewhere else... */ List *distinctClause; /* NULL, list of DISTINCT ON exprs, or * lcons(NIL,NIL) for all (SELECT DISTINCT) */ RangeVar *into; /* target table (for select into table) */ List *intoColNames; /* column names for into table */ - ContainsOids intoHasOids; /* should target table have OIDs? */ + List *intoOptions; /* options passed by WITH */ OnCommitAction intoOnCommit; /* what do we do at COMMIT? */ char *intoTableSpaceName; /* table space to use, or NULL */ List *targetList; /* the target list (of ResTarget) */ @@ -869,6 +861,7 @@ typedef enum AlterTableType AT_DropCluster, /* SET WITHOUT CLUSTER */ AT_DropOids, /* SET WITHOUT OIDS */ AT_SetTableSpace, /* SET TABLESPACE */ + AT_SetOptions, /* SET (...) -- AM specific parameters */ AT_EnableTrig, /* ENABLE TRIGGER name */ AT_DisableTrig, /* DISABLE TRIGGER name */ AT_EnableTrigAll, /* ENABLE TRIGGER ALL */ @@ -1024,7 +1017,7 @@ typedef struct CreateStmt List *inhRelations; /* relations to inherit from (list of * inhRelation) */ List *constraints; /* constraints (list of Constraint nodes) */ - ContainsOids hasoids; /* should it have OIDs? */ + List *options; /* options passed by WITH */ OnCommitAction oncommit; /* what do we do at COMMIT? */ char *tablespacename; /* table space to use, or NULL */ } CreateStmt; @@ -1082,6 +1075,7 @@ typedef struct Constraint Node *raw_expr; /* expr, as untransformed parse tree */ char *cooked_expr; /* expr, as nodeToString representation */ List *keys; /* String nodes naming referenced column(s) */ + List *options; /* options passed by WITH */ char *indexspace; /* index tablespace for PKEY/UNIQUE * constraints; NULL for default */ } Constraint; @@ -1435,6 +1429,7 @@ typedef struct IndexStmt char *accessMethod; /* name of access method (eg. btree) */ char *tableSpace; /* tablespace, or NULL to use parent's */ List *indexParams; /* a list of IndexElem */ + List *options; /* options passed by WITH */ Node *whereClause; /* qualification (partial-index predicate) */ List *rangetable; /* range table for qual and/or expressions, * filled in by transformStmt() */ @@ -1891,8 +1886,8 @@ typedef struct ExecuteStmt NodeTag type; char *name; /* The name of the plan to execute */ RangeVar *into; /* Optional table to store results in */ - ContainsOids into_contains_oids; /* Should it have OIDs? */ bool into_has_oids; /* Merge GUC info with user input */ + List *intoOptions; /* options passed by WITH */ OnCommitAction into_on_commit; /* What do we do at COMMIT? */ char *into_tbl_space; /* Tablespace to use, or NULL */ List *params; /* Values to assign to parameters */ diff --git a/src/include/parser/parse_clause.h b/src/include/parser/parse_clause.h index efe5a8aba6..dc04bcb0bb 100644 --- a/src/include/parser/parse_clause.h +++ b/src/include/parser/parse_clause.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.44 2006/03/05 15:58:57 momjian Exp $ + * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.45 2006/07/02 02:23:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -15,12 +15,17 @@ #define PARSE_CLAUSE_H #include "parser/parse_node.h" +#include "utils/array.h" extern void transformFromClause(ParseState *pstate, List *frmList); extern int setTargetTable(ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms); extern bool interpretInhOption(InhOption inhOpt); -extern bool interpretOidsOption(ContainsOids opt); +extern bool interpretOidsOption(List *options); + +extern ArrayType *OptionBuild(ArrayType *array, List *list); +extern void OptionParse(ArrayType *options, Size num, DefElem kwds[], + bool strict); extern Node *transformWhereClause(ParseState *pstate, Node *clause, const char *constructName); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 015d7ddc9e..9d2e4a8bee 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.89 2006/04/25 22:46:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.90 2006/07/02 02:23:23 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -115,6 +115,7 @@ typedef struct RelationAmInfo FmgrInfo ambulkdelete; FmgrInfo amvacuumcleanup; FmgrInfo amcostestimate; + FmgrInfo amoption; } RelationAmInfo; @@ -142,8 +143,14 @@ typedef struct RelationData * survived into; or zero if the rel was not created in the current top * transaction. This should be relied on only for optimization purposes; * it is possible for new-ness to be "forgotten" (eg, after CLUSTER). + * + * rd_options and rd_amcache are alike, but different in terms of + * lifetime. Invalidation of rd_options is at the change of pg_class + * and of rd_amcache is at the change of AM's metapages. Also, rd_options + * is serialized in the relcache init file, but rd_amcache is not. */ Form_pg_class rd_rel; /* RELATION tuple */ + bytea *rd_options; /* parsed rd_rel->reloptions */ TupleDesc rd_att; /* tuple descriptor */ Oid rd_id; /* relation's object id */ List *rd_indexlist; /* list of OIDs of indexes on relation */