<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.8 2006/02/12 19:11:00 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_index.sgml,v 1.9 2006/07/02 02:23:17 momjian Exp $
PostgreSQL documentation
-->
<synopsis>
ALTER INDEX <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable class="PARAMETER">new_name</replaceable>
ALTER INDEX <replaceable class="PARAMETER">name</replaceable> SET TABLESPACE <replaceable class="PARAMETER">tablespace_name</replaceable>
+ALTER INDEX <replaceable class="PARAMETER">name</replaceable> SET (FILLFACTOR = <replaceable class="PARAMETER">fillfactor</replaceable>)
+ALTER INDEX <replaceable class="PARAMETER">name</replaceable> RESET (FILLFACTOR)
</synopsis>
</refsynopsisdiv>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>SET (FILLFACTOR)</literal></term>
+ <listitem>
+ <para>
+ This form changes the index's fillfactor to the specified percentage.
+ Index structure is not modified immediately; use <literal>REINDEX</literal>
+ to ensure reflection of the change.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>RESET (FILLFACTOR)</literal></term>
+ <listitem>
+ <para>
+ This form changes the index's fillfactor to the default value.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.85 2006/07/02 01:58:36 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.86 2006/07/02 02:23:17 momjian Exp $
PostgreSQL documentation
-->
CLUSTER ON <replaceable class="PARAMETER">index_name</replaceable>
SET WITHOUT CLUSTER
SET WITHOUT OIDS
+ SET (FILLFACTOR = <replaceable class="PARAMETER">fillfactor</replaceable>)
+ RESET (FILLFACTOR)
INHERIT <replaceable class="PARAMETER">parent_table</replaceable>
NO INHERIT <replaceable class="PARAMETER">parent_table</replaceable>
OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>SET (FILLFACTOR)</literal></term>
+ <listitem>
+ <para>
+ This form changes the table's fillfactor to the specified percentage.
+ Table structure is not modified immediately; use <literal>CLUSTER</literal>
+ to ensure reflection of the change.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>RESET</literal></term>
+ <listitem>
+ <para>
+ This form changes the table's fillfactor to the default value.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>RENAME</literal></term>
<listitem>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.52 2005/11/07 17:36:44 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.53 2006/07/02 02:23:17 momjian Exp $
PostgreSQL documentation
-->
<synopsis>
CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table</replaceable> [ USING <replaceable class="parameter">method</replaceable> ]
( { <replaceable class="parameter">column</replaceable> | ( <replaceable class="parameter">expression</replaceable> ) } [ <replaceable class="parameter">opclass</replaceable> ] [, ...] )
+ [ WITH (FILLFACTOR = <replaceable>fillfactor</replaceable>) ]
[ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ]
[ WHERE <replaceable class="parameter">predicate</replaceable> ]
</synopsis>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable class="parameter">fillfactor</replaceable></term>
+ <listitem>
+ <para>
+ The index's fillfactor in percentage.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><replaceable class="parameter">tablespace</replaceable></term>
<listitem>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.102 2006/06/28 22:01:52 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.103 2006/07/02 02:23:17 momjian Exp $
PostgreSQL documentation
-->
] )
[ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
[ WITH OIDS | WITHOUT OIDS ]
+[ WITH (FILLFACTOR = <replaceable>fillfactor</replaceable>) ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ]
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>WITH (FILLFACTOR = <replaceable>fillfactor</replaceable>)</literal></term>
+ <listitem>
+ <para>
+ This optional clause specifies the table's fillfactor in percentage.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable></literal></term>
<listitem>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_table_as.sgml,v 1.32 2006/02/19 00:04:26 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_table_as.sgml,v 1.33 2006/07/02 02:23:18 momjian Exp $
PostgreSQL documentation
-->
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name</replaceable>
[ (<replaceable>column_name</replaceable> [, ...] ) ]
[ WITH OIDS | WITHOUT OIDS ]
+ [ WITH (FILLFACTOR = <replaceable>fillfactor</replaceable>) ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ]
AS <replaceable>query</replaceable>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>WITH (FILLFACTOR = <replaceable>fillfactor</replaceable>)</literal></term>
+ <listitem>
+ <para>
+ This optional clause specifies the table's fillfactor in percentage.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>ON COMMIT</literal></term>
<listitem>
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
+}
* 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 $
*-------------------------------------------------------------------------
*/
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);
+}
* 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 $
*
*-------------------------------------------------------------------------
*/
void *state);
static void gistdoinsert(Relation r,
IndexTuple itup,
+ Size freespace,
GISTSTATE *GISTstate);
static void gistfindleaf(GISTInsertState *state,
GISTSTATE *giststate);
* 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);
values, isnull, true /* size is currently bogus */);
itup->t_tid = *ht_ctid;
- gistdoinsert(r, itup, &giststate);
+ gistdoinsert(r, itup, 0, &giststate);
/* cleanup */
freeGISTstate(&giststate);
* 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;
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;
*/
- 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;
* 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"
* 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++)
for(i=0;i<len;i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
+ /* TODO: Consider fillfactor */
return (size <= GiSTPageSize);
}
return buffer;
}
+
+Datum
+gistoption(PG_FUNCTION_ARGS)
+{
+#define GIST_DEFAULT_FILLFACTOR 90
+#define GIST_MIN_FILLFACTOR 50
+
+ ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0);
+
+ /* Use index common routine. */
+ PG_RETURN_BYTEA_P(genam_option(options,
+ GIST_MIN_FILLFACTOR, GIST_DEFAULT_FILLFACTOR));
+}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.22 2006/05/19 11:10:25 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.23 2006/07/02 02:23:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
if (curlenaddon)
{
/* insert updated tuples */
- if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber)) {
+ if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0)) {
/* there is no space on page to insert tuples */
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
tempPage=NULL; /* vacuumSplitPage() free tempPage */
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.20 2006/05/19 17:15:41 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.21 2006/07/02 02:23:18 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
* that wiil be enough space....
*/
- if (gistnospace(pages[0], itup, lenitup, *todelete))
+ if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
{
/* no space left on page, so we must split */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.57 2006/03/31 23:32:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.58 2006/07/02 02:23:18 momjian Exp $
*
* NOTES
* Postgres hash pages look like ordinary relation pages. The opaque
#include "access/genam.h"
#include "access/hash.h"
+#include "catalog/index.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "utils/lsyscache.h"
RelationGetDescr(rel)->attrs[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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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));
+}
*
*
* 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
#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"
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;
+}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
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
* 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
*/
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;
targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node,
targetBlock,
pageFreeSpace,
- len);
+ len + freespace);
}
/*
*
*
* 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
#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"
/* ----------------------------------------------------------------
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;
+}
*
*
* 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"
{
/* 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 */
* 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
/* 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;
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
{
* 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"
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,
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.
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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));
+}
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include <unistd.h>
#include "access/attnum.h"
+#include "access/heapam.h"
#include "access/htup.h"
#include "access/itup.h"
#include "access/skey.h"
RELKIND_RELATION,
$3,
true);
+ boot_reldesc->rd_options =
+ heap_option(RELKIND_RELATION, NULL);
elog(DEBUG4, "bootstrap relation created");
}
else
true,
0,
ONCOMMIT_NOOP,
- true);
+ true,
+ NULL);
elog(DEBUG4, "relation created with oid %u", id);
}
do_end();
LexIDStr($8),
NULL,
$10,
- NULL, NIL,
+ NULL, NIL, NIL,
false, false, false,
false, false, true, false);
do_end();
LexIDStr($9),
NULL,
$11,
- NULL, NIL,
+ NULL, NIL, NIL,
true, false, false,
false, false, true, false);
do_end();
*
*
* 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
#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"
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,
Oid new_rel_oid,
Oid new_type_oid,
Oid relowner,
- char relkind)
+ char relkind,
+ ArrayType *options)
{
Form_pg_class new_rel_reltup;
HeapTuple tup;
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);
* heap_create_with_catalog
*
* creates a new cataloged relation. see comments above.
+ *
+ * if opaque is specified, it must be allocated in CacheMemoryContext.
* --------------------------------
*/
Oid
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);
(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.
*
relkind,
shared_relation,
allow_system_table_mods);
+ new_rel_desc->rd_options = new_rel_options;
Assert(relid == RelationGetRelid(new_rel_desc));
relid,
new_type_oid,
ownerid,
- relkind);
+ relkind,
+ options);
/*
* now add tuples to pg_attribute for the attributes in our new relation.
*
*
* 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
#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"
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);
* ----------------------------------------------------------------
*/
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
Oid accessMethodObjectId,
Oid tableSpaceId,
Oid *classObjectId,
+ List *options,
bool isprimary,
bool istoast,
bool isconstraint,
Oid namespaceId;
int i;
+ ArrayType *array;
+ RegProcedure amoption;
+
pg_class = heap_open(RelationRelationId, RowExclusiveLock);
/*
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);
/*
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);
+}
*
*
* 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"
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
tupdesc;
Oid OIDNewHeap;
Relation OldHeap;
+ HeapTuple tuple;
+ ArrayType *options;
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
OldHeapDesc = RelationGetDescr(OldHeap);
*/
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,
true,
0,
ONCOMMIT_NOOP,
- allowSystemTableMods);
+ allowSystemTableMods,
+ options);
+
+ ReleaseSysCache(tuple);
/*
* Advance command counter so that the newly-created relation's catalog
*
*
* 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
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,
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 */
}
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
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;
+}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* '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;
List *attributeList,
Expr *predicate,
List *rangetable,
+ List *options,
bool unique,
bool primary,
bool isconstraint,
index_create(relationId, indexRelationName, indexRelationId,
indexInfo, accessMethodId, tablespaceId, classObjectId,
- primary, false, isconstraint,
+ options, primary, false, isconstraint,
allowSystemTableMods, skip_build);
}
* 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 $
*
*-------------------------------------------------------------------------
*/
(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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
/* 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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "utils/relcache.h"
#include "utils/syscache.h"
-
/*
* ON COMMIT action list
*/
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,
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);
ListCell *listptr;
int i;
AttrNumber attnum;
+ ArrayType *options;
/*
* Truncate relname to appropriate length (probably a waste of time, as
*/
descriptor = BuildDescForRelation(schema);
- localHasOids = interpretOidsOption(stmt->hasoids);
+ localHasOids = interpretOidsOption(stmt->options);
descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
if (old_constraints != NIL)
}
}
+ options = OptionBuild(NULL, stmt->options);
relationId = heap_create_with_catalog(relname,
namespaceId,
tablespaceId,
localHasOids,
parentOidCount,
stmt->oncommit,
- allowSystemTableMods);
+ allowSystemTableMods,
+ options);
+ if (options)
+ pfree(options);
StoreCatalogInheritance(relationId, inheritOids);
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:
* 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;
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
*
stmt->indexParams, /* parameters */
(Expr *) stmt->whereClause,
stmt->rangetable,
+ stmt->options,
stmt->unique,
stmt->primary,
stmt->isconstraint,
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))
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.
true,
0,
ONCOMMIT_NOOP,
- true);
+ true,
+ NULL);
/* make the toast relation visible, else index creation will fail */
CommandCounterIncrement();
indexInfo,
BTREE_AM_OID,
rel->rd_rel->reltablespace,
- classObjectId,
+ classObjectId, NIL,
true, true, false, true, false);
/*
*
*
* 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
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/****************************************************************************
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++;
{
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++;
{
/* 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);
}
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);
* 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));
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.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
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;
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
AclResult aclresult;
Oid intoRelationId;
TupleDesc tupdesc;
+ ArrayType *options;
/*
* Check consistency of arguments
*/
tupdesc = CreateTupleDescCopy(tupType);
+ options = OptionBuild(NULL, parseTree->intoOptions);
intoRelationId = heap_create_with_catalog(intoName,
namespaceId,
tablespaceId,
true,
0,
parseTree->intoOnCommit,
- allowSystemTableMods);
+ allowSystemTableMods,
+ options);
+ if (options)
+ pfree(options);
FreeTupleDesc(tupdesc);
* 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 $
*
*-------------------------------------------------------------------------
*/
COPY_NODE_FIELD(raw_expr);
COPY_STRING_FIELD(cooked_expr);
COPY_NODE_FIELD(keys);
+ COPY_NODE_FIELD(options);
COPY_STRING_FIELD(indexspace);
return newnode;
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);
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);
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);
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);
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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);
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);
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);
{
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);
COMPARE_NODE_FIELD(raw_expr);
COMPARE_STRING_FIELD(cooked_expr);
COMPARE_NODE_FIELD(keys);
+ COMPARE_NODE_FIELD(options);
COMPARE_STRING_FIELD(indexspace);
return true;
*
*
* 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*
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);
}
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);
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);
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);
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;
*
*
* 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
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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
index->relation = cxt->relation;
index->accessMethod = DEFAULT_INDEX_TYPE;
+ index->options = constraint->options;
index->tableSpace = constraint->indexspace;
index->indexParams = NIL;
index->whereClause = NULL;
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;
paramtypes = FetchPreparedStatementParams(stmt->name);
- stmt->into_has_oids = interpretOidsOption(stmt->into_contains_oids);
+ stmt->into_has_oids = interpretOidsOption(stmt->intoOptions);
if (stmt->params || paramtypes)
{
*
*
* 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
#include "catalog/index.h"
#include "catalog/namespace.h"
+#include "commands/defrem.h"
#include "nodes/makefuncs.h"
#include "parser/gramparse.h"
#include "storage/lmgr.h"
JoinType jtype;
DropBehavior dbehavior;
OnCommitAction oncommit;
- ContainsOids withoids;
List *list;
Node *node;
Value *value;
%type <list> 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
%type <boolean> TriggerForType OptTemp
%type <oncommit> OnCommitOption
-%type <withoids> OptWithOids
%type <node> for_locking_item
%type <list> for_locking_clause opt_for_locking_clause for_locking_items
n->name = $3;
$$ = (Node *)n;
}
+ /* ALTER [TABLE|INDEX] <name> 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:
*****************************************************************************/
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
- OptInherit OptWithOids OnCommitOption OptTableSpace
+ OptInherit OptWith OnCommitOption OptTableSpace
{
CreateStmt *n = makeNode(CreateStmt);
$4->istemp = $2;
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 <UDT> (cols) seems to be satisfied
* by our inheritance capabilities. Let's try it...
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;
n->indexspace = $2;
$$ = (Node *)n;
}
- | PRIMARY KEY OptConsTableSpace
+ | PRIMARY KEY opt_definition OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
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 ')'
n->indexspace = $5;
$$ = (Node *)n;
}
- | PRIMARY KEY '(' columnList ')' OptConsTableSpace
+ | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
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
| /*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; }
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
$4->istemp = $2;
n->into = $4;
n->intoColNames = $5;
- n->intoHasOids = $6;
+ n->intoOptions = $6;
n->intoOnCommit = $7;
n->intoTableSpaceName = $8;
$$ = $10;
*****************************************************************************/
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;
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;
}
;
$$ = (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);
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)
n->targetList = $3;
n->into = $4;
n->intoColNames = NIL;
- n->intoHasOids = DEFAULT_OIDS;
n->fromClause = $5;
n->whereClause = $6;
n->groupClause = $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 $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "catalog/heap.h"
+#include "commands/defrem.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/memutils.h"
#define ORDER_CLAUSE 0
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);
/*
}
/*
- * 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;
+ if (pg_strcasecmp(def->defname, "oids") == 0)
+ return defGetBoolean(def);
+ }
+
+ /* oids option is not specified. */
+ return default_with_oids;
+}
- case DEFAULT_OIDS:
- 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;
}
- elog(ERROR, "bogus ContainsOids value: %d", opt);
- return false; /* keep compiler quiet */
+ 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:;
+ }
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
stmt->indexParams, /* parameters */
(Expr *) stmt->whereClause,
stmt->rangetable,
+ stmt->options,
stmt->unique,
stmt->primary,
stmt->isconstraint,
* 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"
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 ")
}
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
*/
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:
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;
+}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
#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"
*/
#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
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,
static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
StrategyNumber numStrats,
StrategyNumber numSupport);
+static void RelationParseOptions(Relation relation, HeapTuple tuple);
/*
/* initialize relation tuple form */
relation->rd_rel = relationForm;
+ relation->rd_options = NULL;
/* and allocate attribute tuple form storage */
relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
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
*
*/
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)
*/
/* 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.
*/
* 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;
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
*/
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);
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);
* 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;
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)
{
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.
{
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)
{
/* 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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
+ int i_reloptions;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
* 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
+ * 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, "
+ "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
"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, "
+ "NULL as reloptions "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"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 "
"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",
"'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",
"'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",
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++)
{
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 */
i_conname,
i_contableoid,
i_conoid,
- i_tablespace;
+ i_tablespace,
+ i_options;
int ntups;
for (i = 0; i < numTables; i++)
* 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, "
+ "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, "
+ "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, "
"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, "
+ "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 "
"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 "
"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 "
"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 "
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));
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
appendPQExpBuffer(q, ")");
}
+ if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
+ appendPQExpBuffer(q, "\nWITH (%s)", tbinfo->reloptions);
+
appendPQExpBuffer(q, ";\n");
/* Loop dumping statistics and storage statements */
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)
* 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 $
*
*-------------------------------------------------------------------------
*/
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? */
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;
* 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"
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 */
* 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 $
*--------------------------------------------------------------------------
*/
} 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);
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
#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,
* 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.
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.
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "nodes/primnodes.h"
#include "storage/block.h"
#include "storage/lmgr.h"
+#include "utils/array.h"
#include "utils/rel.h"
#include "utils/tqual.h"
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200605241
+#define CATALOG_VERSION_NO 200607011
#endif
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_attribute.h"
#include "nodes/parsenodes.h"
#include "parser/parse_node.h"
+#include "utils/array.h"
#include "utils/rel.h"
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "access/itup.h"
#include "catalog/pg_index.h"
#include "nodes/execnodes.h"
+#include "utils/array.h"
#define DEFAULT_INDEX_TYPE "btree"
Oid accessMethodObjectId,
Oid tableSpaceId,
Oid *classObjectId,
+ List *options,
bool isprimary,
bool istoast,
bool isconstraint,
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 */
* 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
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;
/* ----------------
* 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
#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
* 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
{ 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));
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));
* 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
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;
* ----------------
*/
#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
#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
* ----------------
*/
-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 */
* 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
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?");
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");
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");
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_ ));
* 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 $
*
*-------------------------------------------------------------------------
*/
List *attributeList,
Expr *predicate,
List *rangetable,
+ List *options,
bool unique,
bool primary,
bool isconstraint,
extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def);
+extern DefElem *defWithOids(bool value);
+
#endif /* DEFREM_H */
* 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 $
*
*-------------------------------------------------------------------------
*/
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 */
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;
/*
* 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) */
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 */
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;
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;
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() */
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 */
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
* 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 $
*
*-------------------------------------------------------------------------
*/
FmgrInfo ambulkdelete;
FmgrInfo amvacuumcleanup;
FmgrInfo amcostestimate;
+ FmgrInfo amoption;
} RelationAmInfo;
* 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 */