Code review for FILLFACTOR patch. Change WITH grammar as per earlier

discussion (including making def_arg allow reserved words), add missed
opt_definition for UNIQUE case.  Put the reloptions support code in a less
random place (I chose to make a new file access/common/reloptions.c).
Eliminate header inclusion creep.  Make the index options functions safely
user-callable (seems like client apps might like to be able to test validity
of options before trying to make an index).  Reduce overhead for normal case
with no options by allowing rd_options to be NULL.  Fix some unmaintainably
klugy code, including getting rid of Natts_pg_class_fixed at long last.
Some stylistic cleanup too, and pay attention to keeping comments in sync
with code.

Documentation still needs work, though I did fix the omissions in
catalogs.sgml and indexam.sgml.
This commit is contained in:
Tom Lane 2006-07-03 22:45:41 +00:00
parent feed07350b
commit b7b78d24f7
57 changed files with 1128 additions and 1088 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.124 2006/06/03 02:53:04 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.125 2006/07/03 22:45:36 tgl Exp $ -->
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
@ -499,6 +499,13 @@
<entry>Function to estimate cost of an index scan</entry> <entry>Function to estimate cost of an index scan</entry>
</row> </row>
<row>
<entry><structfield>amoptions</structfield></entry>
<entry><type>regproc</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>Function to parse and validate reloptions for an index</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
@ -1643,6 +1650,15 @@
for details for details
</entry> </entry>
</row> </row>
<row>
<entry><structfield>reloptions</structfield></entry>
<entry><type>text[]</type></entry>
<entry></entry>
<entry>
Access-method-specific options, as <quote>keyword=value</> strings
</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.14 2006/06/06 17:59:57 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.15 2006/07/03 22:45:36 tgl Exp $ -->
<chapter id="indexam"> <chapter id="indexam">
<title>Index Access Method Interface Definition</title> <title>Index Access Method Interface Definition</title>
@ -233,6 +233,47 @@ amvacuumcleanup (IndexVacuumInfo *info,
be returned. be returned.
</para> </para>
<para>
<programlisting>
void
amcostestimate (PlannerInfo *root,
IndexOptInfo *index,
List *indexQuals,
RelOptInfo *outer_rel,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
</programlisting>
Estimate the costs of an index scan. This function is described fully
in <xref linkend="index-cost-estimation">, below.
</para>
<para>
<programlisting>
bytea *
amoptions (ArrayType *reloptions,
bool validate);
</programlisting>
Parse and validate the reloptions array for an index. This is called only
when a non-null reloptions array exists for the index.
<parameter>reloptions</> is a <type>text</> array containing entries of the
form <replaceable>name</><literal>=</><replaceable>value</>.
The function should construct a <type>bytea</> value, which will be copied
into the <structfield>rd_options</> field of the index's relcache entry.
The data contents of the <type>bytea</> value are open for the access
method to define, but the standard access methods currently all use struct
<structname>StdRdOptions</>.
When <parameter>validate</> is true, the function should report a suitable
error message if any of the options are unrecognized or have invalid
values; when <parameter>validate</> is false, invalid entries should be
silently ignored. (<parameter>validate</> is false when loading options
already stored in <structname>pg_catalog</>; an invalid entry could only
be found if the access method has changed its rules for options, and in
that case ignoring obsolete entries is appropriate.)
It is OK to return NULL if default behavior is wanted.
</para>
<para> <para>
The purpose of an index, of course, is to support scans for tuples matching The purpose of an index, of course, is to support scans for tuples matching
an indexable <literal>WHERE</> condition, often called a an indexable <literal>WHERE</> condition, often called a
@ -339,28 +380,16 @@ amrestrpos (IndexScanDesc scan);
</para> </para>
<para> <para>
<programlisting> By convention, the <literal>pg_proc</literal> entry for an index
void
amcostestimate (PlannerInfo *root,
IndexOptInfo *index,
List *indexQuals,
RelOptInfo *outer_rel,
Cost *indexStartupCost,
Cost *indexTotalCost,
Selectivity *indexSelectivity,
double *indexCorrelation);
</programlisting>
Estimate the costs of an index scan. This function is described fully
in <xref linkend="index-cost-estimation">, below.
</para>
<para>
By convention, the <literal>pg_proc</literal> entry for any index
access method function should show the correct number of arguments, access method function should show the correct number of arguments,
but declare them all as type <type>internal</> (since most of the arguments but declare them all as type <type>internal</> (since most of the arguments
have types that are not known to SQL, and we don't want users calling have types that are not known to SQL, and we don't want users calling
the functions directly anyway). The return type is declared as the functions directly anyway). The return type is declared as
<type>void</>, <type>internal</>, or <type>boolean</> as appropriate. <type>void</>, <type>internal</>, or <type>boolean</> as appropriate.
The only exception is <function>amoptions</>, which should be correctly
declared as taking <type>text[]</> and <type>bool</> and returning
<type>bytea</>. This provision allows client code to execute
<function>amoptions</> to test validity of options settings.
</para> </para>
</sect1> </sect1>

View File

@ -4,7 +4,7 @@
# Makefile for access/common # Makefile for access/common
# #
# IDENTIFICATION # IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/access/common/Makefile,v 1.21 2006/01/14 22:03:35 tgl Exp $ # $PostgreSQL: pgsql/src/backend/access/common/Makefile,v 1.22 2006/07/03 22:45:36 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -12,7 +12,7 @@ subdir = src/backend/access/common
top_builddir = ../../../.. top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
OBJS = heaptuple.o indextuple.o printtup.o scankey.o tupdesc.o OBJS = heaptuple.o indextuple.o printtup.o reloptions.o scankey.o tupdesc.o
all: SUBSYS.o all: SUBSYS.o

View File

@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.108 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.109 2006/07/03 22:45:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1694,9 +1694,8 @@ minimal_tuple_from_heap_tuple(HeapTuple htup)
* presumed to contain no null fields and no varlena fields. * presumed to contain no null fields and no varlena fields.
* *
* This routine is really only useful for certain system tables that are * This routine is really only useful for certain system tables that are
* known to be fixed-width and null-free. It is used in some places for * known to be fixed-width and null-free. Currently it is only used for
* pg_class, but that is a gross hack (it only works because relacl can * pg_attribute tuples.
* be omitted from the tuple entirely in those places).
* ---------------- * ----------------
*/ */
HeapTuple HeapTuple
@ -1738,54 +1737,3 @@ heap_addheader(int natts, /* max domain index */
return tuple; 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;
}

View File

@ -0,0 +1,326 @@
/*-------------------------------------------------------------------------
*
* reloptions.c
* Core support for relation options (pg_class.reloptions)
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.1 2006/07/03 22:45:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/reloptions.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/rel.h"
/*
* Transform a relation options list (list of DefElem) into the text array
* format that is kept in pg_class.reloptions.
*
* This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and
* ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing
* reloptions value (possibly NULL), and we replace or remove entries
* as needed.
*
* If ignoreOids is true, then we should ignore any occurrence of "oids"
* in the list (it will be or has been handled by interpretOidsOption()).
*
* Note that this is not responsible for determining whether the options
* are valid.
*
* Both oldOptions and the result are text arrays (or NULL for "default"),
* but we declare them as Datums to avoid including array.h in reloptions.h.
*/
Datum
transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset)
{
Datum result;
ArrayBuildState *astate;
ListCell *cell;
/* no change if empty list */
if (defList == NIL)
return oldOptions;
/* We build new array using accumArrayResult */
astate = NULL;
/* Copy any oldOptions that aren't to be replaced */
if (oldOptions != (Datum) 0)
{
ArrayType *array = DatumGetArrayTypeP(oldOptions);
Datum *oldoptions;
int noldoptions;
int i;
Assert(ARR_ELEMTYPE(array) == TEXTOID);
deconstruct_array(array, TEXTOID, -1, false, 'i',
&oldoptions, NULL, &noldoptions);
for (i = 0; i < noldoptions; i++)
{
text *oldoption = DatumGetTextP(oldoptions[i]);
char *text_str = (char *) VARATT_DATA(oldoption);
int text_len = VARATT_SIZE(oldoption) - VARHDRSZ;
/* Search for a match in defList */
foreach(cell, defList)
{
DefElem *def = lfirst(cell);
int kw_len = strlen(def->defname);
if (text_len > kw_len && text_str[kw_len] == '=' &&
pg_strncasecmp(text_str, def->defname, kw_len) == 0)
break;
}
if (!cell)
{
/* No match, so keep old option */
astate = accumArrayResult(astate, oldoptions[i],
false, TEXTOID,
CurrentMemoryContext);
}
}
}
/*
* If CREATE/SET, add new options to array; if RESET, just check that
* the user didn't say RESET (option=val). (Must do this because the
* grammar doesn't enforce it.)
*/
foreach(cell, defList)
{
DefElem *def = lfirst(cell);
if (isReset)
{
if (def->arg != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RESET must not include values for parameters")));
}
else
{
text *t;
const char *value;
Size len;
if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
continue;
/*
* Flatten the DefElem into a text string like "name=arg".
* If we have just "name", assume "name=true" is meant.
*/
if (def->arg != NULL)
value = defGetString(def);
else
value = "true";
len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
/* +1 leaves room for sprintf's trailing null */
t = (text *) palloc(len + 1);
VARATT_SIZEP(t) = len;
sprintf((char *) VARATT_DATA(t), "%s=%s", def->defname, value);
astate = accumArrayResult(astate, PointerGetDatum(t),
false, TEXTOID,
CurrentMemoryContext);
}
}
if (astate)
result = makeArrayResult(astate, CurrentMemoryContext);
else
result = (Datum) 0;
return result;
}
/*
* Interpret reloptions that are given in text-array format.
*
* options: array of "keyword=value" strings, as built by transformRelOptions
* numkeywords: number of legal keywords
* keywords: the allowed keywords
* values: output area
* validate: if true, throw error for unrecognized keywords.
*
* The keywords and values arrays must both be of length numkeywords.
* The values entry corresponding to a keyword is set to a palloc'd string
* containing the corresponding value, or NULL if the keyword does not appear.
*/
void
parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
char **values, bool validate)
{
ArrayType *array;
Datum *optiondatums;
int noptions;
int i;
/* Initialize to "all defaulted" */
MemSet(values, 0, numkeywords * sizeof(char *));
/* Done if no options */
if (options == (Datum) 0)
return;
array = DatumGetArrayTypeP(options);
Assert(ARR_ELEMTYPE(array) == TEXTOID);
deconstruct_array(array, TEXTOID, -1, false, 'i',
&optiondatums, NULL, &noptions);
for (i = 0; i < noptions; i++)
{
text *optiontext = DatumGetTextP(optiondatums[i]);
char *text_str = (char *) VARATT_DATA(optiontext);
int text_len = VARATT_SIZE(optiontext) - VARHDRSZ;
int j;
/* Search for a match in keywords */
for (j = 0; j < numkeywords; j++)
{
int kw_len = strlen(keywords[j]);
if (text_len > kw_len && text_str[kw_len] == '=' &&
pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
{
char *value;
int value_len;
if (values[j] && validate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("duplicate parameter \"%s\"",
keywords[j])));
value_len = text_len - kw_len - 1;
value = (char *) palloc(value_len + 1);
memcpy(value, text_str + kw_len + 1, value_len);
value[value_len] = '\0';
values[j] = value;
break;
}
}
if (j >= numkeywords && validate)
{
char *s;
char *p;
s = DatumGetCString(DirectFunctionCall1(textout, optiondatums[i]));
p = strchr(s, '=');
if (p)
*p = '\0';
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized parameter \"%s\"", s)));
}
}
}
/*
* Parse reloptions for anything using StdRdOptions (ie, fillfactor only)
*/
bytea *
default_reloptions(Datum reloptions, bool validate,
int minFillfactor, int defaultFillfactor)
{
static const char * const default_keywords[1] = { "fillfactor" };
char *values[1];
int32 fillfactor;
StdRdOptions *result;
parseRelOptions(reloptions, 1, default_keywords, values, validate);
/*
* If no options, we can just return NULL rather than doing anything.
* (defaultFillfactor is thus not used, but we require callers to pass
* it anyway since we would need it if more options were added.)
*/
if (values[0] == NULL)
return NULL;
fillfactor = pg_atoi(values[0], sizeof(int32), 0);
if (fillfactor < minFillfactor || fillfactor > 100)
{
if (validate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("fillfactor=%d is out of range (should be between %d and 100)",
fillfactor, minFillfactor)));
return NULL;
}
result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
VARATT_SIZEP(result) = sizeof(StdRdOptions);
result->fillfactor = fillfactor;
return (bytea *) result;
}
/*
* Parse options for heaps (and perhaps someday toast tables).
*/
bytea *
heap_reloptions(char relkind, Datum reloptions, bool validate)
{
return default_reloptions(reloptions, validate,
HEAP_MIN_FILLFACTOR,
HEAP_DEFAULT_FILLFACTOR);
}
/*
* Parse options for indexes.
*
* amoptions Oid of option parser
* reloptions options as text[] datum
* validate error flag
*/
bytea *
index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
{
FmgrInfo flinfo;
FunctionCallInfoData fcinfo;
Datum result;
Assert(RegProcedureIsValid(amoptions));
/* Assume function is strict */
if (reloptions == (Datum) 0)
return NULL;
/* Can't use OidFunctionCallN because we might get a NULL result */
fmgr_info(amoptions, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 2, NULL, NULL);
fcinfo.arg[0] = reloptions;
fcinfo.arg[1] = BoolGetDatum(validate);
fcinfo.argnull[0] = false;
fcinfo.argnull[1] = false;
result = FunctionCallInvoke(&fcinfo);
if (fcinfo.isnull || DatumGetPointer(result) == NULL)
return NULL;
return DatumGetByteaP(result);
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.2 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.3 2006/07/03 22:45:36 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -16,7 +16,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/gin.h" #include "access/gin.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/index.h" #include "access/reloptions.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/freespace.h" #include "storage/freespace.h"
@ -203,15 +203,23 @@ GinPageGetCopyPage( Page page ) {
} }
Datum Datum
ginoption(PG_FUNCTION_ARGS) ginoptions(PG_FUNCTION_ARGS)
{ {
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); Datum reloptions = PG_GETARG_DATUM(0);
bool validate = PG_GETARG_BOOL(1);
bytea *result;
if (options != NULL) /*
ereport(ERROR, * It's not clear that fillfactor is useful for GIN, but for the moment
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), * we'll accept it anyway. (It won't do anything...)
errmsg("GIN does not support parameters at all"))); */
#define GIN_MIN_FILLFACTOR 50
#define GIN_DEFAULT_FILLFACTOR 100
/* Do not use PG_RETURN_NULL. */ result = default_reloptions(reloptions, validate,
PG_RETURN_BYTEA_P(NULL); GIN_MIN_FILLFACTOR,
GIN_DEFAULT_FILLFACTOR);
if (result)
PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
} }

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.140 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.141 2006/07/03 22:45:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -197,9 +197,13 @@ gistbuildCallback(Relation index,
* which locks the relation for write. This is the right thing to do if * which locks the relation for write. This is the right thing to do if
* you're inserting single tups, but not when you're initializing the * you're inserting single tups, but not when you're initializing the
* whole index at once. * whole index at once.
*
* In this path we respect the fillfactor setting, whereas insertions
* after initial build do not.
*/ */
gistdoinsert(index, itup, IndexGetPageFreeSpace(index), gistdoinsert(index, itup,
&buildstate->giststate); RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
&buildstate->giststate);
buildstate->indtuples += 1; buildstate->indtuples += 1;
MemoryContextSwitchTo(oldCtx); MemoryContextSwitchTo(oldCtx);
@ -283,7 +287,6 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
bool is_splitted = false; bool is_splitted = false;
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false; bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
/* /*
* if (!is_leaf) remove old key: * if (!is_leaf) remove old key:
* This node's key has been modified, either because a child split * This node's key has been modified, either because a child split
@ -294,14 +297,13 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
* setting up a one-element todelete array; in the split case, it's * setting up a one-element todelete array; in the split case, it's
* handled implicitly because the tuple vector passed to gistSplit * handled implicitly because the tuple vector passed to gistSplit
* won't include this tuple. * won't include this tuple.
*/ *
/*
* XXX: If we want to change fillfactors between node and leaf, * XXX: If we want to change fillfactors between node and leaf,
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor) * 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)) if (gistnospace(state->stack->page, state->itup, state->ituplen,
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
state->freespace))
{ {
/* no space for insertion */ /* no space for insertion */
IndexTuple *itvec; IndexTuple *itvec;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.17 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.18 2006/07/03 22:45:36 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
@ -17,7 +17,7 @@
#include "access/gist_private.h" #include "access/gist_private.h"
#include "access/gistscan.h" #include "access/gistscan.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/index.h" #include "access/reloptions.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/freespace.h" #include "storage/freespace.h"
@ -637,14 +637,16 @@ gistNewBuffer(Relation r)
} }
Datum Datum
gistoption(PG_FUNCTION_ARGS) gistoptions(PG_FUNCTION_ARGS)
{ {
#define GIST_DEFAULT_FILLFACTOR 90 Datum reloptions = PG_GETARG_DATUM(0);
#define GIST_MIN_FILLFACTOR 50 bool validate = PG_GETARG_BOOL(1);
bytea *result;
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); result = default_reloptions(reloptions, validate,
GIST_MIN_FILLFACTOR,
/* Use index common routine. */ GIST_DEFAULT_FILLFACTOR);
PG_RETURN_BYTEA_P(genam_option(options, if (result)
GIST_MIN_FILLFACTOR, GIST_DEFAULT_FILLFACTOR)); PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.58 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.59 2006/07/03 22:45:36 tgl Exp $
* *
* NOTES * NOTES
* Postgres hash pages look like ordinary relation pages. The opaque * Postgres hash pages look like ordinary relation pages. The opaque
@ -30,7 +30,6 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/hash.h" #include "access/hash.h"
#include "catalog/index.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
@ -223,16 +222,17 @@ _hash_metapinit(Relation rel)
RelationGetRelationName(rel)); RelationGetRelationName(rel));
/* /*
* Determine the target fill factor (tuples per bucket) for this index. * Determine the target fill factor (in tuples per bucket) for this index.
* The idea is to make the fill factor correspond to pages about 3/4ths * The idea is to make the fill factor correspond to pages about as full
* full. We can compute it exactly if the index datatype is fixed-width, * as the user-settable fillfactor parameter says. We can compute it
* but for var-width there's some guessing involved. * exactly if the index datatype is fixed-width, but for var-width there's
* some guessing involved.
*/ */
data_width = get_typavgwidth(RelationGetDescr(rel)->attrs[0]->atttypid, data_width = get_typavgwidth(RelationGetDescr(rel)->attrs[0]->atttypid,
RelationGetDescr(rel)->attrs[0]->atttypmod); RelationGetDescr(rel)->attrs[0]->atttypmod);
item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) + item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
sizeof(ItemIdData); /* include the line pointer */ sizeof(ItemIdData); /* include the line pointer */
ffactor = BLCKSZ * IndexGetFillFactor(rel) / 100 / item_width; ffactor = RelationGetTargetPageUsage(rel, HASH_DEFAULT_FILLFACTOR) / item_width;
/* keep to a sane range */ /* keep to a sane range */
if (ffactor < 10) if (ffactor < 10)
ffactor = 10; ffactor = 10;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.48 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.49 2006/07/03 22:45:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -16,6 +16,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/hash.h" #include "access/hash.h"
#include "access/reloptions.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
@ -175,14 +176,16 @@ _hash_checkpage(Relation rel, Buffer buf, int flags)
} }
Datum Datum
hashoption(PG_FUNCTION_ARGS) hashoptions(PG_FUNCTION_ARGS)
{ {
#define HASH_MIN_FILLFACTOR 50 Datum reloptions = PG_GETARG_DATUM(0);
#define HASH_DEFAULT_FILLFACTOR 75 bool validate = PG_GETARG_BOOL(1);
bytea *result;
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); result = default_reloptions(reloptions, validate,
HASH_MIN_FILLFACTOR,
/* Use index common routine. */ HASH_DEFAULT_FILLFACTOR);
PG_RETURN_BYTEA_P(genam_option(options, if (result)
HASH_MIN_FILLFACTOR, HASH_DEFAULT_FILLFACTOR)); PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.214 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.215 2006/07/03 22:45:37 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -46,13 +46,9 @@
#include "access/xlogutils.h" #include "access/xlogutils.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/parsenodes.h"
#include "parser/parse_clause.h"
#include "pgstat.h" #include "pgstat.h"
#include "storage/procarray.h" #include "storage/procarray.h"
#include "utils/catcache.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/relcache.h" #include "utils/relcache.h"
@ -3592,59 +3588,3 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
else else
appendStringInfo(buf, "UNKNOWN"); 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;
}

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.62 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.63 2006/07/03 22:45:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -93,6 +93,11 @@ RelationPutHeapTuple(Relation relation,
* any committed data of other transactions. (See heap_insert's comments * any committed data of other transactions. (See heap_insert's comments
* for additional constraints needed for safe usage of this behavior.) * for additional constraints needed for safe usage of this behavior.)
* *
* We always try to avoid filling existing pages further than the fillfactor.
* This is OK since this routine is not consulted when updating a tuple and
* keeping it on the same page, which is the scenario fillfactor is meant
* to reserve space for.
*
* ereport(ERROR) is allowed here, so this routine *must* be called * ereport(ERROR) is allowed here, so this routine *must* be called
* before any (unlogged) changes are made in buffer pool. * before any (unlogged) changes are made in buffer pool.
*/ */
@ -103,17 +108,12 @@ RelationGetBufferForTuple(Relation relation, Size len,
Buffer buffer = InvalidBuffer; Buffer buffer = InvalidBuffer;
Page pageHeader; Page pageHeader;
Size pageFreeSpace, Size pageFreeSpace,
freespace; saveFreeSpace;
BlockNumber targetBlock, BlockNumber targetBlock,
otherBlock; otherBlock;
bool needLock; 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 */ len = MAXALIGN(len); /* be conservative */
freespace = HeapGetPageFreeSpace(relation);
/* /*
* If we're gonna fail for oversize tuple, do it right away * If we're gonna fail for oversize tuple, do it right away
@ -125,6 +125,10 @@ RelationGetBufferForTuple(Relation relation, Size len,
(unsigned long) len, (unsigned long) len,
(unsigned long) MaxTupleSize))); (unsigned long) MaxTupleSize)));
/* Compute desired extra freespace due to fillfactor option */
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
HEAP_DEFAULT_FILLFACTOR);
if (otherBuffer != InvalidBuffer) if (otherBuffer != InvalidBuffer)
otherBlock = BufferGetBlockNumber(otherBuffer); otherBlock = BufferGetBlockNumber(otherBuffer);
else else
@ -143,8 +147,14 @@ RelationGetBufferForTuple(Relation relation, Size len,
* When use_fsm is false, we either put the tuple onto the existing target * When use_fsm is false, we either put the tuple onto the existing target
* page or extend the relation. * page or extend the relation.
*/ */
if (len + saveFreeSpace <= MaxTupleSize)
targetBlock = relation->rd_targblock; targetBlock = relation->rd_targblock;
else
{
/* can't fit, don't screw up FSM request tracking by trying */
targetBlock = InvalidBlockNumber;
use_fsm = false;
}
if (targetBlock == InvalidBlockNumber && use_fsm) if (targetBlock == InvalidBlockNumber && use_fsm)
{ {
@ -152,7 +162,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
* We have no cached target page, so ask the FSM for an initial * We have no cached target page, so ask the FSM for an initial
* target. * target.
*/ */
targetBlock = GetPageWithFreeSpace(&relation->rd_node, len + freespace); targetBlock = GetPageWithFreeSpace(&relation->rd_node,
len + saveFreeSpace);
/* /*
* If the FSM knows nothing of the rel, try the last page before we * If the FSM knows nothing of the rel, try the last page before we
@ -208,7 +219,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
*/ */
pageHeader = (Page) BufferGetPage(buffer); pageHeader = (Page) BufferGetPage(buffer);
pageFreeSpace = PageGetFreeSpace(pageHeader); pageFreeSpace = PageGetFreeSpace(pageHeader);
if (len + freespace <= pageFreeSpace) if (len + saveFreeSpace <= pageFreeSpace)
{ {
/* use this page as future insert target, too */ /* use this page as future insert target, too */
relation->rd_targblock = targetBlock; relation->rd_targblock = targetBlock;
@ -241,7 +252,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node, targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node,
targetBlock, targetBlock,
pageFreeSpace, pageFreeSpace,
len + freespace); len + saveFreeSpace);
} }
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.56 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.57 2006/07/03 22:45:37 tgl Exp $
* *
* NOTES * NOTES
* many of the old access method routines have been turned into * many of the old access method routines have been turned into
@ -21,12 +21,8 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/parsenodes.h"
#include "parser/parse_clause.h"
#include "pgstat.h" #include "pgstat.h"
#include "utils/catcache.h"
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
@ -264,44 +260,3 @@ systable_endscan(SysScanDesc sysscan)
pfree(sysscan); pfree(sysscan);
} }
/*
* Parse options for generic indexes.
*/
bytea *
genam_option(ArrayType *options,
int minFillfactor, int defaultFillfactor)
{
int fillfactor;
IndexOption *result;
DefElem kwds[] =
{
{ T_DefElem, "fillfactor" },
};
/*
* parse options
*/
OptionParse(options, lengthof(kwds), kwds, true);
/* 0: fillfactor */
if (kwds[0].arg)
fillfactor = (int) defGetInt64(&kwds[0]);
else
fillfactor = defaultFillfactor;
if (fillfactor < minFillfactor || 100 < fillfactor)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("fillfactor=%d should be between %d and 100",
fillfactor, minFillfactor)));
/*
* build options
*/
result = (IndexOption *)
MemoryContextAlloc(CacheMemoryContext, sizeof(IndexOption));
VARATT_SIZEP(result) = sizeof(IndexOption);
result->fillfactor = fillfactor;
return (bytea *) result;
}

View File

@ -8,14 +8,13 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.138 2006/07/02 02:23:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.139 2006/07/03 22:45:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "miscadmin.h" #include "miscadmin.h"
@ -26,7 +25,7 @@ typedef struct
{ {
/* context data for _bt_checksplitloc */ /* context data for _bt_checksplitloc */
Size newitemsz; /* size of new item to be inserted */ Size newitemsz; /* size of new item to be inserted */
int fillfactor; /* used when insert at right most */ int fillfactor; /* needed when splitting rightmost page */
bool is_leaf; /* T if splitting a leaf page */ bool is_leaf; /* T if splitting a leaf page */
bool is_rightmost; /* T if splitting a rightmost page */ bool is_rightmost; /* T if splitting a rightmost page */
@ -988,11 +987,11 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
* it needs to go into!) * it needs to go into!)
* *
* If the page is the rightmost page on its level, we instead try to arrange * If the page is the rightmost page on its level, we instead try to arrange
* for reserving (100-fillfactor)% of free space on left page. In this way, * to leave the left split page fillfactor% full. In this way, when we are
* when we are inserting successively increasing keys (consider sequences, * inserting successively increasing keys (consider sequences, timestamps,
* timestamps, etc) we will end up with a tree whose pages are about fillfactor% full, * 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. * instead of the 50% full result that we'd get without this special case.
* This is the same as initially-loaded tree. * This is the same as nbtsort.c produces for a newly-created tree.
* *
* We are passed the intended insert position of the new tuple, expressed as * 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 * the offsetnumber of the tuple it must go in front of. (This could be
@ -1026,7 +1025,7 @@ _bt_findsplitloc(Relation rel,
/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */ /* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
newitemsz += sizeof(ItemIdData); newitemsz += sizeof(ItemIdData);
state.newitemsz = newitemsz; state.newitemsz = newitemsz;
state.fillfactor = IndexGetFillFactor(rel); state.fillfactor = RelationGetFillFactor(rel, BTREE_DEFAULT_FILLFACTOR);
state.is_leaf = P_ISLEAF(opaque); state.is_leaf = P_ISLEAF(opaque);
state.is_rightmost = P_RIGHTMOST(opaque); state.is_rightmost = P_RIGHTMOST(opaque);
state.have_split = false; state.have_split = false;
@ -1157,7 +1156,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
if (state->is_rightmost) if (state->is_rightmost)
{ {
/* /*
* On a rightmost page, try to reserve (100-fillfactor)% of * If splitting a rightmost page, try to put (100-fillfactor)% of
* free space on left page. See comments for _bt_findsplitloc. * free space on left page. See comments for _bt_findsplitloc.
*/ */
delta = (state->fillfactor * leftfree) delta = (state->fillfactor * leftfree)

View File

@ -27,9 +27,10 @@
* insertion would cause a split (and not only of the leaf page; the need * insertion would cause a split (and not only of the leaf page; the need
* for a split would cascade right up the tree). The steady-state load * for a split would cascade right up the tree). The steady-state load
* factor for btrees is usually estimated at 70%. We choose to pack leaf * factor for btrees is usually estimated at 70%. We choose to pack leaf
* pages to 90% and upper pages to 70%. This gives us reasonable density * pages to the user-controllable fill factor while upper pages are always
* (there aren't many upper pages if the keys are reasonable-size) without * packed to 70%. This gives us reasonable density (there aren't many upper
* incurring a lot of cascading splits during early insertions. * pages if the keys are reasonable-size) without incurring a lot of cascading
* splits during early insertions.
* *
* Formerly the index pages being built were kept in shared buffers, but * Formerly the index pages being built were kept in shared buffers, but
* that is of no value (since other backends have no interest in them yet) * that is of no value (since other backends have no interest in them yet)
@ -56,14 +57,13 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.103 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.104 2006/07/03 22:45:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/genam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "miscadmin.h" #include "miscadmin.h"
@ -121,7 +121,6 @@ typedef struct BTWriteState
static Page _bt_blnewpage(uint32 level); 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 BTPageState *_bt_pagestate(BTWriteState *wstate, uint32 level);
static void _bt_slideleft(Page page); static void _bt_slideleft(Page page);
static void _bt_sortaddtup(Page page, Size itemsize, static void _bt_sortaddtup(Page page, Size itemsize,
@ -329,22 +328,6 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
pfree(page); 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 * allocate and initialize a new BTPageState. the returned structure
* is suitable for immediate use by _bt_buildadd. * is suitable for immediate use by _bt_buildadd.
@ -365,8 +348,11 @@ _bt_pagestate(BTWriteState *wstate, uint32 level)
state->btps_lastoff = P_HIKEY; state->btps_lastoff = P_HIKEY;
state->btps_level = level; state->btps_level = level;
/* set "full" threshold based on level. See notes at head of file. */ /* set "full" threshold based on level. See notes at head of file. */
state->btps_full = _bt_full_threshold(wstate->index, if (level > 0)
PageGetPageSize(state->btps_page), level == 0); state->btps_full = (BLCKSZ * (100 - BTREE_MIN_FILLFACTOR) / 100);
else
state->btps_full = RelationGetTargetPageFreeSpace(wstate->index,
BTREE_DEFAULT_FILLFACTOR);
/* no parent level, yet */ /* no parent level, yet */
state->btps_next = NULL; state->btps_next = NULL;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.75 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.76 2006/07/03 22:45:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -19,7 +19,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "catalog/catalog.h" #include "access/reloptions.h"
#include "executor/execdebug.h" #include "executor/execdebug.h"
#include "miscadmin.h" #include "miscadmin.h"
@ -1081,14 +1081,16 @@ BTreeShmemInit(void)
} }
Datum Datum
btoption(PG_FUNCTION_ARGS) btoptions(PG_FUNCTION_ARGS)
{ {
#define BTREE_MIN_FILLFACTOR 50 Datum reloptions = PG_GETARG_DATUM(0);
#define BTREE_DEFAULT_FILLFACTOR 90 bool validate = PG_GETARG_BOOL(1);
bytea *result;
ArrayType *options = (ArrayType *) PG_GETARG_POINTER(0); result = default_reloptions(reloptions, validate,
BTREE_MIN_FILLFACTOR,
/* Use index common routine. */ BTREE_DEFAULT_FILLFACTOR);
PG_RETURN_BYTEA_P(genam_option(options, if (result)
BTREE_MIN_FILLFACTOR, BTREE_DEFAULT_FILLFACTOR)); PG_RETURN_BYTEA_P(result);
PG_RETURN_NULL();
} }

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.45 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.46 2006/07/03 22:45:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -337,7 +337,7 @@ _xl_remove_hash_entry(XLogRelDesc *rdesc)
RelationCloseSmgr(&(rdesc->reldata)); RelationCloseSmgr(&(rdesc->reldata));
memset(rdesc, 0, sizeof(XLogRelDesc)); memset(rdesc, 0, sizeof(XLogRelDesc));
memset(tpgc, 0, CLASS_TUPLE_SIZE); memset(tpgc, 0, sizeof(FormData_pg_class));
rdesc->reldata.rd_rel = tpgc; rdesc->reldata.rd_rel = tpgc;
} }

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.81 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.82 2006/07/03 22:45:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -19,7 +19,6 @@
#include <unistd.h> #include <unistd.h>
#include "access/attnum.h" #include "access/attnum.h"
#include "access/heapam.h"
#include "access/htup.h" #include "access/htup.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/skey.h" #include "access/skey.h"
@ -193,8 +192,6 @@ Boot_CreateStmt:
RELKIND_RELATION, RELKIND_RELATION,
$3, $3,
true); true);
boot_reldesc->rd_options =
heap_option(RELKIND_RELATION, NULL);
elog(DEBUG4, "bootstrap relation created"); elog(DEBUG4, "bootstrap relation created");
} }
else else
@ -212,8 +209,8 @@ Boot_CreateStmt:
true, true,
0, 0,
ONCOMMIT_NOOP, ONCOMMIT_NOOP,
true, (Datum) 0,
NULL); true);
elog(DEBUG4, "relation created with oid %u", id); elog(DEBUG4, "relation created with oid %u", id);
} }
do_end(); do_end();

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.303 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.304 2006/07/03 22:45:37 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -44,24 +44,20 @@
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_clause.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteRemove.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/catcache.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -71,7 +67,7 @@ static void AddNewRelationTuple(Relation pg_class_desc,
Oid new_rel_oid, Oid new_type_oid, Oid new_rel_oid, Oid new_type_oid,
Oid relowner, Oid relowner,
char relkind, char relkind,
ArrayType *options); Datum reloptions);
static Oid AddNewRelationType(const char *typeName, static Oid AddNewRelationType(const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid new_rel_oid, Oid new_rel_oid,
@ -550,6 +546,80 @@ AddNewAttributeTuples(Oid new_rel_oid,
heap_close(rel, RowExclusiveLock); heap_close(rel, RowExclusiveLock);
} }
/* --------------------------------
* InsertPgClassTuple
*
* Construct and insert a new tuple in pg_class.
*
* Caller has already opened and locked pg_class.
* Tuple data is taken from new_rel_desc->rd_rel, except for the
* variable-width fields which are not present in a cached reldesc.
* We alway initialize relacl to NULL (i.e., default permissions),
* and reloptions is set to the passed-in text array (if any).
* --------------------------------
*/
void
InsertPgClassTuple(Relation pg_class_desc,
Relation new_rel_desc,
Oid new_rel_oid,
Datum reloptions)
{
Form_pg_class rd_rel = new_rel_desc->rd_rel;
Datum values[Natts_pg_class];
char nulls[Natts_pg_class];
HeapTuple tup;
/* This is a tad tedious, but way cleaner than what we used to do... */
memset(values, 0, sizeof(values));
memset(nulls, ' ', sizeof(nulls));
values[Anum_pg_class_relname - 1] = NameGetDatum(&rd_rel->relname);
values[Anum_pg_class_relnamespace - 1] = ObjectIdGetDatum(rd_rel->relnamespace);
values[Anum_pg_class_reltype - 1] = ObjectIdGetDatum(rd_rel->reltype);
values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner);
values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam);
values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode);
values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace);
values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages);
values[Anum_pg_class_reltuples - 1] = Float4GetDatum(rd_rel->reltuples);
values[Anum_pg_class_reltoastrelid - 1] = ObjectIdGetDatum(rd_rel->reltoastrelid);
values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
values[Anum_pg_class_reltriggers - 1] = Int16GetDatum(rd_rel->reltriggers);
values[Anum_pg_class_relukeys - 1] = Int16GetDatum(rd_rel->relukeys);
values[Anum_pg_class_relfkeys - 1] = Int16GetDatum(rd_rel->relfkeys);
values[Anum_pg_class_relrefs - 1] = Int16GetDatum(rd_rel->relrefs);
values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids);
values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey);
values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
/* start out with empty permissions */
nulls[Anum_pg_class_relacl - 1] = 'n';
if (reloptions != (Datum) 0)
values[Anum_pg_class_reloptions - 1] = reloptions;
else
nulls[Anum_pg_class_reloptions - 1] = 'n';
tup = heap_formtuple(RelationGetDescr(pg_class_desc), values, nulls);
/*
* The new tuple must have the oid already chosen for the rel. Sure
* would be embarrassing to do this sort of thing in polite company.
*/
HeapTupleSetOid(tup, new_rel_oid);
/* finally insert the new tuple, update the indexes, and clean up */
simple_heap_insert(pg_class_desc, tup);
CatalogUpdateIndexes(pg_class_desc, tup);
heap_freetuple(tup);
}
/* -------------------------------- /* --------------------------------
* AddNewRelationTuple * AddNewRelationTuple
* *
@ -564,10 +634,9 @@ AddNewRelationTuple(Relation pg_class_desc,
Oid new_type_oid, Oid new_type_oid,
Oid relowner, Oid relowner,
char relkind, char relkind,
ArrayType *options) Datum reloptions)
{ {
Form_pg_class new_rel_reltup; Form_pg_class new_rel_reltup;
HeapTuple tup;
/* /*
* first we update some of the information in our uncataloged relation's * first we update some of the information in our uncataloged relation's
@ -602,20 +671,8 @@ AddNewRelationTuple(Relation pg_class_desc,
new_rel_desc->rd_att->tdtypeid = new_type_oid; new_rel_desc->rd_att->tdtypeid = new_type_oid;
/* now form a tuple to add to pg_class */ /* Now build and insert the tuple */
tup = build_class_tuple(new_rel_reltup, options); InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
/* force tuple to have the desired OID */
HeapTupleSetOid(tup, new_rel_oid);
/*
* finally insert the new tuple, update the indexes, and clean up.
*/
simple_heap_insert(pg_class_desc, tup);
CatalogUpdateIndexes(pg_class_desc, tup);
heap_freetuple(tup);
} }
@ -660,8 +717,6 @@ AddNewRelationType(const char *typeName,
* heap_create_with_catalog * heap_create_with_catalog
* *
* creates a new cataloged relation. see comments above. * creates a new cataloged relation. see comments above.
*
* if opaque is specified, it must be allocated in CacheMemoryContext.
* -------------------------------- * --------------------------------
*/ */
Oid Oid
@ -676,12 +731,11 @@ heap_create_with_catalog(const char *relname,
bool oidislocal, bool oidislocal,
int oidinhcount, int oidinhcount,
OnCommitAction oncommit, OnCommitAction oncommit,
bool allow_system_table_mods, Datum reloptions,
ArrayType *options) bool allow_system_table_mods)
{ {
Relation pg_class_desc; Relation pg_class_desc;
Relation new_rel_desc; Relation new_rel_desc;
bytea *new_rel_options;
Oid new_type_oid; Oid new_type_oid;
pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
@ -698,13 +752,6 @@ heap_create_with_catalog(const char *relname,
(errcode(ERRCODE_DUPLICATE_TABLE), (errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("relation \"%s\" already exists", relname))); 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. * Allocate an OID for the relation, unless we were told what to use.
* *
@ -728,7 +775,6 @@ heap_create_with_catalog(const char *relname,
relkind, relkind,
shared_relation, shared_relation,
allow_system_table_mods); allow_system_table_mods);
new_rel_desc->rd_options = new_rel_options;
Assert(relid == RelationGetRelid(new_rel_desc)); Assert(relid == RelationGetRelid(new_rel_desc));
@ -757,7 +803,7 @@ heap_create_with_catalog(const char *relname,
new_type_oid, new_type_oid,
ownerid, ownerid,
relkind, relkind,
options); reloptions);
/* /*
* now add tuples to pg_attribute for the attributes in our new relation. * now add tuples to pg_attribute for the attributes in our new relation.

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.267 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.268 2006/07/03 22:45:37 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -37,7 +37,6 @@
#include "executor/executor.h" #include "executor/executor.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "parser/parse_clause.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "storage/procarray.h" #include "storage/procarray.h"
#include "storage/smgr.h" #include "storage/smgr.h"
@ -54,8 +53,6 @@
static TupleDesc ConstructTupleDescriptor(Relation heapRelation, static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
IndexInfo *indexInfo, IndexInfo *indexInfo,
Oid *classObjectId); Oid *classObjectId);
static void UpdateRelationRelation(Relation pg_class, Relation indexRelation,
ArrayType *options);
static void InitializeAttributeOids(Relation indexRelation, static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid); int numatts, Oid indexoid);
static void AppendAttributeTuples(Relation indexRelation, int numatts); static void AppendAttributeTuples(Relation indexRelation, int numatts);
@ -238,32 +235,6 @@ ConstructTupleDescriptor(Relation heapRelation,
return indexTupDesc; return indexTupDesc;
} }
/* ----------------------------------------------------------------
* UpdateRelationRelation
* ----------------------------------------------------------------
*/
static void
UpdateRelationRelation(Relation pg_class, Relation indexRelation,
ArrayType *options)
{
HeapTuple tuple;
tuple = build_class_tuple(indexRelation->rd_rel, options);
/*
* the new tuple must have the oid already chosen for the index. sure
* would be embarrassing to do this sort of thing in polite company.
*/
HeapTupleSetOid(tuple, RelationGetRelid(indexRelation));
simple_heap_insert(pg_class, tuple);
/* update the system catalog indexes */
CatalogUpdateIndexes(pg_class, tuple);
heap_freetuple(tuple);
}
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* InitializeAttributeOids * InitializeAttributeOids
* ---------------------------------------------------------------- * ----------------------------------------------------------------
@ -449,6 +420,7 @@ UpdateIndexRelation(Oid indexoid,
* accessMethodObjectId: OID of index AM to use * accessMethodObjectId: OID of index AM to use
* tableSpaceId: OID of tablespace to use * tableSpaceId: OID of tablespace to use
* classObjectId: array of index opclass OIDs, one per index column * classObjectId: array of index opclass OIDs, one per index column
* reloptions: AM-specific options
* isprimary: index is a PRIMARY KEY * isprimary: index is a PRIMARY KEY
* istoast: index is a toast table's index * istoast: index is a toast table's index
* isconstraint: index is owned by a PRIMARY KEY or UNIQUE constraint * isconstraint: index is owned by a PRIMARY KEY or UNIQUE constraint
@ -466,7 +438,7 @@ index_create(Oid heapRelationId,
Oid accessMethodObjectId, Oid accessMethodObjectId,
Oid tableSpaceId, Oid tableSpaceId,
Oid *classObjectId, Oid *classObjectId,
List *options, Datum reloptions,
bool isprimary, bool isprimary,
bool istoast, bool istoast,
bool isconstraint, bool isconstraint,
@ -481,9 +453,6 @@ index_create(Oid heapRelationId,
Oid namespaceId; Oid namespaceId;
int i; int i;
ArrayType *array;
RegProcedure amoption;
pg_class = heap_open(RelationRelationId, RowExclusiveLock); pg_class = heap_open(RelationRelationId, RowExclusiveLock);
/* /*
@ -581,41 +550,14 @@ index_create(Oid heapRelationId,
indexRelation->rd_rel->relkind = RELKIND_INDEX; indexRelation->rd_rel->relkind = RELKIND_INDEX;
indexRelation->rd_rel->relhasoids = false; 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 * store index's pg_class entry
*/ */
UpdateRelationRelation(pg_class, indexRelation, array); InsertPgClassTuple(pg_class, indexRelation,
RelationGetRelid(indexRelation),
reloptions);
/* done with pg_class */ /* done with pg_class */
if (array)
pfree(array);
heap_close(pg_class, RowExclusiveLock); heap_close(pg_class, RowExclusiveLock);
/* /*
@ -1783,23 +1725,3 @@ reindex_relation(Oid relid, bool toast_too)
return result; 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);
}

View File

@ -9,19 +9,16 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/indexing.c,v 1.112 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/indexing.c,v 1.113 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "utils/syscache.h"
#include "commands/defrem.h"
/* /*

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.148 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.149 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -567,7 +567,8 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
Oid OIDNewHeap; Oid OIDNewHeap;
Relation OldHeap; Relation OldHeap;
HeapTuple tuple; HeapTuple tuple;
ArrayType *options; Datum reloptions;
bool isNull;
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock); OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
OldHeapDesc = RelationGetDescr(OldHeap); OldHeapDesc = RelationGetDescr(OldHeap);
@ -584,19 +585,12 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
tuple = SearchSysCache(RELOID, tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(OIDOldHeap), ObjectIdGetDatum(OIDOldHeap),
0, 0, 0); 0, 0, 0);
if (tuple) if (!HeapTupleIsValid(tuple))
{ elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap);
Datum datum; reloptions = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions,
bool isNull; &isNull);
datum = SysCacheGetAttr(RELOID, tuple, if (isNull)
Anum_pg_class_reloptions, &isNull); reloptions = (Datum) 0;
options = isNull ? NULL : DatumGetArrayTypeP(datum);
}
else
{
/* should not happen */
options = NULL;
}
OIDNewHeap = heap_create_with_catalog(NewName, OIDNewHeap = heap_create_with_catalog(NewName,
RelationGetNamespace(OldHeap), RelationGetNamespace(OldHeap),
@ -609,8 +603,8 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
true, true,
0, 0,
ONCOMMIT_NOOP, ONCOMMIT_NOOP,
allowSystemTableMods, reloptions,
options); allowSystemTableMods);
ReleaseSysCache(tuple); ReleaseSysCache(tuple);

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.96 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.97 2006/07/03 22:45:38 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
@ -110,7 +110,6 @@ defGetNumeric(DefElem *def)
case T_Integer: case T_Integer:
return (double) intVal(def->arg); return (double) intVal(def->arg);
case T_Float: case T_Float:
case T_String: /* XXX: needs strict check? */
return floatVal(def->arg); return floatVal(def->arg);
default: default:
ereport(ERROR, ereport(ERROR,
@ -128,27 +127,39 @@ bool
defGetBoolean(DefElem *def) defGetBoolean(DefElem *def)
{ {
/* /*
* Presently, boolean flags must simply be present/absent or * If no parameter given, assume "true" is meant.
* integer 0/1. Later we could allow 'flag = t', 'flag = f', etc.
*/ */
if (def->arg == NULL) if (def->arg == NULL)
return true; return true;
/*
* Allow 0, 1, "true", "false"
*/
switch (nodeTag(def->arg)) switch (nodeTag(def->arg))
{ {
case T_Integer: case T_Integer:
switch (intVal(def->arg)) switch (intVal(def->arg))
{ {
case 0: case 0:
return false; return false;
case 1: case 1:
return true; return true;
default:
/* otherwise, error out below */
break;
} }
break; break;
default: default:
{
char *sval = defGetString(def);
if (pg_strcasecmp(sval, "true") == 0)
return true;
if (pg_strcasecmp(sval, "false") == 0)
return false;
}
break; break;
} }
/* on error */
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("%s requires a boolean value", errmsg("%s requires a boolean value",
@ -172,7 +183,7 @@ defGetInt64(DefElem *def)
case T_Integer: case T_Integer:
return (int64) intVal(def->arg); return (int64) intVal(def->arg);
case T_Float: case T_Float:
case T_String: /* XXX: needs strict check? */
/* /*
* Values too large for int4 will be represented as Float * Values too large for int4 will be represented as Float
* constants by the lexer. Accept these if they are valid int8 * constants by the lexer. Accept these if they are valid int8
@ -293,10 +304,14 @@ defGetTypeLength(DefElem *def)
return 0; /* keep compiler quiet */ return 0; /* keep compiler quiet */
} }
/*
* Create a DefElem setting "oids" to the specified value.
*/
DefElem * DefElem *
defWithOids(bool value) defWithOids(bool value)
{ {
DefElem *f = makeNode(DefElem); DefElem *f = makeNode(DefElem);
f->defname = "oids"; f->defname = "oids";
f->arg = (Node *)makeInteger(value); f->arg = (Node *)makeInteger(value);
return f; return f;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.142 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.143 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -17,6 +17,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/reloptions.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/dependency.h" #include "catalog/dependency.h"
#include "catalog/heap.h" #include "catalog/heap.h"
@ -72,12 +73,12 @@ static bool relationHasPrimaryKey(Relation rel);
* to index on. * to index on.
* 'predicate': the partial-index condition, or NULL if none. * 'predicate': the partial-index condition, or NULL if none.
* 'rangetable': needed to interpret the predicate. * 'rangetable': needed to interpret the predicate.
* 'options': reloptions from WITH (in list-of-DefElem form).
* 'unique': make the index enforce uniqueness. * 'unique': make the index enforce uniqueness.
* 'primary': mark the index as a primary key in the catalogs. * 'primary': mark the index as a primary key in the catalogs.
* 'isconstraint': index is for a PRIMARY KEY or UNIQUE constraint, * 'isconstraint': index is for a PRIMARY KEY or UNIQUE constraint,
* so build a pg_constraint entry for it. * so build a pg_constraint entry for it.
* 'is_alter_table': this is due to an ALTER rather than a CREATE operation. * '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 * 'check_rights': check for CREATE rights in the namespace. (This should
* be true except when ALTER is deleting/recreating an index.) * be true except when ALTER is deleting/recreating an index.)
* 'skip_build': make the catalog entries but leave the index file empty; * 'skip_build': make the catalog entries but leave the index file empty;
@ -110,6 +111,8 @@ DefineIndex(RangeVar *heapRelation,
Relation rel; Relation rel;
HeapTuple tuple; HeapTuple tuple;
Form_pg_am accessMethodForm; Form_pg_am accessMethodForm;
RegProcedure amoptions;
Datum reloptions;
IndexInfo *indexInfo; IndexInfo *indexInfo;
int numberOfAttributes; int numberOfAttributes;
@ -261,6 +264,8 @@ DefineIndex(RangeVar *heapRelation,
errmsg("access method \"%s\" does not support multicolumn indexes", errmsg("access method \"%s\" does not support multicolumn indexes",
accessMethodName))); accessMethodName)));
amoptions = accessMethodForm->amoptions;
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
/* /*
@ -367,6 +372,13 @@ DefineIndex(RangeVar *heapRelation,
AlterTableInternal(relationId, cmds, false); AlterTableInternal(relationId, cmds, false);
} }
/*
* Parse AM-specific options, convert to text array form, validate.
*/
reloptions = transformRelOptions((Datum) 0, options, false, false);
(void) index_reloptions(amoptions, reloptions, true);
/* /*
* Prepare arguments for index_create, primarily an IndexInfo structure. * Prepare arguments for index_create, primarily an IndexInfo structure.
* Note that ii_Predicate must be in implicit-AND format. * Note that ii_Predicate must be in implicit-AND format.
@ -399,7 +411,7 @@ DefineIndex(RangeVar *heapRelation,
index_create(relationId, indexRelationName, indexRelationId, index_create(relationId, indexRelationName, indexRelationId,
indexInfo, accessMethodId, tablespaceId, classObjectId, indexInfo, accessMethodId, tablespaceId, classObjectId,
options, primary, false, isconstraint, reloptions, primary, false, isconstraint,
allowSystemTableMods, skip_build); allowSystemTableMods, skip_build);
} }

View File

@ -10,7 +10,7 @@
* Copyright (c) 2002-2006, PostgreSQL Global Development Group * Copyright (c) 2002-2006, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.54 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.55 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -197,7 +197,6 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
errmsg("prepared statement is not a SELECT"))); errmsg("prepared statement is not a SELECT")));
query->into = copyObject(stmt->into); query->into = copyObject(stmt->into);
query->intoOptions = copyObject(stmt->intoOptions); query->intoOptions = copyObject(stmt->intoOptions);
query->intoHasOids = stmt->into_has_oids;
query->intoOnCommit = stmt->into_on_commit; query->intoOnCommit = stmt->into_on_commit;
if (stmt->into_tbl_space) if (stmt->into_tbl_space)
query->intoTableSpaceName = pstrdup(stmt->into_tbl_space); query->intoTableSpaceName = pstrdup(stmt->into_tbl_space);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.133 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.134 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -205,17 +205,7 @@ DefineSequence(CreateSeqStmt *seq)
/* Now form & insert sequence tuple */ /* Now form & insert sequence tuple */
tuple = heap_formtuple(tupDesc, value, null); 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); Assert(ItemPointerGetOffsetNumber(&(tuple->t_self)) == FirstOffsetNumber);

View File

@ -8,13 +8,14 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.191 2006/07/02 05:17:26 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.192 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/genam.h" #include "access/genam.h"
#include "access/reloptions.h"
#include "access/tuptoaster.h" #include "access/tuptoaster.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/dependency.h" #include "catalog/dependency.h"
@ -62,6 +63,7 @@
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
/* /*
* ON COMMIT action list * ON COMMIT action list
*/ */
@ -248,7 +250,7 @@ static void ATExecDropCluster(Relation rel);
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
char *tablespacename); char *tablespacename);
static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace);
static void ATExecSetOptions(Relation rel, List *newOptions); static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset);
static void ATExecEnableDisableTrigger(Relation rel, char *trigname, static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
bool enable, bool skip_system); bool enable, bool skip_system);
static void ATExecAddInherits(Relation rel, RangeVar *parent); static void ATExecAddInherits(Relation rel, RangeVar *parent);
@ -283,10 +285,10 @@ DefineRelation(CreateStmt *stmt, char relkind)
bool localHasOids; bool localHasOids;
int parentOidCount; int parentOidCount;
List *rawDefaults; List *rawDefaults;
Datum reloptions;
ListCell *listptr; ListCell *listptr;
int i; int i;
AttrNumber attnum; AttrNumber attnum;
ArrayType *options;
/* /*
* Truncate relname to appropriate length (probably a waste of time, as * Truncate relname to appropriate length (probably a waste of time, as
@ -339,6 +341,13 @@ DefineRelation(CreateStmt *stmt, char relkind)
/* note InvalidOid is OK in this case */ /* note InvalidOid is OK in this case */
} }
/*
* Parse and validate reloptions, if any.
*/
reloptions = transformRelOptions((Datum) 0, stmt->options, true, false);
(void) heap_reloptions(relkind, reloptions, true);
/* Check permissions except when using database's default */ /* Check permissions except when using database's default */
if (OidIsValid(tablespaceId)) if (OidIsValid(tablespaceId))
{ {
@ -428,7 +437,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
} }
} }
options = OptionBuild(NULL, stmt->options);
relationId = heap_create_with_catalog(relname, relationId = heap_create_with_catalog(relname,
namespaceId, namespaceId,
tablespaceId, tablespaceId,
@ -440,10 +448,8 @@ DefineRelation(CreateStmt *stmt, char relkind)
localHasOids, localHasOids,
parentOidCount, parentOidCount,
stmt->oncommit, stmt->oncommit,
allowSystemTableMods, reloptions,
options); allowSystemTableMods);
if (options)
pfree(options);
StoreCatalogInheritance(relationId, inheritOids); StoreCatalogInheritance(relationId, inheritOids);
@ -2103,7 +2109,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
ATPrepSetTableSpace(tab, rel, cmd->name); ATPrepSetTableSpace(tab, rel, cmd->name);
pass = AT_PASS_MISC; /* doesn't actually matter */ pass = AT_PASS_MISC; /* doesn't actually matter */
break; break;
case AT_SetOptions: /* SET (...) */ case AT_SetRelOptions: /* SET (...) */
case AT_ResetRelOptions: /* RESET (...) */
ATSimplePermissionsRelationOrIndex(rel); ATSimplePermissionsRelationOrIndex(rel);
/* This command never recurses */ /* This command never recurses */
/* No command-specific prep needed */ /* No command-specific prep needed */
@ -2279,8 +2286,11 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd)
* Nothing to do here; Phase 3 does the work * Nothing to do here; Phase 3 does the work
*/ */
break; break;
case AT_SetOptions: /* SET (...) */ case AT_SetRelOptions: /* SET (...) */
ATExecSetOptions(rel, (List *) cmd->def); ATExecSetRelOptions(rel, (List *) cmd->def, false);
break;
case AT_ResetRelOptions: /* RESET (...) */
ATExecSetRelOptions(rel, (List *) cmd->def, true);
break; break;
case AT_EnableTrig: /* ENABLE TRIGGER name */ case AT_EnableTrig: /* ENABLE TRIGGER name */
ATExecEnableDisableTrigger(rel, cmd->name, true, false); ATExecEnableDisableTrigger(rel, cmd->name, true, false);
@ -5757,24 +5767,29 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename)
} }
/* /*
* ALTER TABLE/INDEX SET (...) * ALTER TABLE/INDEX SET (...) or RESET (...)
*/ */
static void static void
ATExecSetOptions(Relation rel, List *newOptions) ATExecSetRelOptions(Relation rel, List *defList, bool isReset)
{ {
Oid relid; Oid relid;
Relation pgclass; Relation pgclass;
HeapTuple tuple; HeapTuple tuple;
HeapTuple newtuple;
Datum datum; Datum datum;
bool isnull; bool isnull;
ArrayType *mergedOptions; Datum newOptions;
bytea *options; Datum repl_val[Natts_pg_class];
char repl_null[Natts_pg_class];
char repl_repl[Natts_pg_class];
if (list_length(newOptions) == 0) if (defList == NIL)
return; /* do nothing */ return; /* nothing to do */
relid = RelationGetRelid(rel);
pgclass = heap_open(RelationRelationId, RowExclusiveLock); pgclass = heap_open(RelationRelationId, RowExclusiveLock);
/* Get the old reloptions */
relid = RelationGetRelid(rel);
tuple = SearchSysCache(RELOID, tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relid), ObjectIdGetDatum(relid),
0, 0, 0); 0, 0, 0);
@ -5783,59 +5798,54 @@ ATExecSetOptions(Relation rel, List *newOptions)
datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull); datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_reloptions, &isnull);
mergedOptions = OptionBuild( /* Generate new proposed reloptions (text array) */
isnull ? NULL : DatumGetArrayTypeP(datum), newOptions); newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
defList, false, isReset);
/* Validate */
switch (rel->rd_rel->relkind) switch (rel->rd_rel->relkind)
{ {
case RELKIND_RELATION: case RELKIND_RELATION:
case RELKIND_TOASTVALUE: case RELKIND_TOASTVALUE:
options = heap_option(rel->rd_rel->relkind, mergedOptions); (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
break; break;
case RELKIND_INDEX: case RELKIND_INDEX:
options = index_option(rel->rd_am->amoption, mergedOptions); (void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
break; break;
default: default:
elog(ERROR, "unexpected RELKIND=%c", rel->rd_rel->relkind); ereport(ERROR,
options = NULL; /* keep compiler quiet */ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table, index, or TOAST table",
RelationGetRelationName(rel))));
break; break;
} }
if (rel->rd_options != options) /*
{ * All we need do here is update the pg_class row; the new options will be
HeapTuple newtuple; * propagated into relcaches during post-commit cache inval.
Datum repl_val[Natts_pg_class]; */
char repl_null[Natts_pg_class]; memset(repl_val, 0, sizeof(repl_val));
char repl_repl[Natts_pg_class]; memset(repl_null, ' ', sizeof(repl_null));
memset(repl_repl, ' ', sizeof(repl_repl));
/* XXX: This is not necessarily required. */ if (newOptions != (Datum) 0)
if (rel->rd_options) repl_val[Anum_pg_class_reloptions - 1] = newOptions;
pfree(rel->rd_options); else
rel->rd_options = options; repl_null[Anum_pg_class_reloptions - 1] = 'n';
memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_class_reloptions - 1] = 'r';
memset(repl_null, ' ', sizeof(repl_null));
repl_repl[Anum_pg_class_reloptions - 1] = 'r';
if (mergedOptions) newtuple = heap_modifytuple(tuple, RelationGetDescr(pgclass),
repl_val[Anum_pg_class_reloptions - 1] = repl_val, repl_null, repl_repl);
PointerGetDatum(mergedOptions);
else
repl_null[Anum_pg_class_reloptions - 1] = 'n';
newtuple = heap_modifytuple(tuple, RelationGetDescr(pgclass), simple_heap_update(pgclass, &newtuple->t_self, newtuple);
repl_val, repl_null, repl_repl);
simple_heap_update(pgclass, &newtuple->t_self, newtuple); CatalogUpdateIndexes(pgclass, newtuple);
CatalogUpdateIndexes(pgclass, newtuple);
heap_freetuple(newtuple); heap_freetuple(newtuple);
}
if (mergedOptions)
pfree(mergedOptions);
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
heap_close(pgclass, RowExclusiveLock); heap_close(pgclass, RowExclusiveLock);
} }
@ -6642,6 +6652,9 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
* even if its master relation is a temp table. There cannot be any * even if its master relation is a temp table. There cannot be any
* naming collision, and the toast rel will be destroyed when its master * naming collision, and the toast rel will be destroyed when its master
* is, so there's no need to handle the toast rel as temp. * is, so there's no need to handle the toast rel as temp.
*
* XXX would it make sense to apply the master's reloptions to the toast
* table?
*/ */
toast_relid = heap_create_with_catalog(toast_relname, toast_relid = heap_create_with_catalog(toast_relname,
PG_TOAST_NAMESPACE, PG_TOAST_NAMESPACE,
@ -6654,8 +6667,8 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
true, true,
0, 0,
ONCOMMIT_NOOP, ONCOMMIT_NOOP,
true, (Datum) 0,
NULL); true);
/* make the toast relation visible, else index creation will fail */ /* make the toast relation visible, else index creation will fail */
CommandCounterIncrement(); CommandCounterIncrement();
@ -6689,7 +6702,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
indexInfo, indexInfo,
BTREE_AM_OID, BTREE_AM_OID,
rel->rd_rel->reltablespace, rel->rd_rel->reltablespace,
classObjectId, NIL, classObjectId, (Datum) 0,
true, true, false, true, false); true, true, false, true, false);
/* /*

View File

@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.331 2006/07/02 02:23:19 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.332 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -3119,8 +3119,6 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages,
* vacuumlazy.c does, we'd be skewing that statistic. * vacuumlazy.c does, we'd be skewing that statistic.
*/ */
threshold = GetAvgFSMRequestSize(&onerel->rd_node); threshold = GetAvgFSMRequestSize(&onerel->rd_node);
if (threshold < HeapGetPageFreeSpace(onerel))
threshold = HeapGetPageFreeSpace(onerel);
pageSpaces = (PageFreeSpaceInfo *) pageSpaces = (PageFreeSpaceInfo *)
palloc(nPages * sizeof(PageFreeSpaceInfo)); palloc(nPages * sizeof(PageFreeSpaceInfo));
@ -3391,11 +3389,13 @@ static Size
PageGetFreeSpaceWithFillFactor(Relation relation, Page page) PageGetFreeSpaceWithFillFactor(Relation relation, Page page)
{ {
PageHeader pd = (PageHeader) page; PageHeader pd = (PageHeader) page;
Size pagefree = HeapGetPageFreeSpace(relation);
Size freespace = pd->pd_upper - pd->pd_lower; Size freespace = pd->pd_upper - pd->pd_lower;
Size targetfree;
if (freespace > pagefree) targetfree = RelationGetTargetPageFreeSpace(relation,
return freespace - pagefree; HEAP_DEFAULT_FILLFACTOR);
if (freespace > targetfree)
return freespace - targetfree;
else else
return 0; return 0;
} }

View File

@ -31,7 +31,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.71 2006/07/02 02:23:20 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.72 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -149,8 +149,6 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
/* Set threshold for interesting free space = average request size */ /* Set threshold for interesting free space = average request size */
/* XXX should we scale it up or down? Adjust vacuum.c too, if so */ /* XXX should we scale it up or down? Adjust vacuum.c too, if so */
vacrelstats->threshold = GetAvgFSMRequestSize(&onerel->rd_node); vacrelstats->threshold = GetAvgFSMRequestSize(&onerel->rd_node);
if (vacrelstats->threshold < HeapGetPageFreeSpace(onerel))
vacrelstats->threshold = HeapGetPageFreeSpace(onerel);
/* Open all indexes of the relation */ /* Open all indexes of the relation */
vac_open_indexes(onerel, ShareUpdateExclusiveLock, &nindexes, &Irel); vac_open_indexes(onerel, ShareUpdateExclusiveLock, &nindexes, &Irel);

View File

@ -26,13 +26,14 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.272 2006/07/02 02:23:20 momjian Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.273 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/reloptions.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "catalog/heap.h" #include "catalog/heap.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
@ -45,8 +46,8 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "parser/parse_clause.h"
#include "parser/parsetree.h" #include "parser/parsetree.h"
#include "parser/parse_clause.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/guc.h" #include "utils/guc.h"
@ -543,7 +544,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
{ {
do_select_into = true; do_select_into = true;
estate->es_select_into = true; estate->es_select_into = true;
estate->es_into_oids = parseTree->intoHasOids; estate->es_into_oids = interpretOidsOption(parseTree->intoOptions);
} }
/* /*
@ -727,10 +728,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
char *intoName; char *intoName;
Oid namespaceId; Oid namespaceId;
Oid tablespaceId; Oid tablespaceId;
Datum reloptions;
AclResult aclresult; AclResult aclresult;
Oid intoRelationId; Oid intoRelationId;
TupleDesc tupdesc; TupleDesc tupdesc;
ArrayType *options;
/* /*
* Check consistency of arguments * Check consistency of arguments
@ -770,6 +771,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/* note InvalidOid is OK in this case */ /* note InvalidOid is OK in this case */
} }
/* Parse and validate any reloptions */
reloptions = transformRelOptions((Datum) 0,
parseTree->intoOptions,
true,
false);
(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
/* Check permissions except when using the database's default */ /* Check permissions except when using the database's default */
if (OidIsValid(tablespaceId)) if (OidIsValid(tablespaceId))
{ {
@ -788,7 +796,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
*/ */
tupdesc = CreateTupleDescCopy(tupType); tupdesc = CreateTupleDescCopy(tupType);
options = OptionBuild(NULL, parseTree->intoOptions);
intoRelationId = heap_create_with_catalog(intoName, intoRelationId = heap_create_with_catalog(intoName,
namespaceId, namespaceId,
tablespaceId, tablespaceId,
@ -800,10 +807,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
true, true,
0, 0,
parseTree->intoOnCommit, parseTree->intoOnCommit,
allowSystemTableMods, reloptions,
options); allowSystemTableMods);
if (options)
pfree(options);
FreeTupleDesc(tupdesc); FreeTupleDesc(tupdesc);

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.341 2006/07/02 05:17:26 neilc Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.342 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1680,7 +1680,6 @@ _copyQuery(Query *from)
COPY_NODE_FIELD(utilityStmt); COPY_NODE_FIELD(utilityStmt);
COPY_SCALAR_FIELD(resultRelation); COPY_SCALAR_FIELD(resultRelation);
COPY_NODE_FIELD(into); COPY_NODE_FIELD(into);
COPY_SCALAR_FIELD(intoHasOids);
COPY_NODE_FIELD(intoOptions); COPY_NODE_FIELD(intoOptions);
COPY_SCALAR_FIELD(intoOnCommit); COPY_SCALAR_FIELD(intoOnCommit);
COPY_STRING_FIELD(intoTableSpaceName); COPY_STRING_FIELD(intoTableSpaceName);
@ -2641,7 +2640,6 @@ _copyExecuteStmt(ExecuteStmt *from)
COPY_STRING_FIELD(name); COPY_STRING_FIELD(name);
COPY_NODE_FIELD(into); COPY_NODE_FIELD(into);
COPY_SCALAR_FIELD(into_has_oids);
COPY_NODE_FIELD(intoOptions); COPY_NODE_FIELD(intoOptions);
COPY_SCALAR_FIELD(into_on_commit); COPY_SCALAR_FIELD(into_on_commit);
COPY_STRING_FIELD(into_tbl_space); COPY_STRING_FIELD(into_tbl_space);

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.275 2006/07/02 05:17:26 neilc Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.276 2006/07/03 22:45:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -658,7 +658,6 @@ _equalQuery(Query *a, Query *b)
COMPARE_NODE_FIELD(utilityStmt); COMPARE_NODE_FIELD(utilityStmt);
COMPARE_SCALAR_FIELD(resultRelation); COMPARE_SCALAR_FIELD(resultRelation);
COMPARE_NODE_FIELD(into); COMPARE_NODE_FIELD(into);
COMPARE_SCALAR_FIELD(intoHasOids);
COMPARE_NODE_FIELD(intoOptions); COMPARE_NODE_FIELD(intoOptions);
COMPARE_SCALAR_FIELD(intoOnCommit); COMPARE_SCALAR_FIELD(intoOnCommit);
COMPARE_STRING_FIELD(intoTableSpaceName); COMPARE_STRING_FIELD(intoTableSpaceName);
@ -1474,7 +1473,6 @@ _equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b)
{ {
COMPARE_STRING_FIELD(name); COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(into); COMPARE_NODE_FIELD(into);
COMPARE_SCALAR_FIELD(into_has_oids);
COMPARE_NODE_FIELD(intoOptions); COMPARE_NODE_FIELD(intoOptions);
COMPARE_SCALAR_FIELD(into_on_commit); COMPARE_SCALAR_FIELD(into_on_commit);
COMPARE_STRING_FIELD(into_tbl_space); COMPARE_STRING_FIELD(into_tbl_space);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.276 2006/07/02 02:23:20 momjian Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.277 2006/07/03 22:45:39 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
@ -1509,7 +1509,6 @@ _outQuery(StringInfo str, Query *node)
WRITE_INT_FIELD(resultRelation); WRITE_INT_FIELD(resultRelation);
WRITE_NODE_FIELD(into); WRITE_NODE_FIELD(into);
WRITE_BOOL_FIELD(intoHasOids);
WRITE_NODE_FIELD(intoOptions); WRITE_NODE_FIELD(intoOptions);
WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction); WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction);
WRITE_STRING_FIELD(intoTableSpaceName); WRITE_STRING_FIELD(intoTableSpaceName);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.190 2006/07/02 02:23:20 momjian Exp $ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.191 2006/07/03 22:45:39 tgl Exp $
* *
* NOTES * NOTES
* Path and Plan nodes do not have any readfuncs support, because we * Path and Plan nodes do not have any readfuncs support, because we
@ -140,7 +140,6 @@ _readQuery(void)
READ_NODE_FIELD(utilityStmt); READ_NODE_FIELD(utilityStmt);
READ_INT_FIELD(resultRelation); READ_INT_FIELD(resultRelation);
READ_NODE_FIELD(into); READ_NODE_FIELD(into);
READ_BOOL_FIELD(intoHasOids);
READ_NODE_FIELD(intoOptions); READ_NODE_FIELD(intoOptions);
READ_ENUM_FIELD(intoOnCommit, OnCommitAction); READ_ENUM_FIELD(intoOnCommit, OnCommitAction);
READ_STRING_FIELD(intoTableSpaceName); READ_STRING_FIELD(intoTableSpaceName);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.337 2006/07/02 02:23:20 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.338 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1882,7 +1882,6 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
if (stmt->intoColNames) if (stmt->intoColNames)
applyColumnNames(qry->targetList, stmt->intoColNames); applyColumnNames(qry->targetList, stmt->intoColNames);
qry->intoHasOids = interpretOidsOption(stmt->intoOptions);
qry->intoOptions = copyObject(stmt->intoOptions); qry->intoOptions = copyObject(stmt->intoOptions);
qry->intoOnCommit = stmt->intoOnCommit; qry->intoOnCommit = stmt->intoOnCommit;
qry->intoTableSpaceName = stmt->intoTableSpaceName; qry->intoTableSpaceName = stmt->intoTableSpaceName;
@ -2754,8 +2753,6 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
paramtypes = FetchPreparedStatementParams(stmt->name); paramtypes = FetchPreparedStatementParams(stmt->name);
stmt->into_has_oids = interpretOidsOption(stmt->intoOptions);
if (stmt->params || paramtypes) if (stmt->params || paramtypes)
{ {
int nparams = list_length(stmt->params); int nparams = list_length(stmt->params);

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.550 2006/07/02 02:23:21 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.551 2006/07/03 22:45:39 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -232,7 +232,7 @@ static void doNegateFloat(Value *v);
func_as createfunc_opt_list alterfunc_opt_list func_as createfunc_opt_list alterfunc_opt_list
aggr_args aggr_args_list old_aggr_definition old_aggr_list aggr_args aggr_args_list old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti 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 sort_clause opt_sort_clause sortby_list index_params
name_list from_clause from_list opt_array_bounds name_list from_clause from_list opt_array_bounds
qualified_name_list any_name any_name_list qualified_name_list any_name any_name_list
@ -1562,25 +1562,15 @@ alter_rel_cmd:
| SET definition | SET definition
{ {
AlterTableCmd *n = makeNode(AlterTableCmd); AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_SetOptions; n->subtype = AT_SetRelOptions;
n->def = (Node *)$2; n->def = (Node *)$2;
$$ = (Node *)n; $$ = (Node *)n;
} }
/* ALTER [TABLE|INDEX] <name> RESET (...) */
| RESET definition | RESET definition
{ {
AlterTableCmd *n; AlterTableCmd *n = makeNode(AlterTableCmd);
ListCell *cell; n->subtype = AT_ResetRelOptions;
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; n->def = (Node *)$2;
$$ = (Node *)n; $$ = (Node *)n;
} }
@ -1919,7 +1909,7 @@ ColConstraintElem:
n->indexspace = NULL; n->indexspace = NULL;
$$ = (Node *)n; $$ = (Node *)n;
} }
| UNIQUE OptConsTableSpace | UNIQUE opt_definition OptConsTableSpace
{ {
Constraint *n = makeNode(Constraint); Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE; n->contype = CONSTR_UNIQUE;
@ -1927,7 +1917,8 @@ ColConstraintElem:
n->raw_expr = NULL; n->raw_expr = NULL;
n->cooked_expr = NULL; n->cooked_expr = NULL;
n->keys = NULL; n->keys = NULL;
n->indexspace = $2; n->options = $2;
n->indexspace = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
| PRIMARY KEY opt_definition OptConsTableSpace | PRIMARY KEY opt_definition OptConsTableSpace
@ -2100,7 +2091,7 @@ ConstraintElem:
n->indexspace = NULL; n->indexspace = NULL;
$$ = (Node *)n; $$ = (Node *)n;
} }
| UNIQUE '(' columnList ')' OptConsTableSpace | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
{ {
Constraint *n = makeNode(Constraint); Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE; n->contype = CONSTR_UNIQUE;
@ -2108,7 +2099,8 @@ ConstraintElem:
n->raw_expr = NULL; n->raw_expr = NULL;
n->cooked_expr = NULL; n->cooked_expr = NULL;
n->keys = $3; n->keys = $3;
n->indexspace = $5; n->options = $5;
n->indexspace = $6;
$$ = (Node *)n; $$ = (Node *)n;
} }
| PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
@ -2214,13 +2206,12 @@ OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; }
; ;
/* WITH (options) is preferred, WITH OIDS and WITHOUT OIDS are legacy forms */
OptWith: OptWith:
WITH OIDS { $$ = list_make1(defWithOids(true)); } WITH definition { $$ = $2; }
| WITHOUT OIDS { $$ = list_make1(defWithOids(false)); } | WITH OIDS { $$ = list_make1(defWithOids(true)); }
| WITH definition { $$ = $2; } | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); }
| WITH OIDS WITH definition { $$ = lappend($4, defWithOids(true)); } | /*EMPTY*/ { $$ = NIL; }
| WITHOUT OIDS WITH definition { $$ = lappend($4, defWithOids(false)); }
| /*EMPTY*/ { $$ = NIL; }
; ;
OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; } OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; }
@ -2874,6 +2865,8 @@ def_elem: ColLabel '=' def_arg
/* Note: any simple identifier will be returned as a type name! */ /* Note: any simple identifier will be returned as a type name! */
def_arg: func_type { $$ = (Node *)$1; } def_arg: func_type { $$ = (Node *)$1; }
| func_name_keyword { $$ = (Node *)makeString(pstrdup($1)); }
| reserved_keyword { $$ = (Node *)makeString(pstrdup($1)); }
| qual_all_Op { $$ = (Node *)$1; } | qual_all_Op { $$ = (Node *)$1; }
| NumericOnly { $$ = (Node *)$1; } | NumericOnly { $$ = (Node *)$1; }
| Sconst { $$ = (Node *)makeString($1); } | Sconst { $$ = (Node *)makeString($1); }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.150 2006/07/02 02:23:21 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.151 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -34,7 +34,6 @@
#include "rewrite/rewriteManip.h" #include "rewrite/rewriteManip.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/memutils.h"
#define ORDER_CLAUSE 0 #define ORDER_CLAUSE 0
@ -66,8 +65,6 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar); Var *l_colvar, Var *r_colvar);
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List **tlist, int clause); List **tlist, int clause);
static bool OptionMatches(text *t, const char* kw, char **str, Size *len);
static Datum OptionToText(DefElem *def);
/* /*
@ -216,18 +213,18 @@ interpretInhOption(InhOption inhOpt)
} }
/* /*
* Given a List that indicates whether WITH / WITHOUT OIDS was * Given a relation-options list (of DefElems), return true iff the specified
* specified by the user, return true iff the specified table/result * table/result set should be created with OIDs. This needs to be done after
* set should be created with OIDs. This needs to be done after * parsing the query string because the return value can depend upon the
* parsing the query string because the return value can depend upon * default_with_oids GUC var.
* the default_with_oids GUC var.
*/ */
bool bool
interpretOidsOption(List *options) interpretOidsOption(List *defList)
{ {
ListCell *cell; ListCell *cell;
foreach(cell, options) /* Scan list to see if OIDS was included */
foreach(cell, defList)
{ {
DefElem *def = (DefElem *) lfirst(cell); DefElem *def = (DefElem *) lfirst(cell);
@ -235,263 +232,10 @@ interpretOidsOption(List *options)
return defGetBoolean(def); return defGetBoolean(def);
} }
/* oids option is not specified. */ /* OIDS option was not specified, so use default. */
return default_with_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;
}
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:;
}
}
/* /*
* Extract all not-in-common columns from column lists of a source table * Extract all not-in-common columns from column lists of a source table
*/ */

View File

@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees * ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text * back to source text
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.225 2006/07/02 02:23:21 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.226 2006/07/03 22:45:39 tgl Exp $
**********************************************************************/ **********************************************************************/
#include "postgres.h" #include "postgres.h"
@ -757,20 +757,23 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
} }
if (!colno) if (!colno)
{
appendStringInfoChar(&buf, ')'); appendStringInfoChar(&buf, ')');
/* /*
* If it has options, append "WITH (options)" * If it has options, append "WITH (options)"
*/ */
str = flatten_reloptions(indexrelid); str = flatten_reloptions(indexrelid);
if (str) if (str)
{ {
appendStringInfo(&buf, " WITH (%s)", str); appendStringInfo(&buf, " WITH (%s)", str);
pfree(str); pfree(str);
} }
/*
* XXX we don't include the tablespace ... this is for pg_dump
*/
if (!colno)
{
/* /*
* If it's a partial index, decompile and append the predicate * If it's a partial index, decompile and append the predicate
*/ */
@ -1020,6 +1023,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
if (fullCommand && OidIsValid(conForm->conrelid)) if (fullCommand && OidIsValid(conForm->conrelid))
{ {
char *options = flatten_reloptions(conForm->conrelid); char *options = flatten_reloptions(conForm->conrelid);
if (options) if (options)
{ {
appendStringInfo(&buf, " WITH (%s)", options); appendStringInfo(&buf, " WITH (%s)", options);
@ -4937,35 +4941,42 @@ string_to_text(char *str)
return result; return result;
} }
/*
* Generate a C string representing a relation's reloptions, or NULL if none.
*/
static char * static char *
flatten_reloptions(Oid relid) flatten_reloptions(Oid relid)
{ {
HeapTuple tuple;
char *result = NULL; char *result = NULL;
HeapTuple tuple;
Datum reloptions;
bool isnull;
tuple = SearchSysCache(RELOID, tuple = SearchSysCache(RELOID,
ObjectIdGetDatum(relid), ObjectIdGetDatum(relid),
0, 0, 0); 0, 0, 0);
if (tuple) if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for relation %u", relid);
reloptions = SysCacheGetAttr(RELOID, tuple,
Anum_pg_class_reloptions, &isnull);
if (!isnull)
{ {
bool isnull; Datum sep,
Datum reloptions; txt;
reloptions = SysCacheGetAttr(RELOID, tuple,
Anum_pg_class_reloptions, &isnull); /*
if (!isnull) * We want to use array_to_text(reloptions, ', ') --- but
{ * DirectFunctionCall2(array_to_text) does not work, because
Datum sep, * array_to_text() relies on flinfo to be valid. So use
txt; * OidFunctionCall2.
sep = DirectFunctionCall1(textin, CStringGetDatum(", ")); */
/* sep = DirectFunctionCall1(textin, CStringGetDatum(", "));
* OID 395 = array_to_text. txt = OidFunctionCall2(F_ARRAY_TO_TEXT, reloptions, sep);
* DirectFunctionCall2(array_to_text) is not available here. result = DatumGetCString(DirectFunctionCall1(textout, txt));
*/
txt = OidFunctionCall2(395, reloptions, sep);
result = DatumGetCString(DirectFunctionCall1(textout, txt));
}
ReleaseSysCache(tuple);
} }
ReleaseSysCache(tuple);
return result; return result;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.243 2006/07/02 02:23:21 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.244 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -32,6 +32,7 @@
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/reloptions.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
@ -47,8 +48,6 @@
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h" #include "catalog/pg_rewrite.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
@ -56,7 +55,6 @@
#include "optimizer/prep.h" #include "optimizer/prep.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/catcache.h" #include "utils/catcache.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
@ -186,17 +184,19 @@ static void RelationClearRelation(Relation relation, bool rebuild);
static void RelationReloadClassinfo(Relation relation); static void RelationReloadClassinfo(Relation relation);
static void RelationFlushRelation(Relation relation); static void RelationFlushRelation(Relation relation);
static bool load_relcache_init_file(void); 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 write_relcache_init_file(void);
static void write_item(const void *data, Size len, FILE *fp);
static void formrdesc(const char *relationName, Oid relationReltype, static void formrdesc(const char *relationName, Oid relationReltype,
bool hasoids, int natts, FormData_pg_attribute *att); bool hasoids, int natts, FormData_pg_attribute *att);
static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK); static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK);
static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp); static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp);
static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
static void RelationBuildTupleDesc(Relation relation); static void RelationBuildTupleDesc(Relation relation);
static Relation RelationBuildDesc(Oid targetRelId, Relation oldrelation); static Relation RelationBuildDesc(Oid targetRelId, Relation oldrelation);
static void RelationInitPhysicalAddr(Relation relation); static void RelationInitPhysicalAddr(Relation relation);
static TupleDesc GetPgClassDescriptor(void);
static TupleDesc GetPgIndexDescriptor(void); static TupleDesc GetPgIndexDescriptor(void);
static void AttrDefaultFetch(Relation relation); static void AttrDefaultFetch(Relation relation);
static void CheckConstraintFetch(Relation relation); static void CheckConstraintFetch(Relation relation);
@ -210,7 +210,6 @@ static void IndexSupportInitialize(oidvector *indclass,
static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid, static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
StrategyNumber numStrats, StrategyNumber numStrats,
StrategyNumber numSupport); StrategyNumber numSupport);
static void RelationParseOptions(Relation relation, HeapTuple tuple);
/* /*
@ -303,10 +302,13 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
* Copy the relation tuple form * Copy the relation tuple form
* *
* We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE. * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE.
* relacl is NOT stored in the relcache --- there'd be little point in it, * The variable-length fields (relacl, reloptions) are NOT stored in the
* since we don't copy the tuple's nullvalues bitmap and hence wouldn't * relcache --- there'd be little point in it, since we don't copy the
* know if the value is valid ... bottom line is that relacl *cannot* be * tuple's nulls bitmap and hence wouldn't know if the values are valid.
* retrieved from the relcache. Get it from the syscache if you need it. * Bottom line is that relacl *cannot* be retrieved from the relcache.
* Get it from the syscache if you need it. The same goes for the
* original form of reloptions (however, we do store the parsed form
* of reloptions in rd_options).
*/ */
relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE); relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
@ -314,7 +316,6 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
/* initialize relation tuple form */ /* initialize relation tuple form */
relation->rd_rel = relationForm; relation->rd_rel = relationForm;
relation->rd_options = NULL;
/* and allocate attribute tuple form storage */ /* and allocate attribute tuple form storage */
relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts, relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts,
@ -328,49 +329,71 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp)
} }
/* /*
* RelationParseOptions * RelationParseRelOptions
* Convert pg_class.reloptions into pre-parsed rd_options
*
* tuple is the real pg_class tuple (not rd_rel!) for relation
*
* Note: rd_rel and (if an index) rd_am must be valid already
*/ */
static void static void
RelationParseOptions(Relation relation, HeapTuple tuple) RelationParseRelOptions(Relation relation, HeapTuple tuple)
{ {
ArrayType *options; Datum datum;
bool isnull;
bytea *options;
Assert(tuple); relation->rd_options = NULL;
/* Fall out if relkind should not have options */
switch (relation->rd_rel->relkind) switch (relation->rd_rel->relkind)
{ {
case RELKIND_RELATION: case RELKIND_RELATION:
case RELKIND_TOASTVALUE: case RELKIND_TOASTVALUE:
case RELKIND_UNCATALOGED: case RELKIND_UNCATALOGED:
case RELKIND_INDEX: case RELKIND_INDEX:
break; break;
default: default:
/* other relation should not have options. */ return;
relation->rd_options = NULL;
return;
} }
/* SysCacheGetAttr is not available here. */ /*
if (heap_attisnull(tuple, Anum_pg_class_reloptions)) * Fetch reloptions from tuple; have to use a hardwired descriptor
options = NULL; * because we might not have any other for pg_class yet (consider
else * executing this code for pg_class itself)
options = (ArrayType *) ((Form_pg_class) GETSTRUCT(tuple))->reloptions; */
datum = fastgetattr(tuple,
Anum_pg_class_reloptions,
GetPgClassDescriptor(),
&isnull);
if (isnull)
return;
/* Parse into appropriate format; don't error out here */
switch (relation->rd_rel->relkind) switch (relation->rd_rel->relkind)
{ {
case RELKIND_RELATION: case RELKIND_RELATION:
case RELKIND_TOASTVALUE: case RELKIND_TOASTVALUE:
case RELKIND_UNCATALOGED: case RELKIND_UNCATALOGED:
relation->rd_options = heap_option( options = heap_reloptions(relation->rd_rel->relkind, datum,
relation->rd_rel->relkind, options); false);
break; break;
case RELKIND_INDEX: case RELKIND_INDEX:
relation->rd_options = index_option( options = index_reloptions(relation->rd_am->amoptions, datum,
relation->rd_am->amoption, options); false);
break; break;
default: default:
/* should not happen */ Assert(false); /* can't get here */
break; options = NULL; /* keep compiler quiet */
break;
}
/* Copy parsed data into CacheMemoryContext */
if (options)
{
relation->rd_options = MemoryContextAlloc(CacheMemoryContext,
VARSIZE(options));
memcpy(relation->rd_options, options, VARSIZE(options));
} }
} }
@ -820,6 +843,9 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation)
if (OidIsValid(relation->rd_rel->relam)) if (OidIsValid(relation->rd_rel->relam))
RelationInitIndexAccessInfo(relation); RelationInitIndexAccessInfo(relation);
/* extract reloptions if any */
RelationParseRelOptions(relation, pg_class_tuple);
/* /*
* initialize the relation lock manager information * initialize the relation lock manager information
*/ */
@ -833,9 +859,6 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation)
/* make sure relation is marked as having no open file yet */ /* make sure relation is marked as having no open file yet */
relation->rd_smgr = NULL; relation->rd_smgr = NULL;
/* Build AM-specific fields. */
RelationParseOptions(relation, pg_class_tuple);
/* /*
* now we can free the memory allocated for pg_class_tuple * now we can free the memory allocated for pg_class_tuple
*/ */
@ -1266,7 +1289,6 @@ formrdesc(const char *relationName, Oid relationReltype,
* data from pg_class and replace what we've done here. * data from pg_class and replace what we've done here.
*/ */
relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
relation->rd_options = NULL;
namestrcpy(&relation->rd_rel->relname, relationName); namestrcpy(&relation->rd_rel->relname, relationName);
relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE; relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
@ -1354,11 +1376,6 @@ formrdesc(const char *relationName, Oid relationReltype,
relation->rd_rel->relhasindex = true; 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 * add new reldesc to relcache
*/ */
@ -1537,9 +1554,11 @@ RelationReloadClassinfo(Relation relation)
RelationGetRelid(relation)); RelationGetRelid(relation));
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE); memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
/* Reload reloptions in case they changed */
if (relation->rd_options) if (relation->rd_options)
pfree(relation->rd_options); pfree(relation->rd_options);
RelationParseOptions(relation, pg_class_tuple); RelationParseRelOptions(relation, pg_class_tuple);
/* done with pg_class tuple */
heap_freetuple(pg_class_tuple); heap_freetuple(pg_class_tuple);
/* We must recalculate physical address in case it changed */ /* We must recalculate physical address in case it changed */
RelationInitPhysicalAddr(relation); RelationInitPhysicalAddr(relation);
@ -2178,7 +2197,6 @@ RelationBuildLocalRelation(const char *relname,
* initialize relation tuple form (caller may add/override data later) * initialize relation tuple form (caller may add/override data later)
*/ */
rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
rel->rd_options = NULL;
namestrcpy(&rel->rd_rel->relname, relname); namestrcpy(&rel->rd_rel->relname, relname);
rel->rd_rel->relnamespace = relnamespace; rel->rd_rel->relnamespace = relnamespace;
@ -2412,6 +2430,11 @@ RelationCacheInitializePhase2(void)
Assert(relation->rd_rel != NULL); Assert(relation->rd_rel != NULL);
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE); memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
/* Update rd_options while we have the tuple */
if (relation->rd_options)
pfree(relation->rd_options);
RelationParseRelOptions(relation, htup);
/* /*
* Also update the derived fields in rd_att. * Also update the derived fields in rd_att.
*/ */
@ -2450,49 +2473,72 @@ RelationCacheInitializePhase2(void)
} }
/* /*
* GetPgClassDescriptor -- get a predefined tuple descriptor for pg_class
* GetPgIndexDescriptor -- get a predefined tuple descriptor for pg_index * GetPgIndexDescriptor -- get a predefined tuple descriptor for pg_index
* *
* We need this kluge because we have to be able to access non-fixed-width * We need this kluge because we have to be able to access non-fixed-width
* fields of pg_index before we have the standard catalog caches available. * fields of pg_class and pg_index before we have the standard catalog caches
* We use predefined data that's set up in just the same way as the * available. We use predefined data that's set up in just the same way as
* bootstrapped reldescs used by formrdesc(). The resulting tupdesc is * the bootstrapped reldescs used by formrdesc(). The resulting tupdesc is
* not 100% kosher: it does not have the correct rowtype OID in tdtypeid, * not 100% kosher: it does not have the correct rowtype OID in tdtypeid, nor
* nor does it have a TupleConstr field. But it's good enough for the * does it have a TupleConstr field. But it's good enough for the purpose of
* purpose of extracting fields. * extracting fields.
*/ */
static TupleDesc static TupleDesc
GetPgIndexDescriptor(void) BuildHardcodedDescriptor(int natts, Form_pg_attribute attrs, bool hasoids)
{ {
static TupleDesc pgindexdesc = NULL; TupleDesc result;
MemoryContext oldcxt; MemoryContext oldcxt;
int i; int i;
/* Already done? */
if (pgindexdesc)
return pgindexdesc;
oldcxt = MemoryContextSwitchTo(CacheMemoryContext); oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
pgindexdesc = CreateTemplateTupleDesc(Natts_pg_index, false); result = CreateTemplateTupleDesc(natts, hasoids);
pgindexdesc->tdtypeid = RECORDOID; /* not right, but we don't care */ result->tdtypeid = RECORDOID; /* not right, but we don't care */
pgindexdesc->tdtypmod = -1; result->tdtypmod = -1;
for (i = 0; i < Natts_pg_index; i++) for (i = 0; i < natts; i++)
{ {
memcpy(pgindexdesc->attrs[i], memcpy(result->attrs[i], &attrs[i], ATTRIBUTE_TUPLE_SIZE);
&Desc_pg_index[i],
ATTRIBUTE_TUPLE_SIZE);
/* make sure attcacheoff is valid */ /* make sure attcacheoff is valid */
pgindexdesc->attrs[i]->attcacheoff = -1; result->attrs[i]->attcacheoff = -1;
} }
/* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */
pgindexdesc->attrs[0]->attcacheoff = 0; result->attrs[0]->attcacheoff = 0;
/* Note: we don't bother to set up a TupleConstr entry */ /* Note: we don't bother to set up a TupleConstr entry */
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
return result;
}
static TupleDesc
GetPgClassDescriptor(void)
{
static TupleDesc pgclassdesc = NULL;
/* Already done? */
if (pgclassdesc == NULL)
pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
Desc_pg_class,
true);
return pgclassdesc;
}
static TupleDesc
GetPgIndexDescriptor(void)
{
static TupleDesc pgindexdesc = NULL;
/* Already done? */
if (pgindexdesc == NULL)
pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
Desc_pg_index,
false);
return pgindexdesc; return pgindexdesc;
} }
@ -3109,7 +3155,7 @@ load_relcache_init_file(void)
if ((nread = fread(rel->rd_options, 1, len, fp)) != len) if ((nread = fread(rel->rd_options, 1, len, fp)) != len)
goto read_failed; goto read_failed;
if (len != VARATT_SIZE(rel->rd_options)) if (len != VARATT_SIZE(rel->rd_options))
goto read_failed; goto read_failed; /* sanity check */
} }
else else
{ {
@ -3299,15 +3345,6 @@ read_failed:
return false; 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 * Write out a new initialization file with the current contents
* of the relcache. * of the relcache.
@ -3380,13 +3417,13 @@ write_relcache_init_file(void)
/* next, do all the attribute tuple form data entries */ /* next, do all the attribute tuple form data entries */
for (i = 0; i < relform->relnatts; i++) for (i = 0; i < relform->relnatts; i++)
{ {
write_item(rel->rd_att->attrs[i], write_item(rel->rd_att->attrs[i], ATTRIBUTE_TUPLE_SIZE, fp);
ATTRIBUTE_TUPLE_SIZE, fp);
} }
/* next, do the access method specific field */ /* next, do the access method specific field */
write_item(rel->rd_options, write_item(rel->rd_options,
(rel->rd_options ? VARATT_SIZE(rel->rd_options) : 0), fp); (rel->rd_options ? VARATT_SIZE(rel->rd_options) : 0),
fp);
/* If it's an index, there's more to do */ /* If it's an index, there's more to do */
if (rel->rd_rel->relkind == RELKIND_INDEX) if (rel->rd_rel->relkind == RELKIND_INDEX)
@ -3396,18 +3433,21 @@ write_relcache_init_file(void)
/* write the pg_index tuple */ /* write the pg_index tuple */
/* we assume this was created by heap_copytuple! */ /* we assume this was created by heap_copytuple! */
write_item(rel->rd_indextuple, write_item(rel->rd_indextuple,
HEAPTUPLESIZE + rel->rd_indextuple->t_len, fp); HEAPTUPLESIZE + rel->rd_indextuple->t_len,
fp);
/* next, write the access method tuple form */ /* next, write the access method tuple form */
write_item(am, sizeof(FormData_pg_am), fp); write_item(am, sizeof(FormData_pg_am), fp);
/* next, write the vector of operator OIDs */ /* next, write the vector of operator OIDs */
write_item(rel->rd_operator, relform->relnatts * write_item(rel->rd_operator,
(am->amstrategies * sizeof(Oid)), fp); relform->relnatts * (am->amstrategies * sizeof(Oid)),
fp);
/* finally, write the vector of support procedures */ /* finally, write the vector of support procedures */
write_item(rel->rd_support, relform->relnatts * write_item(rel->rd_support,
(am->amsupport * sizeof(RegProcedure)), fp); relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);
} }
/* also make a list of their OIDs, for RelationIdIsInInitFile */ /* also make a list of their OIDs, for RelationIdIsInInitFile */
@ -3463,6 +3503,16 @@ write_relcache_init_file(void)
LWLockRelease(RelCacheInitLock); LWLockRelease(RelCacheInitLock);
} }
/* write a chunk of data preceded by its length */
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");
}
/* /*
* Detect whether a given relation (identified by OID) is one of the ones * Detect whether a given relation (identified by OID) is one of the ones
* we store in the init file. * we store in the init file.

View File

@ -7,14 +7,13 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/genam.h,v 1.61 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/genam.h,v 1.62 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef GENAM_H #ifndef GENAM_H
#define GENAM_H #define GENAM_H
#include "access/heapam.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
@ -145,13 +144,4 @@ extern SysScanDesc systable_beginscan(Relation heapRelation,
extern HeapTuple systable_getnext(SysScanDesc sysscan); extern HeapTuple systable_getnext(SysScanDesc sysscan);
extern void systable_endscan(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 */ #endif /* GENAM_H */

View File

@ -3,7 +3,7 @@
* header file for postgres inverted index access method implementation. * header file for postgres inverted index access method implementation.
* *
* Copyright (c) 2006, PostgreSQL Global Development Group * Copyright (c) 2006, PostgreSQL Global Development Group
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.2 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.3 2006/07/03 22:45:39 tgl Exp $
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
*/ */
@ -213,7 +213,7 @@ typedef struct ginxlogDeletePage {
} ginxlogDeletePage; } ginxlogDeletePage;
/* ginutil.c */ /* ginutil.c */
extern Datum ginoption(PG_FUNCTION_ARGS); extern Datum ginoptions(PG_FUNCTION_ARGS);
extern void initGinState( GinState *state, Relation index ); extern void initGinState( GinState *state, Relation index );
extern Buffer GinNewBuffer(Relation index); extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f); extern void GinInitBuffer(Buffer b, uint32 f);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.19 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.20 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -272,7 +272,10 @@ extern Datum gistgetmulti(PG_FUNCTION_ARGS);
#define GiSTPageSize \ #define GiSTPageSize \
( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) ) ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) )
extern Datum gistoption(PG_FUNCTION_ARGS); #define GIST_MIN_FILLFACTOR 50
#define GIST_DEFAULT_FILLFACTOR 90
extern Datum gistoptions(PG_FUNCTION_ARGS);
extern bool gistfitpage(IndexTuple *itvec, int len); extern bool gistfitpage(IndexTuple *itvec, int len);
extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace); extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
extern void gistcheckpage(Relation rel, Buffer buf); extern void gistcheckpage(Relation rel, Buffer buf);
@ -330,4 +333,5 @@ extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup,
int len, GISTSTATE *giststate, int len, GISTSTATE *giststate,
GistSplitVector *v, GistEntryVector *entryvec, GistSplitVector *v, GistEntryVector *entryvec,
int attno); int attno);
#endif /* GIST_PRIVATE_H */ #endif /* GIST_PRIVATE_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/hash.h,v 1.70 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.71 2006/07/03 22:45:39 tgl Exp $
* *
* NOTES * NOTES
* modeled after Margo Seltzer's hash implementation for unix. * modeled after Margo Seltzer's hash implementation for unix.
@ -167,6 +167,9 @@ typedef HashMetaPageData *HashMetaPage;
MAXALIGN(sizeof(HashPageOpaqueData)) - \ MAXALIGN(sizeof(HashPageOpaqueData)) - \
sizeof(ItemIdData)) sizeof(ItemIdData))
#define HASH_MIN_FILLFACTOR 50
#define HASH_DEFAULT_FILLFACTOR 75
/* /*
* Constants * Constants
*/ */
@ -234,7 +237,7 @@ extern Datum hashmarkpos(PG_FUNCTION_ARGS);
extern Datum hashrestrpos(PG_FUNCTION_ARGS); extern Datum hashrestrpos(PG_FUNCTION_ARGS);
extern Datum hashbulkdelete(PG_FUNCTION_ARGS); extern Datum hashbulkdelete(PG_FUNCTION_ARGS);
extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS); extern Datum hashvacuumcleanup(PG_FUNCTION_ARGS);
extern Datum hashoption(PG_FUNCTION_ARGS); extern Datum hashoptions(PG_FUNCTION_ARGS);
/* /*
* Datatype-specific hash functions in hashfunc.c. * Datatype-specific hash functions in hashfunc.c.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.113 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.114 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -22,7 +22,6 @@
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
#include "storage/block.h" #include "storage/block.h"
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "utils/array.h"
#include "utils/rel.h" #include "utils/rel.h"
#include "utils/tqual.h" #include "utils/tqual.h"
@ -228,32 +227,4 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
extern HeapTuple heap_addheader(int natts, bool withoid, extern HeapTuple heap_addheader(int natts, bool withoid,
Size structlen, void *structure); 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 */ #endif /* HEAPAM_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.99 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.100 2006/07/03 22:45:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -106,6 +106,13 @@ typedef struct BTMetaPageData
sizeof(PageHeaderData) - \ sizeof(PageHeaderData) - \
MAXALIGN(sizeof(BTPageOpaqueData))) / 3 - sizeof(ItemIdData)) MAXALIGN(sizeof(BTPageOpaqueData))) / 3 - sizeof(ItemIdData))
/*
* Because of above, min fillfactor can't be less than 2/3rds; see notes in
* nbtsort.c before you change these!
*/
#define BTREE_MIN_FILLFACTOR 70
#define BTREE_DEFAULT_FILLFACTOR 90
/* /*
* Test whether two btree entries are "the same". * Test whether two btree entries are "the same".
* *
@ -453,7 +460,7 @@ extern Datum btmarkpos(PG_FUNCTION_ARGS);
extern Datum btrestrpos(PG_FUNCTION_ARGS); extern Datum btrestrpos(PG_FUNCTION_ARGS);
extern Datum btbulkdelete(PG_FUNCTION_ARGS); extern Datum btbulkdelete(PG_FUNCTION_ARGS);
extern Datum btvacuumcleanup(PG_FUNCTION_ARGS); extern Datum btvacuumcleanup(PG_FUNCTION_ARGS);
extern Datum btoption(PG_FUNCTION_ARGS); extern Datum btoptions(PG_FUNCTION_ARGS);
/* /*
* prototypes for functions in nbtinsert.c * prototypes for functions in nbtinsert.c

View File

@ -0,0 +1,38 @@
/*-------------------------------------------------------------------------
*
* reloptions.h
* Core support for relation options (pg_class.reloptions)
*
* Note: the functions dealing with text-array reloptions values declare
* them as Datum, not ArrayType *, to avoid needing to include array.h
* into a lot of low-level code.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.1 2006/07/03 22:45:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RELOPTIONS_H
#define RELOPTIONS_H
#include "nodes/pg_list.h"
extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool ignoreOids, bool isReset);
extern void parseRelOptions(Datum options, int numkeywords,
const char * const *keywords,
char **values, bool validate);
extern bytea *default_reloptions(Datum reloptions, bool validate,
int minFillfactor, int defaultFillfactor);
extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions,
bool validate);
#endif /* RELOPTIONS_H */

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.335 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.336 2006/07/03 22:45:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200607011 #define CATALOG_VERSION_NO 200607021
#endif #endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.83 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.84 2006/07/03 22:45:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -17,7 +17,6 @@
#include "catalog/pg_attribute.h" #include "catalog/pg_attribute.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "parser/parse_node.h" #include "parser/parse_node.h"
#include "utils/array.h"
#include "utils/rel.h" #include "utils/rel.h"
@ -55,8 +54,8 @@ extern Oid heap_create_with_catalog(const char *relname,
bool oidislocal, bool oidislocal,
int oidinhcount, int oidinhcount,
OnCommitAction oncommit, OnCommitAction oncommit,
bool allow_system_table_mods, Datum reloptions,
ArrayType *options); bool allow_system_table_mods);
extern void heap_drop_with_catalog(Oid relid); extern void heap_drop_with_catalog(Oid relid);
@ -66,6 +65,11 @@ extern void heap_truncate_check_FKs(List *relations, bool tempTables);
extern List *heap_truncate_find_FKs(List *relationIds); extern List *heap_truncate_find_FKs(List *relationIds);
extern void InsertPgClassTuple(Relation pg_class_desc,
Relation new_rel_desc,
Oid new_rel_oid,
Datum reloptions);
extern List *AddRelationRawConstraints(Relation rel, extern List *AddRelationRawConstraints(Relation rel,
List *rawColDefaults, List *rawColDefaults,
List *rawConstraints); List *rawConstraints);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.67 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.68 2006/07/03 22:45:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -17,7 +17,6 @@
#include "access/itup.h" #include "access/itup.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "nodes/execnodes.h" #include "nodes/execnodes.h"
#include "utils/array.h"
#define DEFAULT_INDEX_TYPE "btree" #define DEFAULT_INDEX_TYPE "btree"
@ -38,7 +37,7 @@ extern Oid index_create(Oid heapRelationId,
Oid accessMethodObjectId, Oid accessMethodObjectId,
Oid tableSpaceId, Oid tableSpaceId,
Oid *classObjectId, Oid *classObjectId,
List *options, Datum reloptions,
bool isprimary, bool isprimary,
bool istoast, bool istoast,
bool isconstraint, bool isconstraint,
@ -72,6 +71,4 @@ extern double IndexBuildHeapScan(Relation heapRelation,
extern void reindex_index(Oid indexId); extern void reindex_index(Oid indexId);
extern bool reindex_relation(Oid relid, bool toast_too); extern bool reindex_relation(Oid relid, bool toast_too);
extern bytea *index_option(RegProcedure amoption, ArrayType *options);
#endif /* INDEX_H */ #endif /* INDEX_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.44 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_am.h,v 1.45 2006/07/03 22:45:40 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -65,7 +65,7 @@ CATALOG(pg_am,2601)
regproc ambulkdelete; /* bulk-delete function */ regproc ambulkdelete; /* bulk-delete function */
regproc amvacuumcleanup; /* post-VACUUM cleanup function */ regproc amvacuumcleanup; /* post-VACUUM cleanup function */
regproc amcostestimate; /* estimate cost of an indexscan */ regproc amcostestimate; /* estimate cost of an indexscan */
regproc amoption; /* parse AM-specific parameters */ regproc amoptions; /* parse AM-specific parameters */
} FormData_pg_am; } FormData_pg_am;
/* ---------------- /* ----------------
@ -103,23 +103,23 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_ambulkdelete 21 #define Anum_pg_am_ambulkdelete 21
#define Anum_pg_am_amvacuumcleanup 22 #define Anum_pg_am_amvacuumcleanup 22
#define Anum_pg_am_amcostestimate 23 #define Anum_pg_am_amcostestimate 23
#define Anum_pg_am_amoption 24 #define Anum_pg_am_amoptions 24
/* ---------------- /* ----------------
* initial contents of pg_am * 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 btoption )); 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 btoptions ));
DESCR("b-tree index access method"); DESCR("b-tree index access method");
#define BTREE_AM_OID 403 #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 hashoption )); 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 hashoptions ));
DESCR("hash index access method"); DESCR("hash index access method");
#define HASH_AM_OID 405 #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 gistoption )); 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 gistoptions ));
DESCR("GiST index access method"); DESCR("GiST index access method");
#define GIST_AM_OID 783 #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 ginoption )); 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 ginoptions ));
DESCR("GIN index access method"); DESCR("GIN index access method");
#define GIN_AM_OID 2742 #define GIN_AM_OID 2742

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.121 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.122 2006/07/03 22:45:40 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -404,8 +404,8 @@ DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
{ 1259, {"relhaspkey"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"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, {"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, {"relhassubclass"},16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, 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, 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 } { 1259, {"reloptions"}, 1009, -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 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 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
@ -431,8 +431,8 @@ DATA(insert ( 1259 relhasoids 16 -1 1 21 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relhaspkey 16 -1 1 22 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 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 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 relhassubclass 16 -1 1 24 0 -1 -1 t p c t 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 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 reloptions 1009 -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 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 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)); DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.93 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.94 2006/07/03 22:45:40 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -31,15 +31,6 @@
* typedef struct FormData_pg_class * typedef struct FormData_pg_class
* ---------------- * ----------------
*/ */
/* ----------------
* This structure is actually variable-length (the last attribute is
* a POSTGRES array). Hence, sizeof(FormData_pg_class) does not
* necessarily match the actual length of the structure. Furthermore
* relacl may be a NULL field. Hence, you MUST use heap_getattr()
* to get the relacl field ... and don't forget to check isNull.
* ----------------
*/
#define RelationRelationId 1259 #define RelationRelationId 1259
CATALOG(pg_class,1259) BKI_BOOTSTRAP CATALOG(pg_class,1259) BKI_BOOTSTRAP
@ -75,12 +66,17 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP
bool relhasrules; /* has associated rules */ bool relhasrules; /* has associated rules */
bool relhassubclass; /* has derived classes */ bool relhassubclass; /* has derived classes */
/* following fields may or may not be present, see note above! */ /*
text reloptions[1]; /* access method specific data */ * VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
aclitem relacl[1]; /* we declare this just for the catalog */ *
* NOTE: these fields are not present in a relcache entry's rd_rel field.
*/
aclitem relacl[1]; /* access permissions */
text reloptions[1]; /* access-method-specific options */
} FormData_pg_class; } FormData_pg_class;
/* Size of fixed part of pg_class tuples, not counting relacl or padding */ /* Size of fixed part of pg_class tuples, not counting var-length fields */
#define CLASS_TUPLE_SIZE \ #define CLASS_TUPLE_SIZE \
(offsetof(FormData_pg_class,relhassubclass) + sizeof(bool)) (offsetof(FormData_pg_class,relhassubclass) + sizeof(bool))
@ -96,13 +92,6 @@ typedef FormData_pg_class *Form_pg_class;
* ---------------- * ----------------
*/ */
/* ----------------
* Natts_pg_class_fixed is used to tell routines that insert new
* pg_class tuples (as opposed to replacing old ones) that there's no
* relacl field. This is a kluge.
* ----------------
*/
#define Natts_pg_class_fixed 24
#define Natts_pg_class 26 #define Natts_pg_class 26
#define Anum_pg_class_relname 1 #define Anum_pg_class_relname 1
#define Anum_pg_class_relnamespace 2 #define Anum_pg_class_relnamespace 2
@ -128,8 +117,8 @@ typedef FormData_pg_class *Form_pg_class;
#define Anum_pg_class_relhaspkey 22 #define Anum_pg_class_relhaspkey 22
#define Anum_pg_class_relhasrules 23 #define Anum_pg_class_relhasrules 23
#define Anum_pg_class_relhassubclass 24 #define Anum_pg_class_relhassubclass 24
#define Anum_pg_class_reloptions 25 #define Anum_pg_class_relacl 25
#define Anum_pg_class_relacl 26 #define Anum_pg_class_reloptions 26
/* ---------------- /* ----------------
* initial contents of pg_class * initial contents of pg_class

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.414 2006/07/02 02:23:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.415 2006/07/03 22:45:40 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
@ -680,7 +680,7 @@ DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281
DESCR("btree(internal)"); 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_ )); 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)"); DESCR("btree(internal)");
DATA(insert OID = 2785 ( btoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ btoption - _null_ )); DATA(insert OID = 2785 ( btoptions PGNSP PGUID 12 f f t f s 2 17 "1009 16" _null_ _null_ _null_ btoptions - _null_ ));
DESCR("btree(internal)"); 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_ )); DATA(insert OID = 339 ( poly_same PGNSP PGUID 12 f f t f i 2 16 "604 604" _null_ _null_ _null_ poly_same - _null_ ));
@ -799,7 +799,7 @@ DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281
DESCR("hash(internal)"); 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_ )); 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)"); DESCR("hash(internal)");
DATA(insert OID = 2786 ( hashoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ hashoption - _null_ )); DATA(insert OID = 2786 ( hashoptions PGNSP PGUID 12 f f t f s 2 17 "1009 16" _null_ _null_ _null_ hashoptions - _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 f f t f i 1 23 "21" _null_ _null_ _null_ hashint2 - _null_ )); DATA(insert OID = 449 ( hashint2 PGNSP PGUID 12 f f t f i 1 23 "21" _null_ _null_ _null_ hashint2 - _null_ ));
@ -1067,7 +1067,7 @@ DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2
DESCR("gist(internal)"); 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_ )); 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)"); DESCR("gist(internal)");
DATA(insert OID = 2787 ( gistoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ gistoption - _null_ )); DATA(insert OID = 2787 ( gistoptions PGNSP PGUID 12 f f t f s 2 17 "1009 16" _null_ _null_ _null_ gistoptions - _null_ ));
DESCR("gist(internal)"); 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_ )); DATA(insert OID = 784 ( tintervaleq PGNSP PGUID 12 f f t f i 2 16 "704 704" _null_ _null_ _null_ tintervaleq - _null_ ));
@ -3855,7 +3855,7 @@ DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 f f t f v 2 2281 "2281
DESCR("gin(internal)"); 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_ )); 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)"); DESCR("gin(internal)");
DATA(insert OID = 2788 ( ginoption PGNSP PGUID 12 f f t f v 1 2281 "2281" _null_ _null_ _null_ ginoption - _null_ )); DATA(insert OID = 2788 ( ginoptions PGNSP PGUID 12 f f t f s 2 17 "1009 16" _null_ _null_ _null_ ginoptions - _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
/* GIN array support */ /* GIN array support */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.73 2006/07/02 02:23:23 momjian Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.74 2006/07/03 22:45:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -95,7 +95,6 @@ extern int64 defGetInt64(DefElem *def);
extern List *defGetQualifiedName(DefElem *def); extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def); extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def); extern int defGetTypeLength(DefElem *def);
extern DefElem *defWithOids(bool value); extern DefElem *defWithOids(bool value);
#endif /* DEFREM_H */ #endif /* DEFREM_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.314 2006/07/02 02:23:23 momjian Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.315 2006/07/03 22:45:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -92,9 +92,8 @@ typedef struct Query
int resultRelation; /* target relation (index into rtable) */ int resultRelation; /* target relation (index into rtable) */
RangeVar *into; /* target relation for SELECT INTO */ RangeVar *into; /* target relation for SELECT INTO */
bool intoHasOids; /* should target relation contain OIDs? */ List *intoOptions; /* options from WITH clause */
List *intoOptions; /* options passed by WITH */ OnCommitAction intoOnCommit; /* what do we do at COMMIT? */
OnCommitAction intoOnCommit; /* what do we do at COMMIT? */
char *intoTableSpaceName; /* table space to use, or NULL */ char *intoTableSpaceName; /* table space to use, or NULL */
bool hasAggs; /* has aggregates in tlist or havingQual */ bool hasAggs; /* has aggregates in tlist or havingQual */
@ -708,7 +707,7 @@ typedef struct SelectStmt
* lcons(NIL,NIL) for all (SELECT DISTINCT) */ * lcons(NIL,NIL) for all (SELECT DISTINCT) */
RangeVar *into; /* target table (for select into table) */ RangeVar *into; /* target table (for select into table) */
List *intoColNames; /* column names for into table */ List *intoColNames; /* column names for into table */
List *intoOptions; /* options passed by WITH */ List *intoOptions; /* options from WITH clause */
OnCommitAction intoOnCommit; /* what do we do at COMMIT? */ OnCommitAction intoOnCommit; /* what do we do at COMMIT? */
char *intoTableSpaceName; /* table space to use, or NULL */ char *intoTableSpaceName; /* table space to use, or NULL */
List *targetList; /* the target list (of ResTarget) */ List *targetList; /* the target list (of ResTarget) */
@ -861,7 +860,8 @@ typedef enum AlterTableType
AT_DropCluster, /* SET WITHOUT CLUSTER */ AT_DropCluster, /* SET WITHOUT CLUSTER */
AT_DropOids, /* SET WITHOUT OIDS */ AT_DropOids, /* SET WITHOUT OIDS */
AT_SetTableSpace, /* SET TABLESPACE */ AT_SetTableSpace, /* SET TABLESPACE */
AT_SetOptions, /* SET (...) -- AM specific parameters */ AT_SetRelOptions, /* SET (...) -- AM specific parameters */
AT_ResetRelOptions, /* RESET (...) -- AM specific parameters */
AT_EnableTrig, /* ENABLE TRIGGER name */ AT_EnableTrig, /* ENABLE TRIGGER name */
AT_DisableTrig, /* DISABLE TRIGGER name */ AT_DisableTrig, /* DISABLE TRIGGER name */
AT_EnableTrigAll, /* ENABLE TRIGGER ALL */ AT_EnableTrigAll, /* ENABLE TRIGGER ALL */
@ -1017,7 +1017,7 @@ typedef struct CreateStmt
List *inhRelations; /* relations to inherit from (list of List *inhRelations; /* relations to inherit from (list of
* inhRelation) */ * inhRelation) */
List *constraints; /* constraints (list of Constraint nodes) */ List *constraints; /* constraints (list of Constraint nodes) */
List *options; /* options passed by WITH */ List *options; /* options from WITH clause */
OnCommitAction oncommit; /* what do we do at COMMIT? */ OnCommitAction oncommit; /* what do we do at COMMIT? */
char *tablespacename; /* table space to use, or NULL */ char *tablespacename; /* table space to use, or NULL */
} CreateStmt; } CreateStmt;
@ -1075,7 +1075,7 @@ typedef struct Constraint
Node *raw_expr; /* expr, as untransformed parse tree */ Node *raw_expr; /* expr, as untransformed parse tree */
char *cooked_expr; /* expr, as nodeToString representation */ char *cooked_expr; /* expr, as nodeToString representation */
List *keys; /* String nodes naming referenced column(s) */ List *keys; /* String nodes naming referenced column(s) */
List *options; /* options passed by WITH */ List *options; /* options from WITH clause */
char *indexspace; /* index tablespace for PKEY/UNIQUE char *indexspace; /* index tablespace for PKEY/UNIQUE
* constraints; NULL for default */ * constraints; NULL for default */
} Constraint; } Constraint;
@ -1429,7 +1429,7 @@ typedef struct IndexStmt
char *accessMethod; /* name of access method (eg. btree) */ char *accessMethod; /* name of access method (eg. btree) */
char *tableSpace; /* tablespace, or NULL to use parent's */ char *tableSpace; /* tablespace, or NULL to use parent's */
List *indexParams; /* a list of IndexElem */ List *indexParams; /* a list of IndexElem */
List *options; /* options passed by WITH */ List *options; /* options from WITH clause */
Node *whereClause; /* qualification (partial-index predicate) */ Node *whereClause; /* qualification (partial-index predicate) */
List *rangetable; /* range table for qual and/or expressions, List *rangetable; /* range table for qual and/or expressions,
* filled in by transformStmt() */ * filled in by transformStmt() */
@ -1886,8 +1886,7 @@ typedef struct ExecuteStmt
NodeTag type; NodeTag type;
char *name; /* The name of the plan to execute */ char *name; /* The name of the plan to execute */
RangeVar *into; /* Optional table to store results in */ RangeVar *into; /* Optional table to store results in */
bool into_has_oids; /* Merge GUC info with user input */ List *intoOptions; /* Options from WITH clause */
List *intoOptions; /* options passed by WITH */
OnCommitAction into_on_commit; /* What do we do at COMMIT? */ OnCommitAction into_on_commit; /* What do we do at COMMIT? */
char *into_tbl_space; /* Tablespace to use, or NULL */ char *into_tbl_space; /* Tablespace to use, or NULL */
List *params; /* Values to assign to parameters */ List *params; /* Values to assign to parameters */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.45 2006/07/02 02:23:23 momjian Exp $ * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.46 2006/07/03 22:45:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -15,17 +15,12 @@
#define PARSE_CLAUSE_H #define PARSE_CLAUSE_H
#include "parser/parse_node.h" #include "parser/parse_node.h"
#include "utils/array.h"
extern void transformFromClause(ParseState *pstate, List *frmList); extern void transformFromClause(ParseState *pstate, List *frmList);
extern int setTargetTable(ParseState *pstate, RangeVar *relation, extern int setTargetTable(ParseState *pstate, RangeVar *relation,
bool inh, bool alsoSource, AclMode requiredPerms); bool inh, bool alsoSource, AclMode requiredPerms);
extern bool interpretInhOption(InhOption inhOpt); extern bool interpretInhOption(InhOption inhOpt);
extern bool interpretOidsOption(List *options); extern bool interpretOidsOption(List *defList);
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, extern Node *transformWhereClause(ParseState *pstate, Node *clause,
const char *constructName); const char *constructName);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.90 2006/07/02 02:23:23 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.91 2006/07/03 22:45:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -115,7 +115,7 @@ typedef struct RelationAmInfo
FmgrInfo ambulkdelete; FmgrInfo ambulkdelete;
FmgrInfo amvacuumcleanup; FmgrInfo amvacuumcleanup;
FmgrInfo amcostestimate; FmgrInfo amcostestimate;
FmgrInfo amoption; FmgrInfo amoptions;
} RelationAmInfo; } RelationAmInfo;
@ -143,14 +143,8 @@ typedef struct RelationData
* survived into; or zero if the rel was not created in the current top * survived into; or zero if the rel was not created in the current top
* transaction. This should be relied on only for optimization purposes; * transaction. This should be relied on only for optimization purposes;
* it is possible for new-ness to be "forgotten" (eg, after CLUSTER). * 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 */ Form_pg_class rd_rel; /* RELATION tuple */
bytea *rd_options; /* parsed rd_rel->reloptions */
TupleDesc rd_att; /* tuple descriptor */ TupleDesc rd_att; /* tuple descriptor */
Oid rd_id; /* relation's object id */ Oid rd_id; /* relation's object id */
List *rd_indexlist; /* list of OIDs of indexes on relation */ List *rd_indexlist; /* list of OIDs of indexes on relation */
@ -160,6 +154,13 @@ typedef struct RelationData
MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */
TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */
/*
* rd_options is set whenever rd_rel is loaded into the relcache entry.
* Note that you can NOT look into rd_rel for this data. NULL means
* "use defaults".
*/
bytea *rd_options; /* parsed pg_class.reloptions */
/* These are non-NULL only for an index relation: */ /* These are non-NULL only for an index relation: */
Form_pg_index rd_index; /* pg_index tuple describing this index */ Form_pg_index rd_index; /* pg_index tuple describing this index */
struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */
@ -207,6 +208,45 @@ typedef RelationData *Relation;
typedef Relation *RelationPtr; typedef Relation *RelationPtr;
/*
* StdRdOptions
* Standard contents of rd_options for heaps and generic indexes.
*
* RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only
* be applied to relations that use this format or a superset for
* private options data.
*/
typedef struct StdRdOptions
{
int32 vl_len; /* required to be a bytea */
int fillfactor; /* page fill factor in percent (0..100) */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10
#define HEAP_DEFAULT_FILLFACTOR 100
/*
* RelationGetFillFactor
* Returns the relation's fillfactor. Note multiple eval of argument!
*/
#define RelationGetFillFactor(relation, defaultff) \
((relation)->rd_options ? \
((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
/*
* RelationGetTargetPageUsage
* Returns the relation's desired space usage per page in bytes.
*/
#define RelationGetTargetPageUsage(relation, defaultff) \
(BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100)
/*
* RelationGetTargetPageFreeSpace
* Returns the relation's desired freespace per page in bytes.
*/
#define RelationGetTargetPageFreeSpace(relation, defaultff) \
(BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100)
/* /*
* RelationIsValid * RelationIsValid
* True iff relation descriptor is valid. * True iff relation descriptor is valid.