mirror of
https://github.com/postgres/postgres.git
synced 2025-11-18 02:02:55 +03:00
pgindent run on all C files. Java run to follow. initdb/regression
tests pass.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.73 2001/08/23 23:06:37 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.74 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The old interface functions have been converted to macros
|
||||
@@ -241,7 +241,6 @@ nocachegetattr(HeapTuple tuple,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* there's a null somewhere in the tuple
|
||||
*/
|
||||
@@ -347,7 +346,6 @@ nocachegetattr(HeapTuple tuple,
|
||||
(HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) &&
|
||||
(HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++)
|
||||
{
|
||||
|
||||
/*
|
||||
* Fix me when going to a machine with more than a four-byte
|
||||
* word!
|
||||
@@ -546,7 +544,6 @@ heap_deformtuple(HeapTuple tuple,
|
||||
nulls[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@@ -739,7 +736,7 @@ heap_freetuple(HeapTuple htup)
|
||||
*
|
||||
* This routine forms a HeapTuple by copying the given structure (tuple
|
||||
* data) and adding a generic header. Note that the tuple data is
|
||||
* presumed to contain no null fields. It is typically only useful
|
||||
* presumed to contain no null fields. It is typically only useful
|
||||
* for null-free system tables.
|
||||
* ----------------
|
||||
*/
|
||||
@@ -771,7 +768,7 @@ heap_addheader(int natts, /* max domain index */
|
||||
|
||||
td->t_hoff = hoff;
|
||||
td->t_natts = natts;
|
||||
td->t_infomask = HEAP_XMAX_INVALID; /* XXX sufficient? */
|
||||
td->t_infomask = HEAP_XMAX_INVALID; /* XXX sufficient? */
|
||||
|
||||
memcpy((char *) td + hoff, structure, structlen);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.54 2001/03/22 06:16:06 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.55 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -49,7 +49,6 @@ index_formtuple(TupleDesc tupleDescriptor,
|
||||
#ifdef TOAST_INDEX_HACK
|
||||
Datum untoasted_value[INDEX_MAX_KEYS];
|
||||
bool untoasted_free[INDEX_MAX_KEYS];
|
||||
|
||||
#endif
|
||||
|
||||
if (numberOfAttributes > INDEX_MAX_KEYS)
|
||||
@@ -338,7 +337,6 @@ nocache_index_getattr(IndexTuple tup,
|
||||
|
||||
for (; j <= attnum; j++)
|
||||
{
|
||||
|
||||
/*
|
||||
* Fix me when going to a machine with more than a four-byte
|
||||
* word!
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.59 2001/03/22 06:16:06 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.60 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -197,7 +197,6 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
||||
continue;
|
||||
if (OidIsValid(thisState->typoutput))
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
@@ -306,7 +305,6 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
||||
if (getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
|
||||
&typoutput, &typelem, &typisvarlena))
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
@@ -401,7 +399,6 @@ printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
||||
/* send # of bytes, and opaque data */
|
||||
if (thisState->typisvarlena)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, must detoast before sending.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.75 2001/06/25 21:11:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.76 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||
@@ -238,9 +238,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||
Form_pg_attribute attr2 = tupdesc2->attrs[i];
|
||||
|
||||
/*
|
||||
* We do not need to check every single field here: we can disregard
|
||||
* attrelid, attnum (it was used to place the row in the attrs array)
|
||||
* and everything derived from the column datatype.
|
||||
* We do not need to check every single field here: we can
|
||||
* disregard attrelid, attnum (it was used to place the row in the
|
||||
* attrs array) and everything derived from the column datatype.
|
||||
*/
|
||||
if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
|
||||
return false;
|
||||
@@ -399,7 +399,6 @@ TupleDescInitEntry(TupleDesc desc,
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
|
||||
/*
|
||||
* here type info does not exist yet so we just fill the attribute
|
||||
* with dummy information and return false.
|
||||
@@ -585,7 +584,6 @@ BuildDescForRelation(List *schema, char *relname)
|
||||
typenameTypeId(typename),
|
||||
atttypmod, attdim, attisset))
|
||||
{
|
||||
|
||||
/*
|
||||
* if TupleDescInitEntry() fails, it means there is no type in
|
||||
* the system catalogs. So now we check if the type name
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.30 2001/08/22 18:24:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistget.c,v 1.31 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -251,7 +251,7 @@ gistindex_keytest(IndexTuple tuple,
|
||||
if (key[0].sk_flags & SK_ISNULL)
|
||||
return false;
|
||||
*/
|
||||
gistdentryinit(giststate, key[0].sk_attno-1, &de,
|
||||
gistdentryinit(giststate, key[0].sk_attno - 1, &de,
|
||||
datum, r, p, offset,
|
||||
IndexTupleSize(tuple) - sizeof(IndexTupleData),
|
||||
FALSE, isNull);
|
||||
@@ -271,9 +271,9 @@ gistindex_keytest(IndexTuple tuple,
|
||||
ObjectIdGetDatum(key[0].sk_procedure));
|
||||
}
|
||||
|
||||
if ( de.key != datum && ! isAttByVal( giststate, key[0].sk_attno-1 ) )
|
||||
if ( DatumGetPointer(de.key) != NULL )
|
||||
pfree( DatumGetPointer(de.key) );
|
||||
if (de.key != datum && !isAttByVal(giststate, key[0].sk_attno - 1))
|
||||
if (DatumGetPointer(de.key) != NULL)
|
||||
pfree(DatumGetPointer(de.key));
|
||||
|
||||
if (DatumGetBool(test) == !!(key[0].sk_flags & SK_NEGATE))
|
||||
return false;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.39 2001/08/22 18:24:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.40 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -112,7 +112,7 @@ gistrescan(PG_FUNCTION_ARGS)
|
||||
s->keyData[i].sk_procedure
|
||||
= RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
|
||||
s->keyData[i].sk_procedure);
|
||||
s->keyData[i].sk_func = p->giststate->consistentFn[s->keyData[i].sk_attno-1];
|
||||
s->keyData[i].sk_func = p->giststate->consistentFn[s->keyData[i].sk_attno - 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -137,13 +137,13 @@ gistrescan(PG_FUNCTION_ARGS)
|
||||
|
||||
/*----------
|
||||
* s->keyData[i].sk_procedure =
|
||||
* index_getprocid(s->relation, 1, GIST_CONSISTENT_PROC);
|
||||
* index_getprocid(s->relation, 1, GIST_CONSISTENT_PROC);
|
||||
*----------
|
||||
*/
|
||||
s->keyData[i].sk_procedure
|
||||
= RelationGetGISTStrategy(s->relation, s->keyData[i].sk_attno,
|
||||
s->keyData[i].sk_procedure);
|
||||
s->keyData[i].sk_func = p->giststate->consistentFn[s->keyData[i].sk_attno-1];
|
||||
s->keyData[i].sk_func = p->giststate->consistentFn[s->keyData[i].sk_attno - 1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,8 +234,8 @@ gistendscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
gistfreestack(p->s_stack);
|
||||
gistfreestack(p->s_markstk);
|
||||
if ( p->giststate != NULL )
|
||||
freeGISTstate( p->giststate );
|
||||
if (p->giststate != NULL)
|
||||
freeGISTstate(p->giststate);
|
||||
pfree(s->opaque);
|
||||
}
|
||||
|
||||
@@ -383,7 +383,6 @@ adjustiptr(IndexScanDesc s,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* remember that we're before the current
|
||||
* tuple
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/Attic/giststrat.c,v 1.17 2001/05/30 19:53:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/Attic/giststrat.c,v 1.18 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -121,5 +121,4 @@ RelationInvokeGISTStrategy(Relation r,
|
||||
return (RelationInvokeStrategy(r, &GISTEvaluationData, attnum, s,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.52 2001/07/15 22:48:15 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.53 2001/10/25 05:49:20 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains only the public interface routines.
|
||||
@@ -37,11 +37,11 @@ typedef struct
|
||||
} HashBuildState;
|
||||
|
||||
static void hashbuildCallback(Relation index,
|
||||
HeapTuple htup,
|
||||
Datum *attdata,
|
||||
char *nulls,
|
||||
bool tupleIsAlive,
|
||||
void *state);
|
||||
HeapTuple htup,
|
||||
Datum *attdata,
|
||||
char *nulls,
|
||||
bool tupleIsAlive,
|
||||
void *state);
|
||||
|
||||
|
||||
/*
|
||||
@@ -80,7 +80,7 @@ hashbuild(PG_FUNCTION_ARGS)
|
||||
|
||||
/* do the heap scan */
|
||||
reltuples = IndexBuildHeapScan(heap, index, indexInfo,
|
||||
hashbuildCallback, (void *) &buildstate);
|
||||
hashbuildCallback, (void *) &buildstate);
|
||||
|
||||
/* all done */
|
||||
BuildingHash = false;
|
||||
@@ -121,7 +121,7 @@ hashbuildCallback(Relation index,
|
||||
bool tupleIsAlive,
|
||||
void *state)
|
||||
{
|
||||
HashBuildState *buildstate = (HashBuildState *) state;
|
||||
HashBuildState *buildstate = (HashBuildState *) state;
|
||||
IndexTuple itup;
|
||||
HashItem hitem;
|
||||
InsertIndexResult res;
|
||||
@@ -164,6 +164,7 @@ hashinsert(PG_FUNCTION_ARGS)
|
||||
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
|
||||
char *nulls = (char *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
|
||||
#ifdef NOT_USED
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
#endif
|
||||
@@ -176,14 +177,13 @@ hashinsert(PG_FUNCTION_ARGS)
|
||||
itup->t_tid = *ht_ctid;
|
||||
|
||||
/*
|
||||
* If the single index key is null, we don't insert it into the
|
||||
* index. Hash tables support scans on '='. Relational algebra
|
||||
* says that A = B returns null if either A or B is null. This
|
||||
* means that no qualification used in an index scan could ever
|
||||
* return true on a null attribute. It also means that indices
|
||||
* can't be used by ISNULL or NOTNULL scans, but that's an
|
||||
* artifact of the strategy map architecture chosen in 1986, not
|
||||
* of the way nulls are handled here.
|
||||
* If the single index key is null, we don't insert it into the index.
|
||||
* Hash tables support scans on '='. Relational algebra says that A =
|
||||
* B returns null if either A or B is null. This means that no
|
||||
* qualification used in an index scan could ever return true on a
|
||||
* null attribute. It also means that indices can't be used by ISNULL
|
||||
* or NOTNULL scans, but that's an artifact of the strategy map
|
||||
* architecture chosen in 1986, not of the way nulls are handled here.
|
||||
*/
|
||||
if (IndexTupleHasNulls(itup))
|
||||
{
|
||||
@@ -262,7 +262,6 @@ hashrescan(PG_FUNCTION_ARGS)
|
||||
|
||||
#ifdef NOT_USED /* XXX surely it's wrong to ignore this? */
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
|
||||
#endif
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
ItemPointer iptr;
|
||||
@@ -412,7 +411,7 @@ hashbulkdelete(PG_FUNCTION_ARGS)
|
||||
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
|
||||
void *callback_state = (void *) PG_GETARG_POINTER(2);
|
||||
IndexBulkDeleteResult *result;
|
||||
BlockNumber num_pages;
|
||||
BlockNumber num_pages;
|
||||
double tuples_removed;
|
||||
double num_index_tuples;
|
||||
RetrieveIndexResult res;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashinsert.c,v 1.22 2001/03/07 21:20:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashinsert.c,v 1.23 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -133,13 +133,11 @@ _hash_insertonpg(Relation rel,
|
||||
|
||||
while (PageGetFreeSpace(page) < itemsz)
|
||||
{
|
||||
|
||||
/*
|
||||
* no space on this page; check for an overflow page
|
||||
*/
|
||||
if (BlockNumberIsValid(pageopaque->hasho_nextblkno))
|
||||
{
|
||||
|
||||
/*
|
||||
* ovfl page exists; go get it. if it doesn't have room,
|
||||
* we'll find out next pass through the loop test above.
|
||||
@@ -152,7 +150,6 @@ _hash_insertonpg(Relation rel,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* we're at the end of the bucket chain and we haven't found a
|
||||
* page with enough room. allocate a new overflow page.
|
||||
@@ -184,7 +181,6 @@ _hash_insertonpg(Relation rel,
|
||||
|
||||
if (res != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Increment the number of keys in the table. We switch lock
|
||||
* access type just for a moment to allow greater accessibility to
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashovfl.c,v 1.30 2001/07/15 22:48:15 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashovfl.c,v 1.31 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Overflow pages look like ordinary relation pages.
|
||||
@@ -208,7 +208,6 @@ _hash_getovfladdr(Relation rel, Buffer *metabufp)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Free_bit addresses the last used bit. Bump it to address the
|
||||
* first available bit.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.32 2001/07/15 22:48:15 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.33 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres hash pages look like ordinary relation pages. The opaque
|
||||
@@ -50,7 +50,7 @@ static void _hash_splitpage(Relation rel, Buffer metabuf, Bucket obucket, Bucket
|
||||
* system catalogs anyway.
|
||||
*
|
||||
* Note that our page locks are actual lockmanager locks, not buffer
|
||||
* locks (as are used by btree, for example). This is a good idea because
|
||||
* locks (as are used by btree, for example). This is a good idea because
|
||||
* the algorithms are not deadlock-free, and we'd better be able to detect
|
||||
* and recover from deadlocks.
|
||||
*
|
||||
@@ -325,7 +325,7 @@ _hash_setpagelock(Relation rel,
|
||||
{
|
||||
switch (access)
|
||||
{
|
||||
case HASH_WRITE:
|
||||
case HASH_WRITE:
|
||||
LockPage(rel, blkno, ExclusiveLock);
|
||||
break;
|
||||
case HASH_READ:
|
||||
@@ -349,7 +349,7 @@ _hash_unsetpagelock(Relation rel,
|
||||
{
|
||||
switch (access)
|
||||
{
|
||||
case HASH_WRITE:
|
||||
case HASH_WRITE:
|
||||
UnlockPage(rel, blkno, ExclusiveLock);
|
||||
break;
|
||||
case HASH_READ:
|
||||
@@ -369,7 +369,7 @@ _hash_unsetpagelock(Relation rel,
|
||||
* It is safe to delete an item after acquiring a regular WRITE lock on
|
||||
* the page, because no other backend can hold a READ lock on the page,
|
||||
* and that means no other backend currently has an indexscan stopped on
|
||||
* any item of the item being deleted. Our own backend might have such
|
||||
* any item of the item being deleted. Our own backend might have such
|
||||
* an indexscan (in fact *will*, since that's how VACUUM found the item
|
||||
* in the first place), but _hash_adjscans will fix the scan position.
|
||||
*/
|
||||
@@ -532,7 +532,6 @@ _hash_splitpage(Relation rel,
|
||||
_hash_relbuf(rel, obuf, HASH_WRITE);
|
||||
if (!BlockNumberIsValid(oblkno))
|
||||
{
|
||||
|
||||
/*
|
||||
* the old bucket is completely empty; of course, the new
|
||||
* bucket will be as well, but since it's a base bucket page
|
||||
@@ -559,7 +558,6 @@ _hash_splitpage(Relation rel,
|
||||
omaxoffnum = PageGetMaxOffsetNumber(opage);
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* at each iteration through this loop, each of these variables
|
||||
* should be up-to-date: obuf opage oopaque ooffnum omaxoffnum
|
||||
@@ -572,7 +570,6 @@ _hash_splitpage(Relation rel,
|
||||
oblkno = oopaque->hasho_nextblkno;
|
||||
if (BlockNumberIsValid(oblkno))
|
||||
{
|
||||
|
||||
/*
|
||||
* we ran out of tuples on this particular page, but we
|
||||
* have more overflow pages; re-init values.
|
||||
@@ -594,7 +591,6 @@ _hash_splitpage(Relation rel,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* we're at the end of the bucket chain, so now we're
|
||||
* really done with everything. before quitting, call
|
||||
@@ -618,7 +614,6 @@ _hash_splitpage(Relation rel,
|
||||
|
||||
if (bucket == nbucket)
|
||||
{
|
||||
|
||||
/*
|
||||
* insert the tuple into the new bucket. if it doesn't fit on
|
||||
* the current page in the new bucket, we must allocate a new
|
||||
@@ -695,7 +690,6 @@ _hash_splitpage(Relation rel,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* the tuple stays on this page. we didn't move anything, so
|
||||
* we didn't delete anything and therefore we don't have to
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.26 2001/03/23 04:49:51 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.27 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,7 +36,6 @@ _hash_search(Relation rel,
|
||||
if (scankey == (ScanKey) NULL ||
|
||||
(keyDatum = scankey[0].sk_argument) == (Datum) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* If the scankey argument is NULL, all tuples will satisfy the
|
||||
* scan so we start the scan at the first bucket (bucket 0).
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/Attic/hashstrat.c,v 1.18 2001/05/30 19:53:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/Attic/hashstrat.c,v 1.19 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -46,7 +46,6 @@ static StrategyEvaluationData HTEvaluationData = {
|
||||
(StrategyTransformMap) HTNegateCommute,
|
||||
HTEvaluationExpressions
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -68,7 +67,6 @@ _hash_getstrat(Relation rel,
|
||||
|
||||
return strat;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -82,5 +80,4 @@ _hash_invokestrat(Relation rel,
|
||||
return (RelationInvokeStrategy(rel, &HTEvaluationData, attno, strat,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.125 2001/08/23 23:06:37 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.126 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -116,8 +116,8 @@ heapgettup(Relation relation,
|
||||
{
|
||||
ItemId lpp;
|
||||
Page dp;
|
||||
BlockNumber page;
|
||||
BlockNumber pages;
|
||||
BlockNumber page;
|
||||
BlockNumber pages;
|
||||
int lines;
|
||||
OffsetNumber lineoff;
|
||||
int linesleft;
|
||||
@@ -350,7 +350,7 @@ heapgettup(Relation relation,
|
||||
/*
|
||||
* return NULL if we've exhausted all the pages
|
||||
*/
|
||||
if ((dir < 0) ? (page == 0) : (page+1 >= pages))
|
||||
if ((dir < 0) ? (page == 0) : (page + 1 >= pages))
|
||||
{
|
||||
if (BufferIsValid(*buffer))
|
||||
ReleaseBuffer(*buffer);
|
||||
@@ -429,9 +429,8 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
|
||||
(
|
||||
(Datum) NULL
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
#endif /* defined(DISABLE_COMPLEX_MACRO) */
|
||||
|
||||
|
||||
@@ -1045,12 +1044,13 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||
if (relation->rd_rel->relhasoids)
|
||||
{
|
||||
/*
|
||||
* If the object id of this tuple has already been assigned, trust the
|
||||
* caller. There are a couple of ways this can happen. At initial db
|
||||
* creation, the backend program sets oids for tuples. When we define
|
||||
* an index, we set the oid. Finally, in the future, we may allow
|
||||
* users to set their own object ids in order to support a persistent
|
||||
* object store (objects need to contain pointers to one another).
|
||||
* If the object id of this tuple has already been assigned, trust
|
||||
* the caller. There are a couple of ways this can happen. At
|
||||
* initial db creation, the backend program sets oids for tuples.
|
||||
* When we define an index, we set the oid. Finally, in the
|
||||
* future, we may allow users to set their own object ids in order
|
||||
* to support a persistent object store (objects need to contain
|
||||
* pointers to one another).
|
||||
*/
|
||||
if (!OidIsValid(tup->t_data->t_oid))
|
||||
tup->t_data->t_oid = newoid();
|
||||
@@ -1478,21 +1478,22 @@ l2:
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, do we need a new page for the tuple, or not? This is a bit
|
||||
* tricky since someone else could have added tuples to the page
|
||||
* while we weren't looking. We have to recheck the available space
|
||||
* after reacquiring the buffer lock. But don't bother to do that
|
||||
* if the former amount of free space is still not enough; it's
|
||||
* unlikely there's more free now than before.
|
||||
* Now, do we need a new page for the tuple, or not? This is a
|
||||
* bit tricky since someone else could have added tuples to the
|
||||
* page while we weren't looking. We have to recheck the
|
||||
* available space after reacquiring the buffer lock. But don't
|
||||
* bother to do that if the former amount of free space is still
|
||||
* not enough; it's unlikely there's more free now than before.
|
||||
*
|
||||
* What's more, if we need to get a new page, we will need to acquire
|
||||
* buffer locks on both old and new pages. To avoid deadlock against
|
||||
* some other backend trying to get the same two locks in the other
|
||||
* order, we must be consistent about the order we get the locks in.
|
||||
* We use the rule "lock the lower-numbered page of the relation
|
||||
* first". To implement this, we must do RelationGetBufferForTuple
|
||||
* while not holding the lock on the old page, and we must rely on it
|
||||
* to get the locks on both pages in the correct order.
|
||||
* buffer locks on both old and new pages. To avoid deadlock
|
||||
* against some other backend trying to get the same two locks in
|
||||
* the other order, we must be consistent about the order we get
|
||||
* the locks in. We use the rule "lock the lower-numbered page of
|
||||
* the relation first". To implement this, we must do
|
||||
* RelationGetBufferForTuple while not holding the lock on the old
|
||||
* page, and we must rely on it to get the locks on both pages in
|
||||
* the correct order.
|
||||
*/
|
||||
if (newtupsize > pagefree)
|
||||
{
|
||||
@@ -1510,8 +1511,8 @@ l2:
|
||||
{
|
||||
/*
|
||||
* Rats, it doesn't fit anymore. We must now unlock and
|
||||
* relock to avoid deadlock. Fortunately, this path should
|
||||
* seldom be taken.
|
||||
* relock to avoid deadlock. Fortunately, this path
|
||||
* should seldom be taken.
|
||||
*/
|
||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||
newbuf = RelationGetBufferForTuple(relation, newtup->t_len,
|
||||
@@ -1534,9 +1535,9 @@ l2:
|
||||
pgstat_count_heap_update(&relation->pgstat_info);
|
||||
|
||||
/*
|
||||
* At this point newbuf and buffer are both pinned and locked,
|
||||
* and newbuf has enough space for the new tuple. If they are
|
||||
* the same buffer, only one pin is held.
|
||||
* At this point newbuf and buffer are both pinned and locked, and
|
||||
* newbuf has enough space for the new tuple. If they are the same
|
||||
* buffer, only one pin is held.
|
||||
*/
|
||||
|
||||
/* NO ELOG(ERROR) from here till changes are logged */
|
||||
@@ -1865,12 +1866,14 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
* Note: xlhdr is declared to have adequate size and correct alignment
|
||||
* for an xl_heap_header. However the two tids, if present at all,
|
||||
* will be packed in with no wasted space after the xl_heap_header;
|
||||
* they aren't necessarily aligned as implied by this struct declaration.
|
||||
* they aren't necessarily aligned as implied by this struct
|
||||
* declaration.
|
||||
*/
|
||||
struct {
|
||||
xl_heap_header hdr;
|
||||
TransactionId tid1;
|
||||
TransactionId tid2;
|
||||
struct
|
||||
{
|
||||
xl_heap_header hdr;
|
||||
TransactionId tid1;
|
||||
TransactionId tid2;
|
||||
} xlhdr;
|
||||
int hsize = SizeOfHeapHeader;
|
||||
xl_heap_update xlrec;
|
||||
@@ -1972,7 +1975,7 @@ heap_xlog_clean(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
if (record->xl_len > SizeOfHeapClean)
|
||||
{
|
||||
OffsetNumber unbuf[BLCKSZ/sizeof(OffsetNumber)];
|
||||
OffsetNumber unbuf[BLCKSZ / sizeof(OffsetNumber)];
|
||||
OffsetNumber *unused = unbuf;
|
||||
char *unend;
|
||||
ItemId lp;
|
||||
@@ -2084,9 +2087,10 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
if (redo)
|
||||
{
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
HeapTupleHeaderData hdr;
|
||||
char data[MaxTupleSize];
|
||||
char data[MaxTupleSize];
|
||||
} tbuf;
|
||||
HeapTupleHeader htup;
|
||||
xl_heap_header xlhdr;
|
||||
@@ -2251,9 +2255,10 @@ newsame:;
|
||||
|
||||
if (redo)
|
||||
{
|
||||
struct {
|
||||
struct
|
||||
{
|
||||
HeapTupleHeaderData hdr;
|
||||
char data[MaxTupleSize];
|
||||
char data[MaxTupleSize];
|
||||
} tbuf;
|
||||
xl_heap_header xlhdr;
|
||||
int hsize;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Id: hio.c,v 1.42 2001/07/13 22:52:58 tgl Exp $
|
||||
* $Id: hio.c,v 1.43 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -83,7 +83,7 @@ RelationPutHeapTuple(Relation relation,
|
||||
* NOTE: it is unlikely, but not quite impossible, for otherBuffer to be the
|
||||
* same buffer we select for insertion of the new tuple (this could only
|
||||
* happen if space is freed in that page after heap_update finds there's not
|
||||
* enough there). In that case, the page will be pinned and locked only once.
|
||||
* enough there). In that case, the page will be pinned and locked only once.
|
||||
*
|
||||
* Note that we use LockPage(rel, 0) to lock relation for extension.
|
||||
* We can do this as long as in all other places we use page-level locking
|
||||
@@ -115,17 +115,19 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
if (otherBuffer != InvalidBuffer)
|
||||
otherBlock = BufferGetBlockNumber(otherBuffer);
|
||||
else
|
||||
otherBlock = InvalidBlockNumber; /* just to keep compiler quiet */
|
||||
otherBlock = InvalidBlockNumber; /* just to keep compiler
|
||||
* quiet */
|
||||
|
||||
/*
|
||||
* We first try to put the tuple on the same page we last inserted a
|
||||
* tuple on, as cached in the relcache entry. If that doesn't work,
|
||||
* we ask the shared Free Space Map to locate a suitable page. Since
|
||||
* we ask the shared Free Space Map to locate a suitable page. Since
|
||||
* the FSM's info might be out of date, we have to be prepared to loop
|
||||
* around and retry multiple times. (To insure this isn't an infinite
|
||||
* loop, we must update the FSM with the correct amount of free space on
|
||||
* each page that proves not to be suitable.) If the FSM has no record of
|
||||
* a page with enough free space, we give up and extend the relation.
|
||||
* loop, we must update the FSM with the correct amount of free space
|
||||
* on each page that proves not to be suitable.) If the FSM has no
|
||||
* record of a page with enough free space, we give up and extend the
|
||||
* relation.
|
||||
*/
|
||||
|
||||
targetBlock = relation->rd_targblock;
|
||||
@@ -137,6 +139,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
* target.
|
||||
*/
|
||||
targetBlock = GetPageWithFreeSpace(&relation->rd_node, len);
|
||||
|
||||
/*
|
||||
* If the FSM knows nothing of the rel, try the last page before
|
||||
* we give up and extend. This avoids one-tuple-per-page syndrome
|
||||
@@ -144,7 +147,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
*/
|
||||
if (targetBlock == InvalidBlockNumber)
|
||||
{
|
||||
BlockNumber nblocks = RelationGetNumberOfBlocks(relation);
|
||||
BlockNumber nblocks = RelationGetNumberOfBlocks(relation);
|
||||
|
||||
if (nblocks > 0)
|
||||
targetBlock = nblocks - 1;
|
||||
@@ -154,9 +157,9 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
while (targetBlock != InvalidBlockNumber)
|
||||
{
|
||||
/*
|
||||
* Read and exclusive-lock the target block, as well as the
|
||||
* other block if one was given, taking suitable care with
|
||||
* lock ordering and the possibility they are the same block.
|
||||
* Read and exclusive-lock the target block, as well as the other
|
||||
* block if one was given, taking suitable care with lock ordering
|
||||
* and the possibility they are the same block.
|
||||
*/
|
||||
if (otherBuffer == InvalidBuffer)
|
||||
{
|
||||
@@ -184,9 +187,10 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we can check to see if there's enough free space here.
|
||||
* If so, we're done.
|
||||
* Now we can check to see if there's enough free space here. If
|
||||
* so, we're done.
|
||||
*/
|
||||
pageHeader = (Page) BufferGetPage(buffer);
|
||||
pageFreeSpace = PageGetFreeSpace(pageHeader);
|
||||
@@ -196,22 +200,22 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
relation->rd_targblock = targetBlock;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not enough space, so we must give up our page locks and
|
||||
* pin (if any) and prepare to look elsewhere. We don't care
|
||||
* which order we unlock the two buffers in, so this can be
|
||||
* slightly simpler than the code above.
|
||||
* Not enough space, so we must give up our page locks and pin (if
|
||||
* any) and prepare to look elsewhere. We don't care which order
|
||||
* we unlock the two buffers in, so this can be slightly simpler
|
||||
* than the code above.
|
||||
*/
|
||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||
if (otherBuffer == InvalidBuffer)
|
||||
{
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
else if (otherBlock != targetBlock)
|
||||
{
|
||||
LockBuffer(otherBuffer, BUFFER_LOCK_UNLOCK);
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update FSM as to condition of this page, and ask for another
|
||||
* page to try.
|
||||
@@ -225,9 +229,9 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
/*
|
||||
* Have to extend the relation.
|
||||
*
|
||||
* We have to use a lock to ensure no one else is extending the
|
||||
* rel at the same time, else we will both try to initialize the
|
||||
* same new page.
|
||||
* We have to use a lock to ensure no one else is extending the rel at
|
||||
* the same time, else we will both try to initialize the same new
|
||||
* page.
|
||||
*/
|
||||
if (!relation->rd_myxactonly)
|
||||
LockPage(relation, 0, ExclusiveLock);
|
||||
@@ -236,20 +240,21 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
* XXX This does an lseek - rather expensive - but at the moment it is
|
||||
* the only way to accurately determine how many blocks are in a
|
||||
* relation. Is it worth keeping an accurate file length in shared
|
||||
* memory someplace, rather than relying on the kernel to do it for us?
|
||||
* memory someplace, rather than relying on the kernel to do it for
|
||||
* us?
|
||||
*/
|
||||
buffer = ReadBuffer(relation, P_NEW);
|
||||
|
||||
/*
|
||||
* Release the file-extension lock; it's now OK for someone else
|
||||
* to extend the relation some more.
|
||||
* Release the file-extension lock; it's now OK for someone else to
|
||||
* extend the relation some more.
|
||||
*/
|
||||
if (!relation->rd_myxactonly)
|
||||
UnlockPage(relation, 0, ExclusiveLock);
|
||||
|
||||
/*
|
||||
* We can be certain that locking the otherBuffer first is OK,
|
||||
* since it must have a lower page number.
|
||||
* We can be certain that locking the otherBuffer first is OK, since
|
||||
* it must have a lower page number.
|
||||
*/
|
||||
if (otherBuffer != InvalidBuffer)
|
||||
LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
@@ -273,7 +278,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
*
|
||||
* XXX should we enter the new page into the free space map immediately,
|
||||
* or just keep it for this backend's exclusive use in the short run
|
||||
* (until VACUUM sees it)? Seems to depend on whether you expect the
|
||||
* (until VACUUM sees it)? Seems to depend on whether you expect the
|
||||
* current backend to make more insertions or not, which is probably a
|
||||
* good bet most of the time. So for now, don't add it to FSM yet.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.24 2001/03/22 06:16:07 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.25 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* initam should be moved someplace else.
|
||||
@@ -164,7 +164,6 @@ ResetHeapAccessStatistics()
|
||||
time(&stats->local_reset_timestamp);
|
||||
time(&stats->last_request_timestamp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -200,7 +199,6 @@ GetHeapAccessStatistics()
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -211,7 +209,6 @@ GetHeapAccessStatistics()
|
||||
void
|
||||
PrintHeapAccessStatistics(HeapAccessStatistics stats)
|
||||
{
|
||||
|
||||
/*
|
||||
* return nothing if stats aren't valid
|
||||
*/
|
||||
@@ -302,7 +299,6 @@ PrintHeapAccessStatistics(HeapAccessStatistics stats)
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -317,7 +313,6 @@ PrintAndFreeHeapAccessStatistics(HeapAccessStatistics stats)
|
||||
if (stats != NULL)
|
||||
pfree(stats);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -331,7 +326,6 @@ PrintAndFreeHeapAccessStatistics(HeapAccessStatistics stats)
|
||||
void
|
||||
initam(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* initialize heap statistics.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.24 2001/08/10 18:57:33 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.25 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -74,14 +74,13 @@ heap_tuple_toast_attrs(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* external storage (possibly still in compressed format).
|
||||
* ----------
|
||||
*/
|
||||
varattrib *
|
||||
varattrib *
|
||||
heap_tuple_fetch_attr(varattrib *attr)
|
||||
{
|
||||
varattrib *result;
|
||||
|
||||
if (VARATT_IS_EXTERNAL(attr))
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an external stored plain value
|
||||
*/
|
||||
@@ -89,7 +88,6 @@ heap_tuple_fetch_attr(varattrib *attr)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is a plain value inside of the main tuple - why am I
|
||||
* called?
|
||||
@@ -108,7 +106,7 @@ heap_tuple_fetch_attr(varattrib *attr)
|
||||
* or external storage.
|
||||
* ----------
|
||||
*/
|
||||
varattrib *
|
||||
varattrib *
|
||||
heap_tuple_untoast_attr(varattrib *attr)
|
||||
{
|
||||
varattrib *result;
|
||||
@@ -135,7 +133,6 @@ heap_tuple_untoast_attr(varattrib *attr)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an external stored plain value
|
||||
*/
|
||||
@@ -144,7 +141,6 @@ heap_tuple_untoast_attr(varattrib *attr)
|
||||
}
|
||||
else if (VARATT_IS_COMPRESSED(attr))
|
||||
{
|
||||
|
||||
/*
|
||||
* This is a compressed value inside of the main tuple
|
||||
*/
|
||||
@@ -181,8 +177,8 @@ toast_raw_datum_size(Datum value)
|
||||
if (VARATT_IS_COMPRESSED(attr))
|
||||
{
|
||||
/*
|
||||
* va_rawsize shows the original data size, whether the datum
|
||||
* is external or not.
|
||||
* va_rawsize shows the original data size, whether the datum is
|
||||
* external or not.
|
||||
*/
|
||||
result = attr->va_content.va_compressed.va_rawsize + VARHDRSZ;
|
||||
}
|
||||
@@ -301,7 +297,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
|
||||
if (oldtup != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* For UPDATE get the old and new values of this attribute
|
||||
*/
|
||||
@@ -324,7 +319,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
old_value->va_content.va_external.va_toastrelid !=
|
||||
new_value->va_content.va_external.va_toastrelid)
|
||||
{
|
||||
|
||||
/*
|
||||
* The old external store value isn't needed any more
|
||||
* after the update
|
||||
@@ -334,7 +328,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This attribute isn't changed by this update so we
|
||||
* reuse the original reference to the old value in
|
||||
@@ -348,7 +341,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* For INSERT simply get the new value
|
||||
*/
|
||||
@@ -372,7 +364,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
*/
|
||||
if (att[i]->attlen == -1)
|
||||
{
|
||||
|
||||
/*
|
||||
* If the table's attribute says PLAIN always, force it so.
|
||||
*/
|
||||
@@ -400,7 +391,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Not a variable size attribute, plain storage always
|
||||
*/
|
||||
@@ -475,7 +465,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* incompressible data, ignore on subsequent compression
|
||||
* passes
|
||||
@@ -588,7 +577,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* incompressible data, ignore on subsequent compression
|
||||
* passes
|
||||
@@ -776,9 +764,10 @@ toast_save_datum(Relation rel, Datum value)
|
||||
Datum t_values[3];
|
||||
char t_nulls[3];
|
||||
varattrib *result;
|
||||
struct {
|
||||
struct varlena hdr;
|
||||
char data[TOAST_MAX_CHUNK_SIZE];
|
||||
struct
|
||||
{
|
||||
struct varlena hdr;
|
||||
char data[TOAST_MAX_CHUNK_SIZE];
|
||||
} chunk_data;
|
||||
int32 chunk_size;
|
||||
int32 chunk_seq = 0;
|
||||
@@ -851,12 +840,12 @@ toast_save_datum(Relation rel, Datum value)
|
||||
heap_insert(toastrel, toasttup);
|
||||
|
||||
/*
|
||||
* Create the index entry. We cheat a little here by not using
|
||||
* Create the index entry. We cheat a little here by not using
|
||||
* FormIndexDatum: this relies on the knowledge that the index
|
||||
* columns are the same as the initial columns of the table.
|
||||
*
|
||||
* Note also that there had better not be any user-created index
|
||||
* on the TOAST table, since we don't bother to update anything else.
|
||||
* Note also that there had better not be any user-created index on
|
||||
* the TOAST table, since we don't bother to update anything else.
|
||||
*/
|
||||
idxres = index_insert(toastidx, t_values, t_nulls,
|
||||
&(toasttup->t_self),
|
||||
@@ -916,8 +905,8 @@ toast_delete_datum(Relation rel, Datum value)
|
||||
toastidx = index_open(toastrel->rd_rel->reltoastidxid);
|
||||
|
||||
/*
|
||||
* Setup a scan key to fetch from the index by va_valueid
|
||||
* (we don't particularly care whether we see them in sequence or not)
|
||||
* Setup a scan key to fetch from the index by va_valueid (we don't
|
||||
* particularly care whether we see them in sequence or not)
|
||||
*/
|
||||
ScanKeyEntryInitialize(&toastkey,
|
||||
(bits16) 0,
|
||||
@@ -1096,5 +1085,4 @@ toast_fetch_datum(varattrib *attr)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif /* TUPLE_TOASTER_ACTIVE */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.28 2001/06/22 19:16:21 wieck Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.29 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* many of the old access method routines have been turned into
|
||||
@@ -240,5 +240,4 @@ IndexScanRestorePosition(IndexScanDesc scan)
|
||||
|
||||
scan->flags = 0x0; /* XXX should have a symbolic name */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.53 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.54 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
* index_open - open an index relation by relationId
|
||||
@@ -241,9 +241,9 @@ index_beginscan(Relation relation,
|
||||
pgstat_initstats(&scan->xs_pgstat_info, relation);
|
||||
|
||||
/*
|
||||
* We want to look up the amgettuple procedure just once per scan,
|
||||
* not once per index_getnext call. So do it here and save
|
||||
* the fmgr info result in the scan descriptor.
|
||||
* We want to look up the amgettuple procedure just once per scan, not
|
||||
* once per index_getnext call. So do it here and save the fmgr info
|
||||
* result in the scan descriptor.
|
||||
*/
|
||||
GET_SCAN_PROCEDURE(beginscan, amgettuple);
|
||||
fmgr_info(procedure, &scan->fn_getnext);
|
||||
@@ -342,8 +342,8 @@ index_getnext(IndexScanDesc scan,
|
||||
pgstat_count_index_scan(&scan->xs_pgstat_info);
|
||||
|
||||
/*
|
||||
* have the am's gettuple proc do all the work.
|
||||
* index_beginscan already set up fn_getnext.
|
||||
* have the am's gettuple proc do all the work. index_beginscan
|
||||
* already set up fn_getnext.
|
||||
*/
|
||||
result = (RetrieveIndexResult)
|
||||
DatumGetPointer(FunctionCall2(&scan->fn_getnext,
|
||||
@@ -378,8 +378,8 @@ index_bulk_delete(Relation relation,
|
||||
result = (IndexBulkDeleteResult *)
|
||||
DatumGetPointer(OidFunctionCall3(procedure,
|
||||
PointerGetDatum(relation),
|
||||
PointerGetDatum((Pointer) callback),
|
||||
PointerGetDatum(callback_state)));
|
||||
PointerGetDatum((Pointer) callback),
|
||||
PointerGetDatum(callback_state)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.53 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.54 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -120,9 +120,9 @@ StrategyOperatorIsValid(StrategyOperator operator,
|
||||
StrategyNumber maxStrategy)
|
||||
{
|
||||
return (bool)
|
||||
(PointerIsValid(operator) &&
|
||||
StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
|
||||
!(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
|
||||
(PointerIsValid(operator) &&
|
||||
StrategyNumberIsInBounds(operator->strategy, maxStrategy) &&
|
||||
!(operator->flags & ~(SK_NEGATE | SK_COMMUTE)));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
@@ -196,7 +196,6 @@ StrategyEvaluationIsValid(StrategyEvaluation evaluation)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -255,7 +254,6 @@ StrategyTermEvaluate(StrategyTerm term,
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@@ -453,7 +451,6 @@ RelationInvokeStrategy(Relation relation,
|
||||
/* not reached, just to make compiler happy */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@@ -552,7 +549,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
{
|
||||
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
|
||||
{
|
||||
Oid opclass = operatorClassObjectId[attIndex];
|
||||
Oid opclass = operatorClassObjectId[attIndex];
|
||||
RegProcedure *loc;
|
||||
StrategyNumber support;
|
||||
|
||||
@@ -562,7 +559,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
{
|
||||
tuple = SearchSysCache(AMPROCNUM,
|
||||
ObjectIdGetDatum(opclass),
|
||||
Int16GetDatum(support+1),
|
||||
Int16GetDatum(support + 1),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
@@ -581,7 +578,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
/* Now load the strategy information for the index operators */
|
||||
for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
|
||||
{
|
||||
Oid opclass = operatorClassObjectId[attIndex];
|
||||
Oid opclass = operatorClassObjectId[attIndex];
|
||||
StrategyMap map;
|
||||
StrategyNumber strategy;
|
||||
|
||||
@@ -591,7 +588,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
|
||||
for (strategy = 1; strategy <= maxStrategyNumber; strategy++)
|
||||
{
|
||||
ScanKey mapentry = StrategyMapGetScanKeyEntry(map, strategy);
|
||||
ScanKey mapentry = StrategyMapGetScanKeyEntry(map, strategy);
|
||||
|
||||
tuple = SearchSysCache(AMOPSTRATEGY,
|
||||
ObjectIdGetDatum(opclass),
|
||||
@@ -643,5 +640,4 @@ IndexStrategyDisplay(IndexStrategy indexStrategy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined(ISTRATDEBUG) */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.42 2001/05/03 19:00:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.43 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@@ -25,7 +25,7 @@
|
||||
* NOTE: although any negative int32 is acceptable for reporting "<",
|
||||
* and any positive int32 is acceptable for reporting ">", routines
|
||||
* that work on 32-bit or wider datatypes can't just return "a - b".
|
||||
* That could overflow and give the wrong answer. Also, one should not
|
||||
* That could overflow and give the wrong answer. Also, one should not
|
||||
* return INT_MIN to report "<", since some callers will negate the result.
|
||||
*
|
||||
* NOTE: it is critical that the comparison function impose a total order
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.86 2001/09/29 23:49:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.87 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1100,7 +1100,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
|
||||
* If we are not on the leaf level, we will be able to discard the key
|
||||
* data from the first item that winds up on the right page.
|
||||
*/
|
||||
if (! state->is_leaf)
|
||||
if (!state->is_leaf)
|
||||
rightfree += (int) firstrightitemsz -
|
||||
(int) (MAXALIGN(sizeof(BTItemData)) + sizeof(ItemIdData));
|
||||
|
||||
@@ -1115,7 +1115,8 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
|
||||
{
|
||||
/*
|
||||
* On a rightmost page, try to equalize right free space with
|
||||
* twice the left free space. See comments for _bt_findsplitloc.
|
||||
* twice the left free space. See comments for
|
||||
* _bt_findsplitloc.
|
||||
*/
|
||||
delta = (2 * leftfree) - rightfree;
|
||||
}
|
||||
@@ -1618,7 +1619,6 @@ _bt_fixlevel(Relation rel, Buffer buf, BlockNumber limit)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* Read up to 2 more child pages and look for pointers to them in
|
||||
* *saved* parent page
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.53 2001/07/15 22:48:16 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.54 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||
@@ -153,7 +153,6 @@ _bt_getroot(Relation rel, int access)
|
||||
*/
|
||||
if (metad->btm_root == P_NONE)
|
||||
{
|
||||
|
||||
/*
|
||||
* Get, initialize, write, and leave a lock of the appropriate
|
||||
* type on the new root page. Since this is the first page in
|
||||
@@ -209,7 +208,6 @@ _bt_getroot(Relation rel, int access)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Metadata initialized by someone else. In order to
|
||||
* guarantee no deadlocks, we have to release the metadata
|
||||
@@ -237,7 +235,6 @@ _bt_getroot(Relation rel, int access)
|
||||
|
||||
if (!P_ISROOT(rootopaque))
|
||||
{
|
||||
|
||||
/*
|
||||
* It happened, but if root page splitter failed to create new
|
||||
* root page then we'll go in loop trying to call _bt_getroot
|
||||
@@ -402,7 +399,6 @@ _bt_wrtnorelbuf(Relation rel, Buffer buf)
|
||||
void
|
||||
_bt_pageinit(Page page, Size size)
|
||||
{
|
||||
|
||||
/*
|
||||
* Cargo_cult programming -- don't really need this to be zero, but
|
||||
* creating new pages is an infrequent occurrence and it makes me feel
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.82 2001/07/15 22:48:16 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.83 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,6 +37,7 @@ typedef struct
|
||||
bool haveDead;
|
||||
Relation heapRel;
|
||||
BTSpool *spool;
|
||||
|
||||
/*
|
||||
* spool2 is needed only when the index is an unique index. Dead
|
||||
* tuples are put into spool2 instead of spool in order to avoid
|
||||
@@ -58,11 +59,11 @@ bool FixBTree = true;
|
||||
|
||||
static void _bt_restscan(IndexScanDesc scan);
|
||||
static void btbuildCallback(Relation index,
|
||||
HeapTuple htup,
|
||||
Datum *attdata,
|
||||
char *nulls,
|
||||
bool tupleIsAlive,
|
||||
void *state);
|
||||
HeapTuple htup,
|
||||
Datum *attdata,
|
||||
char *nulls,
|
||||
bool tupleIsAlive,
|
||||
void *state);
|
||||
|
||||
|
||||
/*
|
||||
@@ -134,6 +135,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
if (buildstate.usefast)
|
||||
{
|
||||
buildstate.spool = _bt_spoolinit(index, indexInfo->ii_Unique);
|
||||
|
||||
/*
|
||||
* Different from spool, the uniqueness isn't checked for spool2.
|
||||
*/
|
||||
@@ -214,7 +216,7 @@ btbuildCallback(Relation index,
|
||||
bool tupleIsAlive,
|
||||
void *state)
|
||||
{
|
||||
BTBuildState *buildstate = (BTBuildState *) state;
|
||||
BTBuildState *buildstate = (BTBuildState *) state;
|
||||
IndexTuple itup;
|
||||
BTItem btitem;
|
||||
InsertIndexResult res;
|
||||
@@ -226,9 +228,9 @@ btbuildCallback(Relation index,
|
||||
btitem = _bt_formitem(itup);
|
||||
|
||||
/*
|
||||
* if we are doing bottom-up btree build, we insert the index into
|
||||
* a spool file for subsequent processing. otherwise, we insert
|
||||
* into the btree.
|
||||
* if we are doing bottom-up btree build, we insert the index into a
|
||||
* spool file for subsequent processing. otherwise, we insert into
|
||||
* the btree.
|
||||
*/
|
||||
if (buildstate->usefast)
|
||||
{
|
||||
@@ -305,7 +307,6 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||
|
||||
if (ItemPointerIsValid(&(scan->currentItemData)))
|
||||
{
|
||||
|
||||
/*
|
||||
* Restore scan position using heap TID returned by previous call
|
||||
* to btgettuple(). _bt_restscan() re-grabs the read lock on the
|
||||
@@ -321,7 +322,7 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||
* Save heap TID to use it in _bt_restscan. Then release the read
|
||||
* lock on the buffer so that we aren't blocking other backends.
|
||||
*
|
||||
* NOTE: we do keep the pin on the buffer! This is essential to ensure
|
||||
* NOTE: we do keep the pin on the buffer! This is essential to ensure
|
||||
* that someone else doesn't delete the index entry we are stopped on.
|
||||
*/
|
||||
if (res)
|
||||
@@ -362,7 +363,6 @@ btrescan(PG_FUNCTION_ARGS)
|
||||
|
||||
#ifdef NOT_USED /* XXX surely it's wrong to ignore this? */
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
|
||||
#endif
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
ItemPointer iptr;
|
||||
@@ -547,7 +547,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
|
||||
void *callback_state = (void *) PG_GETARG_POINTER(2);
|
||||
IndexBulkDeleteResult *result;
|
||||
BlockNumber num_pages;
|
||||
BlockNumber num_pages;
|
||||
double tuples_removed;
|
||||
double num_index_tuples;
|
||||
RetrieveIndexResult res;
|
||||
@@ -559,15 +559,16 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
num_index_tuples = 0;
|
||||
|
||||
/*
|
||||
* We use a standard IndexScanDesc scan object, but to speed up the loop,
|
||||
* we skip most of the wrapper layers of index_getnext and instead call
|
||||
* _bt_step directly. This implies holding buffer lock on a target page
|
||||
* throughout the loop over the page's tuples. Initially, we have a read
|
||||
* lock acquired by _bt_step when we stepped onto the page. If we find
|
||||
* a tuple we need to delete, we trade in the read lock for an exclusive
|
||||
* write lock; after that, we hold the write lock until we step off the
|
||||
* page (fortunately, _bt_relbuf doesn't care which kind of lock it's
|
||||
* releasing). This should minimize the amount of work needed per page.
|
||||
* We use a standard IndexScanDesc scan object, but to speed up the
|
||||
* loop, we skip most of the wrapper layers of index_getnext and
|
||||
* instead call _bt_step directly. This implies holding buffer lock
|
||||
* on a target page throughout the loop over the page's tuples.
|
||||
* Initially, we have a read lock acquired by _bt_step when we stepped
|
||||
* onto the page. If we find a tuple we need to delete, we trade in
|
||||
* the read lock for an exclusive write lock; after that, we hold the
|
||||
* write lock until we step off the page (fortunately, _bt_relbuf
|
||||
* doesn't care which kind of lock it's releasing). This should
|
||||
* minimize the amount of work needed per page.
|
||||
*/
|
||||
scan = index_beginscan(rel, false, 0, (ScanKey) NULL);
|
||||
so = (BTScanOpaque) scan->opaque;
|
||||
@@ -579,7 +580,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
if (res != NULL)
|
||||
{
|
||||
Buffer buf;
|
||||
BlockNumber lockedBlock = InvalidBlockNumber;
|
||||
BlockNumber lockedBlock = InvalidBlockNumber;
|
||||
|
||||
pfree(res);
|
||||
/* we have the buffer pinned and locked */
|
||||
@@ -589,11 +590,11 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
do
|
||||
{
|
||||
Page page;
|
||||
BlockNumber blkno;
|
||||
BlockNumber blkno;
|
||||
OffsetNumber offnum;
|
||||
BTItem btitem;
|
||||
IndexTuple itup;
|
||||
ItemPointer htup;
|
||||
ItemPointer htup;
|
||||
|
||||
/* current is the next index tuple */
|
||||
blkno = ItemPointerGetBlockNumber(current);
|
||||
@@ -607,9 +608,10 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/*
|
||||
* If this is first deletion on this page, trade in read
|
||||
* lock for a really-exclusive write lock. Then, step back
|
||||
* one and re-examine the item, because someone else might
|
||||
* have inserted an item while we weren't holding the lock!
|
||||
* lock for a really-exclusive write lock. Then, step
|
||||
* back one and re-examine the item, because someone else
|
||||
* might have inserted an item while we weren't holding
|
||||
* the lock!
|
||||
*/
|
||||
if (blkno != lockedBlock)
|
||||
{
|
||||
@@ -632,8 +634,8 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||
* We need to back up the scan one item so that the next
|
||||
* cycle will re-examine the same offnum on this page.
|
||||
*
|
||||
* For now, just hack the current-item index. Will need
|
||||
* to be smarter when deletion includes removal of empty
|
||||
* For now, just hack the current-item index. Will need to
|
||||
* be smarter when deletion includes removal of empty
|
||||
* index pages.
|
||||
*/
|
||||
current->ip_posid--;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.68 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.69 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -589,10 +589,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
|
||||
/*
|
||||
* At this point we are positioned at the first item >= scan key, or
|
||||
* possibly at the end of a page on which all the existing items are
|
||||
* greater than the scan key and we know that everything on later pages
|
||||
* is less than or equal to scan key.
|
||||
*
|
||||
* possibly at the end of a page on which all the existing items are
|
||||
* greater than the scan key and we know that everything on later
|
||||
* pages is less than or equal to scan key.
|
||||
*
|
||||
* We could step forward in the latter case, but that'd be a waste of
|
||||
* time if we want to scan backwards. So, it's now time to examine
|
||||
* the scan strategy to find the exact place to start the scan.
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.60 2001/03/22 03:59:15 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.61 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -108,7 +108,7 @@ static void _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2);
|
||||
/*
|
||||
* create and initialize a spool structure
|
||||
*/
|
||||
BTSpool *
|
||||
BTSpool *
|
||||
_bt_spoolinit(Relation index, bool isunique)
|
||||
{
|
||||
BTSpool *btspool = (BTSpool *) palloc(sizeof(BTSpool));
|
||||
@@ -354,7 +354,6 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
|
||||
if (pgspc < btisz || pgspc < state->btps_full)
|
||||
{
|
||||
|
||||
/*
|
||||
* Item won't fit on this page, or we feel the page is full enough
|
||||
* already. Finish off the page and write it out.
|
||||
@@ -544,7 +543,6 @@ _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
|
||||
|
||||
if (merge)
|
||||
{
|
||||
|
||||
/*
|
||||
* Another BTSpool for dead tuples exists. Now we have to merge
|
||||
* btspool and btspool2.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.14 2001/05/30 19:53:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtstrat.c,v 1.15 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -134,5 +134,4 @@ _bt_invokestrat(Relation rel,
|
||||
return (RelationInvokeStrategy(rel, &BTEvaluationData, attno, strat,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.46 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.47 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -221,7 +221,6 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
/* We can short-circuit most of the work if there's just one key */
|
||||
if (numberOfKeys == 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't use indices for 'A is null' and 'A is not null'
|
||||
* currently and 'A < = > <> NULL' will always fail - so qual is
|
||||
@@ -317,7 +316,6 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* No "=" for this key, so we're done with required keys
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.65 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.66 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -58,9 +58,9 @@ typedef struct SPLITVEC
|
||||
/* for sorting tuples by cost, for picking split */
|
||||
typedef struct SPLITCOST
|
||||
{
|
||||
OffsetNumber offset_number;
|
||||
float cost_differential;
|
||||
bool choose_left;
|
||||
OffsetNumber offset_number;
|
||||
float cost_differential;
|
||||
bool choose_left;
|
||||
} SPLITCOST;
|
||||
|
||||
typedef struct RTSTATE
|
||||
@@ -79,11 +79,11 @@ typedef struct
|
||||
|
||||
/* non-export function prototypes */
|
||||
static void rtbuildCallback(Relation index,
|
||||
HeapTuple htup,
|
||||
Datum *attdata,
|
||||
char *nulls,
|
||||
bool tupleIsAlive,
|
||||
void *state);
|
||||
HeapTuple htup,
|
||||
Datum *attdata,
|
||||
char *nulls,
|
||||
bool tupleIsAlive,
|
||||
void *state);
|
||||
static InsertIndexResult rtdoinsert(Relation r, IndexTuple itup,
|
||||
RTSTATE *rtstate);
|
||||
static void rttighten(Relation r, RTSTACK *stk, Datum datum, int att_size,
|
||||
@@ -100,7 +100,7 @@ static OffsetNumber choose(Relation r, Page p, IndexTuple it,
|
||||
RTSTATE *rtstate);
|
||||
static int nospace(Page p, IndexTuple it);
|
||||
static void initRtstate(RTSTATE *rtstate, Relation index);
|
||||
static int qsort_comp_splitcost(const void *a, const void *b);
|
||||
static int qsort_comp_splitcost(const void *a, const void *b);
|
||||
|
||||
|
||||
/*
|
||||
@@ -178,7 +178,7 @@ rtbuildCallback(Relation index,
|
||||
bool tupleIsAlive,
|
||||
void *state)
|
||||
{
|
||||
RTBuildState *buildstate = (RTBuildState *) state;
|
||||
RTBuildState *buildstate = (RTBuildState *) state;
|
||||
IndexTuple itup;
|
||||
InsertIndexResult res;
|
||||
|
||||
@@ -194,11 +194,11 @@ rtbuildCallback(Relation index,
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we already have the index relation locked, we call
|
||||
* rtdoinsert directly. Normal access method calls dispatch
|
||||
* through rtinsert, 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 whole index at once.
|
||||
* Since we already have the index relation locked, we call rtdoinsert
|
||||
* directly. Normal access method calls dispatch through rtinsert,
|
||||
* 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 whole index at once.
|
||||
*/
|
||||
res = rtdoinsert(index, itup, &buildstate->rtState);
|
||||
|
||||
@@ -223,6 +223,7 @@ rtinsert(PG_FUNCTION_ARGS)
|
||||
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
|
||||
char *nulls = (char *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
|
||||
#ifdef NOT_USED
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
#endif
|
||||
@@ -249,7 +250,7 @@ rtinsert(PG_FUNCTION_ARGS)
|
||||
|
||||
/*
|
||||
* Since rtree is not marked "amconcurrent" in pg_am, caller should
|
||||
* have acquired exclusive lock on index relation. We need no locking
|
||||
* have acquired exclusive lock on index relation. We need no locking
|
||||
* here.
|
||||
*/
|
||||
|
||||
@@ -376,9 +377,8 @@ rttighten(Relation r,
|
||||
PointerGetDatum(&newd_size));
|
||||
|
||||
/*
|
||||
* If newd_size == 0 we have degenerate rectangles, so we
|
||||
* don't know if there was any change, so we have to
|
||||
* assume there was.
|
||||
* If newd_size == 0 we have degenerate rectangles, so we don't know
|
||||
* if there was any change, so we have to assume there was.
|
||||
*/
|
||||
if ((newd_size == 0) || (newd_size != old_size))
|
||||
{
|
||||
@@ -386,7 +386,6 @@ rttighten(Relation r,
|
||||
|
||||
if (td->attrs[0]->attlen < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an internal page, so 'oldud' had better be a union
|
||||
* (constant-length) key, too. (See comment below.)
|
||||
@@ -500,10 +499,10 @@ rtdosplit(Relation r,
|
||||
res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
|
||||
|
||||
/*
|
||||
* spl_left contains a list of the offset numbers of the
|
||||
* tuples that will go to the left page. For each offset
|
||||
* number, get the tuple item, then add the item to the
|
||||
* left page. Similarly for the right side.
|
||||
* spl_left contains a list of the offset numbers of the tuples that
|
||||
* will go to the left page. For each offset number, get the tuple
|
||||
* item, then add the item to the left page. Similarly for the right
|
||||
* side.
|
||||
*/
|
||||
|
||||
/* fill left node */
|
||||
@@ -527,7 +526,7 @@ rtdosplit(Relation r,
|
||||
if (i == newitemoff)
|
||||
ItemPointerSet(&(res->pointerData), lbknum, leftoff);
|
||||
|
||||
spl_left++; /* advance in left split vector */
|
||||
spl_left++; /* advance in left split vector */
|
||||
}
|
||||
|
||||
/* fill right node */
|
||||
@@ -551,7 +550,7 @@ rtdosplit(Relation r,
|
||||
if (i == newitemoff)
|
||||
ItemPointerSet(&(res->pointerData), rbknum, rightoff);
|
||||
|
||||
spl_right++; /* advance in right split vector */
|
||||
spl_right++; /* advance in right split vector */
|
||||
}
|
||||
|
||||
/* Make sure we consumed all of the split vectors, and release 'em */
|
||||
@@ -764,9 +763,10 @@ rtpicksplit(Relation r,
|
||||
right_avail_space;
|
||||
int total_num_tuples,
|
||||
num_tuples_without_seeds,
|
||||
max_after_split; /* in Guttman's lingo, (M - m) */
|
||||
float diff; /* diff between cost of putting tuple left or right */
|
||||
SPLITCOST *cost_vector;
|
||||
max_after_split; /* in Guttman's lingo, (M - m) */
|
||||
float diff; /* diff between cost of putting tuple left
|
||||
* or right */
|
||||
SPLITCOST *cost_vector;
|
||||
int n;
|
||||
|
||||
/*
|
||||
@@ -852,7 +852,6 @@ rtpicksplit(Relation r,
|
||||
|
||||
if (firsttime)
|
||||
{
|
||||
|
||||
/*
|
||||
* There is no possible split except to put the new item on its
|
||||
* own page. Since we still have to compute the union rectangles,
|
||||
@@ -885,25 +884,25 @@ rtpicksplit(Relation r,
|
||||
/*
|
||||
* Now split up the regions between the two seeds.
|
||||
*
|
||||
* The cost_vector array will contain hints for determining where
|
||||
* each tuple should go. Each record in the array will contain
|
||||
* a boolean, choose_left, that indicates which node the tuple
|
||||
* prefers to be on, and the absolute difference in cost between
|
||||
* putting the tuple in its favored node and in the other node.
|
||||
* The cost_vector array will contain hints for determining where each
|
||||
* tuple should go. Each record in the array will contain a boolean,
|
||||
* choose_left, that indicates which node the tuple prefers to be on,
|
||||
* and the absolute difference in cost between putting the tuple in
|
||||
* its favored node and in the other node.
|
||||
*
|
||||
* Later, we will sort the cost_vector in descending order by cost
|
||||
* difference, and consider the tuples in that order for
|
||||
* placement. That way, the tuples that *really* want to be in
|
||||
* one node or the other get to choose first, and the tuples that
|
||||
* don't really care choose last.
|
||||
* difference, and consider the tuples in that order for placement.
|
||||
* That way, the tuples that *really* want to be in one node or the
|
||||
* other get to choose first, and the tuples that don't really care
|
||||
* choose last.
|
||||
*
|
||||
* First, build the cost_vector array. The new index tuple will
|
||||
* also be handled in this loop, and represented in the array,
|
||||
* with i==newitemoff.
|
||||
* First, build the cost_vector array. The new index tuple will also be
|
||||
* handled in this loop, and represented in the array, with
|
||||
* i==newitemoff.
|
||||
*
|
||||
* In the case of variable size tuples it is possible that we only
|
||||
* have the two seeds and no other tuples, in which case we don't
|
||||
* do any of this cost_vector stuff.
|
||||
* In the case of variable size tuples it is possible that we only have
|
||||
* the two seeds and no other tuples, in which case we don't do any of
|
||||
* this cost_vector stuff.
|
||||
*/
|
||||
|
||||
/* to keep compiler quiet */
|
||||
@@ -943,21 +942,21 @@ rtpicksplit(Relation r,
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the array. The function qsort_comp_splitcost is
|
||||
* set up "backwards", to provided descending order.
|
||||
* Sort the array. The function qsort_comp_splitcost is set up
|
||||
* "backwards", to provided descending order.
|
||||
*/
|
||||
qsort(cost_vector, num_tuples_without_seeds, sizeof(SPLITCOST),
|
||||
&qsort_comp_splitcost);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now make the final decisions about where each tuple will go,
|
||||
* and build the vectors to return in the SPLITVEC record.
|
||||
* Now make the final decisions about where each tuple will go, and
|
||||
* build the vectors to return in the SPLITVEC record.
|
||||
*
|
||||
* The cost_vector array contains (descriptions of) all the
|
||||
* tuples, in the order that we want to consider them, so we
|
||||
* we just iterate through it and place each tuple in left
|
||||
* or right nodes, according to the criteria described below.
|
||||
* The cost_vector array contains (descriptions of) all the tuples, in
|
||||
* the order that we want to consider them, so we we just iterate
|
||||
* through it and place each tuple in left or right nodes, according
|
||||
* to the criteria described below.
|
||||
*/
|
||||
|
||||
left = v->spl_left;
|
||||
@@ -965,9 +964,9 @@ rtpicksplit(Relation r,
|
||||
right = v->spl_right;
|
||||
v->spl_nright = 0;
|
||||
|
||||
/* Place the seeds first.
|
||||
* left avail space, left union, right avail space, and right
|
||||
* union have already been adjusted for the seeds.
|
||||
/*
|
||||
* Place the seeds first. left avail space, left union, right avail
|
||||
* space, and right union have already been adjusted for the seeds.
|
||||
*/
|
||||
|
||||
*left++ = seed_1;
|
||||
@@ -983,8 +982,8 @@ rtpicksplit(Relation r,
|
||||
choose_left;
|
||||
|
||||
/*
|
||||
* We need to figure out which page needs the least
|
||||
* enlargement in order to store the item.
|
||||
* We need to figure out which page needs the least enlargement in
|
||||
* order to store the item.
|
||||
*/
|
||||
|
||||
i = cost_vector[n].offset_number;
|
||||
@@ -1019,22 +1018,22 @@ rtpicksplit(Relation r,
|
||||
* the new item.)
|
||||
*
|
||||
* Guttman's algorithm actually has two factors to consider (in
|
||||
* order): 1. if one node has so many tuples already assigned to
|
||||
* order): 1. if one node has so many tuples already assigned to
|
||||
* it that the other needs all the rest in order to satisfy the
|
||||
* condition that neither node has fewer than m tuples, then
|
||||
* that is decisive; 2. otherwise, choose the page that shows
|
||||
* the smaller enlargement of its union area.
|
||||
* condition that neither node has fewer than m tuples, then that
|
||||
* is decisive; 2. otherwise, choose the page that shows the
|
||||
* smaller enlargement of its union area.
|
||||
*
|
||||
* I have chosen m = M/2, where M is the maximum number of
|
||||
* tuples on a page. (Actually, this is only strictly
|
||||
* true for fixed size tuples. For variable size tuples,
|
||||
* there still might have to be only one tuple on a page,
|
||||
* if it is really big. But even with variable size
|
||||
* tuples we still try to get m as close as possible to M/2.)
|
||||
* I have chosen m = M/2, where M is the maximum number of tuples on
|
||||
* a page. (Actually, this is only strictly true for fixed size
|
||||
* tuples. For variable size tuples, there still might have to be
|
||||
* only one tuple on a page, if it is really big. But even with
|
||||
* variable size tuples we still try to get m as close as possible
|
||||
* to M/2.)
|
||||
*
|
||||
* The question of which page shows the smaller enlargement of
|
||||
* its union area has already been answered, and the answer
|
||||
* stored in the choose_left field of the SPLITCOST record.
|
||||
* The question of which page shows the smaller enlargement of its
|
||||
* union area has already been answered, and the answer stored in
|
||||
* the choose_left field of the SPLITCOST record.
|
||||
*/
|
||||
left_feasible = (left_avail_space >= item_1_sz &&
|
||||
((left_avail_space - item_1_sz) >= newitemsz ||
|
||||
@@ -1045,10 +1044,10 @@ rtpicksplit(Relation r,
|
||||
if (left_feasible && right_feasible)
|
||||
{
|
||||
/*
|
||||
* Both feasible, use Guttman's algorithm.
|
||||
* First check the m condition described above, and if
|
||||
* that doesn't apply, choose the page with the smaller
|
||||
* enlargement of its union area.
|
||||
* Both feasible, use Guttman's algorithm. First check the m
|
||||
* condition described above, and if that doesn't apply,
|
||||
* choose the page with the smaller enlargement of its union
|
||||
* area.
|
||||
*/
|
||||
if (v->spl_nleft > max_after_split)
|
||||
choose_left = false;
|
||||
@@ -1064,7 +1063,7 @@ rtpicksplit(Relation r,
|
||||
else
|
||||
{
|
||||
elog(ERROR, "rtpicksplit: failed to find a workable page split");
|
||||
choose_left = false;/* keep compiler quiet */
|
||||
choose_left = false; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
if (choose_left)
|
||||
@@ -1090,9 +1089,7 @@ rtpicksplit(Relation r,
|
||||
}
|
||||
|
||||
if (num_tuples_without_seeds > 0)
|
||||
{
|
||||
pfree(cost_vector);
|
||||
}
|
||||
|
||||
*left = *right = InvalidOffsetNumber; /* add ending sentinels */
|
||||
|
||||
@@ -1189,7 +1186,7 @@ rtbulkdelete(PG_FUNCTION_ARGS)
|
||||
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
|
||||
void *callback_state = (void *) PG_GETARG_POINTER(2);
|
||||
IndexBulkDeleteResult *result;
|
||||
BlockNumber num_pages;
|
||||
BlockNumber num_pages;
|
||||
double tuples_removed;
|
||||
double num_index_tuples;
|
||||
RetrieveIndexResult res;
|
||||
@@ -1200,7 +1197,7 @@ rtbulkdelete(PG_FUNCTION_ARGS)
|
||||
|
||||
/*
|
||||
* Since rtree is not marked "amconcurrent" in pg_am, caller should
|
||||
* have acquired exclusive lock on index relation. We need no locking
|
||||
* have acquired exclusive lock on index relation. We need no locking
|
||||
* here.
|
||||
*/
|
||||
|
||||
@@ -1279,9 +1276,10 @@ initRtstate(RTSTATE *rtstate, Relation index)
|
||||
static int
|
||||
qsort_comp_splitcost(const void *a, const void *b)
|
||||
{
|
||||
float diff =
|
||||
((SPLITCOST *)a)->cost_differential -
|
||||
((SPLITCOST *)b)->cost_differential;
|
||||
float diff =
|
||||
((SPLITCOST *) a)->cost_differential -
|
||||
((SPLITCOST *) b)->cost_differential;
|
||||
|
||||
if (diff < 0)
|
||||
return 1;
|
||||
else if (diff > 0)
|
||||
@@ -1342,7 +1340,6 @@ _rtdump(Relation r)
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined RTDEBUG */
|
||||
|
||||
void
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.38 2001/07/15 22:48:16 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.39 2001/10/25 05:49:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -380,7 +380,6 @@ adjustiptr(IndexScanDesc s,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* remember that we're before the current
|
||||
* tuple
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.17 2001/05/30 19:53:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtstrat.c,v 1.18 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -163,7 +163,7 @@ static StrategyExpression RTEvaluationExpressions[RTNStrategies] = {
|
||||
NULL, /* express overlap */
|
||||
NULL, /* express overright */
|
||||
NULL, /* express right */
|
||||
(StrategyExpression) RTEqualExpressionData, /* express same */
|
||||
(StrategyExpression) RTEqualExpressionData, /* express same */
|
||||
NULL, /* express contains */
|
||||
NULL /* express contained-by */
|
||||
};
|
||||
@@ -221,7 +221,6 @@ RelationInvokeRTStrategy(Relation r,
|
||||
return (RelationInvokeStrategy(r, &RTEvaluationData, attnum, s,
|
||||
left, right));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
RegProcedure
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.4 2001/09/29 04:02:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.5 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
/*
|
||||
* Defines for CLOG page and segment sizes. A page is the same BLCKSZ
|
||||
* as is used everywhere else in Postgres. The CLOG segment size can be
|
||||
* as is used everywhere else in Postgres. The CLOG segment size can be
|
||||
* chosen somewhat arbitrarily; we make it 1 million transactions by default,
|
||||
* or 256Kb.
|
||||
*
|
||||
@@ -48,15 +48,15 @@
|
||||
|
||||
/* We need two bits per xact, so four xacts fit in a byte */
|
||||
#define CLOG_BITS_PER_XACT 2
|
||||
#define CLOG_XACTS_PER_BYTE 4
|
||||
#define CLOG_XACTS_PER_PAGE (CLOG_BLCKSZ * CLOG_XACTS_PER_BYTE)
|
||||
#define CLOG_XACTS_PER_BYTE 4
|
||||
#define CLOG_XACTS_PER_PAGE (CLOG_BLCKSZ * CLOG_XACTS_PER_BYTE)
|
||||
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
|
||||
|
||||
#define CLOG_XACTS_PER_SEGMENT 0x100000
|
||||
#define CLOG_PAGES_PER_SEGMENT (CLOG_XACTS_PER_SEGMENT / CLOG_XACTS_PER_PAGE)
|
||||
|
||||
#define TransactionIdToPage(xid) ((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)
|
||||
#define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE)
|
||||
#define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE)
|
||||
#define TransactionIdToByte(xid) (TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)
|
||||
#define TransactionIdToBIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)
|
||||
|
||||
@@ -101,15 +101,15 @@
|
||||
* the control lock.
|
||||
*
|
||||
* As with the regular buffer manager, it is possible for another process
|
||||
* to re-dirty a page that is currently being written out. This is handled
|
||||
* to re-dirty a page that is currently being written out. This is handled
|
||||
* by setting the page's state from WRITE_IN_PROGRESS to DIRTY. The writing
|
||||
* process must notice this and not mark the page CLEAN when it's done.
|
||||
*
|
||||
* XLOG interactions: this module generates an XLOG record whenever a new
|
||||
* CLOG page is initialized to zeroes. Other writes of CLOG come from
|
||||
* CLOG page is initialized to zeroes. Other writes of CLOG come from
|
||||
* recording of transaction commit or abort in xact.c, which generates its
|
||||
* own XLOG records for these events and will re-perform the status update
|
||||
* on redo; so we need make no additional XLOG entry here. Also, the XLOG
|
||||
* on redo; so we need make no additional XLOG entry here. Also, the XLOG
|
||||
* is guaranteed flushed through the XLOG commit record before we are called
|
||||
* to log a commit, so the WAL rule "write xlog before data" is satisfied
|
||||
* automatically for commits, and we don't really care for aborts. Therefore,
|
||||
@@ -120,11 +120,13 @@
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLOG_PAGE_EMPTY, /* CLOG buffer is not in use */
|
||||
CLOG_PAGE_READ_IN_PROGRESS, /* CLOG page is being read in */
|
||||
CLOG_PAGE_CLEAN, /* CLOG page is valid and not dirty */
|
||||
CLOG_PAGE_DIRTY, /* CLOG page is valid but needs write */
|
||||
CLOG_PAGE_WRITE_IN_PROGRESS /* CLOG page is being written out in */
|
||||
CLOG_PAGE_EMPTY,/* CLOG buffer is not in use */
|
||||
CLOG_PAGE_READ_IN_PROGRESS, /* CLOG page is being read
|
||||
* in */
|
||||
CLOG_PAGE_CLEAN,/* CLOG page is valid and not dirty */
|
||||
CLOG_PAGE_DIRTY,/* CLOG page is valid but needs write */
|
||||
CLOG_PAGE_WRITE_IN_PROGRESS /* CLOG page is being
|
||||
* written out in */
|
||||
} ClogPageStatus;
|
||||
|
||||
/*
|
||||
@@ -134,14 +136,15 @@ typedef struct ClogCtlData
|
||||
{
|
||||
/*
|
||||
* Info for each buffer slot. Page number is undefined when status is
|
||||
* EMPTY. lru_count is essentially the number of operations since last
|
||||
* use of this page; the page with highest lru_count is the best candidate
|
||||
* to replace.
|
||||
* EMPTY. lru_count is essentially the number of operations since
|
||||
* last use of this page; the page with highest lru_count is the best
|
||||
* candidate to replace.
|
||||
*/
|
||||
char *page_buffer[NUM_CLOG_BUFFERS];
|
||||
ClogPageStatus page_status[NUM_CLOG_BUFFERS];
|
||||
ClogPageStatus page_status[NUM_CLOG_BUFFERS];
|
||||
int page_number[NUM_CLOG_BUFFERS];
|
||||
unsigned int page_lru_count[NUM_CLOG_BUFFERS];
|
||||
unsigned int page_lru_count[NUM_CLOG_BUFFERS];
|
||||
|
||||
/*
|
||||
* latest_page_number is the page number of the current end of the
|
||||
* CLOG; this is not critical data, since we use it only to avoid
|
||||
@@ -157,7 +160,7 @@ static ClogCtlData *ClogCtl = NULL;
|
||||
* The value is automatically inherited by backends via fork, and
|
||||
* doesn't need to be in shared memory.
|
||||
*/
|
||||
static LWLockId ClogBufferLocks[NUM_CLOG_BUFFERS]; /* Per-buffer I/O locks */
|
||||
static LWLockId ClogBufferLocks[NUM_CLOG_BUFFERS]; /* Per-buffer I/O locks */
|
||||
|
||||
/*
|
||||
* ClogDir is set during CLOGShmemInit and does not change thereafter.
|
||||
@@ -166,7 +169,7 @@ static LWLockId ClogBufferLocks[NUM_CLOG_BUFFERS]; /* Per-buffer I/O locks */
|
||||
*/
|
||||
static char ClogDir[MAXPGPATH];
|
||||
|
||||
#define ClogFileName(path, seg) \
|
||||
#define ClogFileName(path, seg) \
|
||||
snprintf(path, MAXPGPATH, "%s/%04X", ClogDir, seg)
|
||||
|
||||
/*
|
||||
@@ -430,7 +433,7 @@ ReadCLOGPage(int pageno)
|
||||
LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
|
||||
|
||||
Assert(ClogCtl->page_number[slotno] == pageno &&
|
||||
ClogCtl->page_status[slotno] == CLOG_PAGE_READ_IN_PROGRESS);
|
||||
ClogCtl->page_status[slotno] == CLOG_PAGE_READ_IN_PROGRESS);
|
||||
|
||||
ClogCtl->page_status[slotno] = CLOG_PAGE_CLEAN;
|
||||
|
||||
@@ -447,7 +450,7 @@ ReadCLOGPage(int pageno)
|
||||
*
|
||||
* NOTE: only one write attempt is made here. Hence, it is possible that
|
||||
* the page is still dirty at exit (if someone else re-dirtied it during
|
||||
* the write). However, we *do* attempt a fresh write even if the page
|
||||
* the write). However, we *do* attempt a fresh write even if the page
|
||||
* is already being written; this is for checkpoints.
|
||||
*
|
||||
* Control lock must be held at entry, and will be held at exit.
|
||||
@@ -455,7 +458,7 @@ ReadCLOGPage(int pageno)
|
||||
static void
|
||||
WriteCLOGPage(int slotno)
|
||||
{
|
||||
int pageno;
|
||||
int pageno;
|
||||
|
||||
/* Do nothing if page does not need writing */
|
||||
if (ClogCtl->page_status[slotno] != CLOG_PAGE_DIRTY &&
|
||||
@@ -489,11 +492,12 @@ WriteCLOGPage(int slotno)
|
||||
* update on this page will mark it dirty again. NB: we are assuming
|
||||
* that read/write of the page status field is atomic, since we change
|
||||
* the state while not holding control lock. However, we cannot set
|
||||
* this state any sooner, or we'd possibly fool a previous writer
|
||||
* into thinking he's successfully dumped the page when he hasn't.
|
||||
* (Scenario: other writer starts, page is redirtied, we come along and
|
||||
* set WRITE_IN_PROGRESS again, other writer completes and sets CLEAN
|
||||
* because redirty info has been lost, then we think it's clean too.)
|
||||
* this state any sooner, or we'd possibly fool a previous writer into
|
||||
* thinking he's successfully dumped the page when he hasn't.
|
||||
* (Scenario: other writer starts, page is redirtied, we come along
|
||||
* and set WRITE_IN_PROGRESS again, other writer completes and sets
|
||||
* CLEAN because redirty info has been lost, then we think it's clean
|
||||
* too.)
|
||||
*/
|
||||
ClogCtl->page_status[slotno] = CLOG_PAGE_WRITE_IN_PROGRESS;
|
||||
|
||||
@@ -523,7 +527,7 @@ WriteCLOGPage(int slotno)
|
||||
static void
|
||||
CLOGPhysicalReadPage(int pageno, int slotno)
|
||||
{
|
||||
int segno = pageno / CLOG_PAGES_PER_SEGMENT;
|
||||
int segno = pageno / CLOG_PAGES_PER_SEGMENT;
|
||||
int rpageno = pageno % CLOG_PAGES_PER_SEGMENT;
|
||||
int offset = rpageno * CLOG_BLCKSZ;
|
||||
char path[MAXPGPATH];
|
||||
@@ -533,9 +537,9 @@ CLOGPhysicalReadPage(int pageno, int slotno)
|
||||
|
||||
/*
|
||||
* In a crash-and-restart situation, it's possible for us to receive
|
||||
* commands to set the commit status of transactions whose bits are
|
||||
* in already-truncated segments of the commit log (see notes in
|
||||
* CLOGPhysicalWritePage). Hence, if we are InRecovery, allow the
|
||||
* commands to set the commit status of transactions whose bits are in
|
||||
* already-truncated segments of the commit log (see notes in
|
||||
* CLOGPhysicalWritePage). Hence, if we are InRecovery, allow the
|
||||
* case where the file doesn't exist, and return zeroes instead.
|
||||
*/
|
||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
@@ -569,7 +573,7 @@ CLOGPhysicalReadPage(int pageno, int slotno)
|
||||
static void
|
||||
CLOGPhysicalWritePage(int pageno, int slotno)
|
||||
{
|
||||
int segno = pageno / CLOG_PAGES_PER_SEGMENT;
|
||||
int segno = pageno / CLOG_PAGES_PER_SEGMENT;
|
||||
int rpageno = pageno % CLOG_PAGES_PER_SEGMENT;
|
||||
int offset = rpageno * CLOG_BLCKSZ;
|
||||
char path[MAXPGPATH];
|
||||
@@ -578,16 +582,17 @@ CLOGPhysicalWritePage(int pageno, int slotno)
|
||||
ClogFileName(path, segno);
|
||||
|
||||
/*
|
||||
* If the file doesn't already exist, we should create it. It is possible
|
||||
* for this to need to happen when writing a page that's not first in
|
||||
* its segment; we assume the OS can cope with that. (Note: it might seem
|
||||
* that it'd be okay to create files only when ZeroCLOGPage is called for
|
||||
* the first page of a segment. However, if after a crash and restart
|
||||
* the REDO logic elects to replay the log from a checkpoint before the
|
||||
* latest one, then it's possible that we will get commands to set
|
||||
* transaction status of transactions that have already been truncated
|
||||
* from the commit log. Easiest way to deal with that is to accept
|
||||
* references to nonexistent files here and in CLOGPhysicalReadPage.)
|
||||
* If the file doesn't already exist, we should create it. It is
|
||||
* possible for this to need to happen when writing a page that's not
|
||||
* first in its segment; we assume the OS can cope with that. (Note:
|
||||
* it might seem that it'd be okay to create files only when
|
||||
* ZeroCLOGPage is called for the first page of a segment. However,
|
||||
* if after a crash and restart the REDO logic elects to replay the
|
||||
* log from a checkpoint before the latest one, then it's possible
|
||||
* that we will get commands to set transaction status of transactions
|
||||
* that have already been truncated from the commit log. Easiest way
|
||||
* to deal with that is to accept references to nonexistent files here
|
||||
* and in CLOGPhysicalReadPage.)
|
||||
*/
|
||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
@@ -649,16 +654,15 @@ SelectLRUCLOGPage(int pageno)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we find any EMPTY slot, just select that one.
|
||||
* Else locate the least-recently-used slot that isn't the
|
||||
* latest CLOG page.
|
||||
* If we find any EMPTY slot, just select that one. Else locate
|
||||
* the least-recently-used slot that isn't the latest CLOG page.
|
||||
*/
|
||||
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
|
||||
{
|
||||
if (ClogCtl->page_status[slotno] == CLOG_PAGE_EMPTY)
|
||||
return slotno;
|
||||
if (ClogCtl->page_lru_count[slotno] > bestcount &&
|
||||
ClogCtl->page_number[slotno] != ClogCtl->latest_page_number)
|
||||
ClogCtl->page_number[slotno] != ClogCtl->latest_page_number)
|
||||
{
|
||||
bestslot = slotno;
|
||||
bestcount = ClogCtl->page_lru_count[slotno];
|
||||
@@ -672,10 +676,10 @@ SelectLRUCLOGPage(int pageno)
|
||||
return bestslot;
|
||||
|
||||
/*
|
||||
* We need to do I/O. Normal case is that we have to write it out,
|
||||
* but it's possible in the worst case to have selected a read-busy
|
||||
* page. In that case we use ReadCLOGPage to wait for the read to
|
||||
* complete.
|
||||
* We need to do I/O. Normal case is that we have to write it
|
||||
* out, but it's possible in the worst case to have selected a
|
||||
* read-busy page. In that case we use ReadCLOGPage to wait for
|
||||
* the read to complete.
|
||||
*/
|
||||
if (ClogCtl->page_status[bestslot] == CLOG_PAGE_READ_IN_PROGRESS)
|
||||
(void) ReadCLOGPage(ClogCtl->page_number[bestslot]);
|
||||
@@ -683,9 +687,9 @@ SelectLRUCLOGPage(int pageno)
|
||||
WriteCLOGPage(bestslot);
|
||||
|
||||
/*
|
||||
* Now loop back and try again. This is the easiest way of dealing
|
||||
* with corner cases such as the victim page being re-dirtied while
|
||||
* we wrote it.
|
||||
* Now loop back and try again. This is the easiest way of
|
||||
* dealing with corner cases such as the victim page being
|
||||
* re-dirtied while we wrote it.
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -736,6 +740,7 @@ CheckPointCLOG(void)
|
||||
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
|
||||
{
|
||||
WriteCLOGPage(slotno);
|
||||
|
||||
/*
|
||||
* We cannot assert that the slot is clean now, since another
|
||||
* process might have re-dirtied it already. That's okay.
|
||||
@@ -782,13 +787,13 @@ ExtendCLOG(TransactionId newestXact)
|
||||
* Remove all CLOG segments before the one holding the passed transaction ID
|
||||
*
|
||||
* When this is called, we know that the database logically contains no
|
||||
* reference to transaction IDs older than oldestXact. However, we must
|
||||
* reference to transaction IDs older than oldestXact. However, we must
|
||||
* not truncate the CLOG until we have performed a checkpoint, to ensure
|
||||
* that no such references remain on disk either; else a crash just after
|
||||
* the truncation might leave us with a problem. Since CLOG segments hold
|
||||
* a large number of transactions, the opportunity to actually remove a
|
||||
* segment is fairly rare, and so it seems best not to do the checkpoint
|
||||
* unless we have confirmed that there is a removable segment. Therefore
|
||||
* unless we have confirmed that there is a removable segment. Therefore
|
||||
* we issue the checkpoint command here, not in higher-level code as might
|
||||
* seem cleaner.
|
||||
*/
|
||||
@@ -813,15 +818,16 @@ TruncateCLOG(TransactionId oldestXact)
|
||||
/*
|
||||
* Scan CLOG shared memory and remove any pages preceding the cutoff
|
||||
* page, to ensure we won't rewrite them later. (Any dirty pages
|
||||
* should have been flushed already during the checkpoint, we're
|
||||
* just being extra careful here.)
|
||||
* should have been flushed already during the checkpoint, we're just
|
||||
* being extra careful here.)
|
||||
*/
|
||||
LWLockAcquire(CLogControlLock, LW_EXCLUSIVE);
|
||||
|
||||
restart:;
|
||||
|
||||
/*
|
||||
* While we are holding the lock, make an important safety check:
|
||||
* the planned cutoff point must be <= the current CLOG endpoint page.
|
||||
* While we are holding the lock, make an important safety check: the
|
||||
* planned cutoff point must be <= the current CLOG endpoint page.
|
||||
* Otherwise we have already wrapped around, and proceeding with the
|
||||
* truncation would risk removing the current CLOG segment.
|
||||
*/
|
||||
@@ -838,6 +844,7 @@ restart:;
|
||||
continue;
|
||||
if (!CLOGPagePrecedes(ClogCtl->page_number[slotno], cutoffPage))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If page is CLEAN, just change state to EMPTY (expected case).
|
||||
*/
|
||||
@@ -846,6 +853,7 @@ restart:;
|
||||
ClogCtl->page_status[slotno] = CLOG_PAGE_EMPTY;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hmm, we have (or may have) I/O operations acting on the page,
|
||||
* so we've got to wait for them to finish and then start again.
|
||||
@@ -928,9 +936,11 @@ CLOGPagePrecedes(int page1, int page2)
|
||||
TransactionId xid1;
|
||||
TransactionId xid2;
|
||||
|
||||
xid1 = (TransactionId) page1 * CLOG_XACTS_PER_PAGE;
|
||||
xid1 = (TransactionId) page1 *CLOG_XACTS_PER_PAGE;
|
||||
|
||||
xid1 += FirstNormalTransactionId;
|
||||
xid2 = (TransactionId) page2 * CLOG_XACTS_PER_PAGE;
|
||||
xid2 = (TransactionId) page2 *CLOG_XACTS_PER_PAGE;
|
||||
|
||||
xid2 += FirstNormalTransactionId;
|
||||
|
||||
return TransactionIdPrecedes(xid1, xid2);
|
||||
@@ -966,8 +976,8 @@ clog_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
if (info == CLOG_ZEROPAGE)
|
||||
{
|
||||
int pageno;
|
||||
int slotno;
|
||||
int pageno;
|
||||
int slotno;
|
||||
|
||||
memcpy(&pageno, XLogRecGetData(record), sizeof(int));
|
||||
|
||||
@@ -993,7 +1003,7 @@ clog_desc(char *buf, uint8 xl_info, char *rec)
|
||||
|
||||
if (info == CLOG_ZEROPAGE)
|
||||
{
|
||||
int pageno;
|
||||
int pageno;
|
||||
|
||||
memcpy(&pageno, rec, sizeof(int));
|
||||
sprintf(buf + strlen(buf), "zeropage: %d", pageno);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.48 2001/08/26 16:55:59 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.49 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains the high level access-method interface to the
|
||||
@@ -32,7 +32,7 @@ static void TransactionLogUpdate(TransactionId transactionId,
|
||||
* ----------------
|
||||
*/
|
||||
static TransactionId cachedTestXid = InvalidTransactionId;
|
||||
static XidStatus cachedTestXidStatus;
|
||||
static XidStatus cachedTestXidStatus;
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -56,8 +56,8 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
||||
XidStatus xidstatus; /* recorded status of xid */
|
||||
|
||||
/*
|
||||
* Before going to the commit log manager, check our single item cache to
|
||||
* see if we didn't just check the transaction status a moment ago.
|
||||
* Before going to the commit log manager, check our single item cache
|
||||
* to see if we didn't just check the transaction status a moment ago.
|
||||
*/
|
||||
if (TransactionIdEquals(transactionId, cachedTestXid))
|
||||
return (status == cachedTestXidStatus);
|
||||
@@ -65,7 +65,7 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
||||
/*
|
||||
* Also, check to see if the transaction ID is a permanent one.
|
||||
*/
|
||||
if (! TransactionIdIsNormal(transactionId))
|
||||
if (!TransactionIdIsNormal(transactionId))
|
||||
{
|
||||
if (TransactionIdEquals(transactionId, BootstrapTransactionId))
|
||||
return (status == TRANSACTION_STATUS_COMMITTED);
|
||||
@@ -77,18 +77,18 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */
|
||||
/*
|
||||
* Get the status.
|
||||
*/
|
||||
xidstatus = TransactionIdGetStatus(transactionId);
|
||||
xidstatus = TransactionIdGetStatus(transactionId);
|
||||
|
||||
/*
|
||||
* DO NOT cache status for unfinished transactions!
|
||||
*/
|
||||
if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS)
|
||||
{
|
||||
TransactionIdStore(transactionId, &cachedTestXid);
|
||||
cachedTestXidStatus = xidstatus;
|
||||
}
|
||||
/*
|
||||
* DO NOT cache status for unfinished transactions!
|
||||
*/
|
||||
if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS)
|
||||
{
|
||||
TransactionIdStore(transactionId, &cachedTestXid);
|
||||
cachedTestXidStatus = xidstatus;
|
||||
}
|
||||
|
||||
return (status == xidstatus);
|
||||
return (status == xidstatus);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
@@ -197,7 +197,7 @@ TransactionIdIsInProgress(TransactionId transactionId)
|
||||
|
||||
return TransactionLogTest(transactionId, TRANSACTION_STATUS_IN_PROGRESS);
|
||||
}
|
||||
#endif /* NOT_USED */
|
||||
#endif /* NOT_USED */
|
||||
|
||||
/* --------------------------------
|
||||
* TransactionId Commit
|
||||
@@ -246,7 +246,7 @@ TransactionIdPrecedes(TransactionId id1, TransactionId id2)
|
||||
{
|
||||
/*
|
||||
* If either ID is a permanent XID then we can just do unsigned
|
||||
* comparison. If both are normal, do a modulo-2^31 comparison.
|
||||
* comparison. If both are normal, do a modulo-2^31 comparison.
|
||||
*/
|
||||
int32 diff;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2000, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.46 2001/09/29 04:02:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.47 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -32,7 +32,7 @@ VariableCache ShmemVariableCache = NULL;
|
||||
TransactionId
|
||||
GetNewTransactionId(void)
|
||||
{
|
||||
TransactionId xid;
|
||||
TransactionId xid;
|
||||
|
||||
/*
|
||||
* During bootstrap initialization, we return the special bootstrap
|
||||
@@ -48,32 +48,32 @@ GetNewTransactionId(void)
|
||||
TransactionIdAdvance(ShmemVariableCache->nextXid);
|
||||
|
||||
/*
|
||||
* If we have just allocated the first XID of a new page of the
|
||||
* commit log, zero out that commit-log page before returning.
|
||||
* We must do this while holding XidGenLock, else another xact could
|
||||
* acquire and commit a later XID before we zero the page. Fortunately,
|
||||
* a page of the commit log holds 32K or more transactions, so we don't
|
||||
* have to do this very often.
|
||||
* If we have just allocated the first XID of a new page of the commit
|
||||
* log, zero out that commit-log page before returning. We must do
|
||||
* this while holding XidGenLock, else another xact could acquire and
|
||||
* commit a later XID before we zero the page. Fortunately, a page of
|
||||
* the commit log holds 32K or more transactions, so we don't have to
|
||||
* do this very often.
|
||||
*/
|
||||
ExtendCLOG(xid);
|
||||
|
||||
/*
|
||||
* Must set MyProc->xid before releasing XidGenLock. This ensures that
|
||||
* when GetSnapshotData calls ReadNewTransactionId, all active XIDs
|
||||
* before the returned value of nextXid are already present in the shared
|
||||
* PROC array. Else we have a race condition.
|
||||
* Must set MyProc->xid before releasing XidGenLock. This ensures
|
||||
* that when GetSnapshotData calls ReadNewTransactionId, all active
|
||||
* XIDs before the returned value of nextXid are already present in
|
||||
* the shared PROC array. Else we have a race condition.
|
||||
*
|
||||
* XXX by storing xid into MyProc without acquiring SInvalLock, we are
|
||||
* relying on fetch/store of an xid to be atomic, else other backends
|
||||
* might see a partially-set xid here. But holding both locks at once
|
||||
* would be a nasty concurrency hit (and in fact could cause a deadlock
|
||||
* against GetSnapshotData). So for now, assume atomicity. Note that
|
||||
* readers of PROC xid field should be careful to fetch the value only
|
||||
* once, rather than assume they can read it multiple times and get the
|
||||
* same answer each time.
|
||||
* might see a partially-set xid here. But holding both locks at once
|
||||
* would be a nasty concurrency hit (and in fact could cause a
|
||||
* deadlock against GetSnapshotData). So for now, assume atomicity.
|
||||
* Note that readers of PROC xid field should be careful to fetch the
|
||||
* value only once, rather than assume they can read it multiple times
|
||||
* and get the same answer each time.
|
||||
*
|
||||
* A solution to the atomic-store problem would be to give each PROC
|
||||
* its own spinlock used only for fetching/storing that PROC's xid.
|
||||
* A solution to the atomic-store problem would be to give each PROC its
|
||||
* own spinlock used only for fetching/storing that PROC's xid.
|
||||
* (SInvalLock would then mean primarily that PROCs couldn't be added/
|
||||
* removed while holding the lock.)
|
||||
*/
|
||||
@@ -91,7 +91,7 @@ GetNewTransactionId(void)
|
||||
TransactionId
|
||||
ReadNewTransactionId(void)
|
||||
{
|
||||
TransactionId xid;
|
||||
TransactionId xid;
|
||||
|
||||
/*
|
||||
* During bootstrap initialization, we return the special bootstrap
|
||||
@@ -117,16 +117,16 @@ static Oid lastSeenOid = InvalidOid;
|
||||
Oid
|
||||
GetNewObjectId(void)
|
||||
{
|
||||
Oid result;
|
||||
Oid result;
|
||||
|
||||
LWLockAcquire(OidGenLock, LW_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* Check for wraparound of the OID counter. We *must* not return 0
|
||||
* (InvalidOid); and as long as we have to check that, it seems a good
|
||||
* idea to skip over everything below BootstrapObjectIdData too. (This
|
||||
* basically just reduces the odds of OID collision right after a wrap
|
||||
* occurs.) Note we are relying on unsigned comparison here.
|
||||
* idea to skip over everything below BootstrapObjectIdData too.
|
||||
* (This basically just reduces the odds of OID collision right after
|
||||
* a wrap occurs.) Note we are relying on unsigned comparison here.
|
||||
*/
|
||||
if (ShmemVariableCache->nextOid < ((Oid) BootstrapObjectIdData))
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.112 2001/10/18 17:30:03 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.113 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Transaction aborts can now occur two ways:
|
||||
@@ -300,7 +300,6 @@ IsTransactionState(void)
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------
|
||||
@@ -476,7 +475,6 @@ AtStart_Cache(void)
|
||||
static void
|
||||
AtStart_Locks(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* at present, it is unknown to me what belongs here -cim 3/18/90
|
||||
*
|
||||
@@ -492,7 +490,6 @@ AtStart_Locks(void)
|
||||
static void
|
||||
AtStart_Memory(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* We shouldn't have any transaction contexts already.
|
||||
*/
|
||||
@@ -717,8 +714,8 @@ RecordTransactionAbort(void)
|
||||
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata);
|
||||
|
||||
/*
|
||||
* There's no need for XLogFlush here, since the default assumption
|
||||
* would be that we aborted, anyway.
|
||||
* There's no need for XLogFlush here, since the default
|
||||
* assumption would be that we aborted, anyway.
|
||||
*/
|
||||
|
||||
/* Mark the transaction aborted in clog */
|
||||
@@ -756,7 +753,6 @@ AtAbort_Cache(void)
|
||||
static void
|
||||
AtAbort_Locks(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX What if ProcReleaseLocks() fails? (race condition?)
|
||||
*
|
||||
@@ -773,7 +769,6 @@ AtAbort_Locks(void)
|
||||
static void
|
||||
AtAbort_Memory(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Make sure we are in a valid context (not a child of
|
||||
* TransactionCommandContext...). Note that it is possible for this
|
||||
@@ -807,7 +802,6 @@ AtAbort_Memory(void)
|
||||
static void
|
||||
AtCleanup_Memory(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Now that we're "out" of a transaction, have the system allocate
|
||||
* things in the top memory context instead of per-transaction
|
||||
@@ -909,7 +903,6 @@ CurrentXactInProgress(void)
|
||||
{
|
||||
return CurrentTransactionState->state == TRANS_INPROGRESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------
|
||||
@@ -965,12 +958,11 @@ CommitTransaction(void)
|
||||
* this must be done _before_ releasing locks we hold and _after_
|
||||
* RecordTransactionCommit.
|
||||
*
|
||||
* LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked
|
||||
* by xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot -
|
||||
* if xid 2' GetSnapshotData sees xid 1 as running then it must see
|
||||
* xid 0 as running as well or it will see two tuple versions - one
|
||||
* deleted by xid 1 and one inserted by xid 0. See notes in
|
||||
* GetSnapshotData.
|
||||
* LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
|
||||
* xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
|
||||
* xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
|
||||
* as running as well or it will see two tuple versions - one deleted
|
||||
* by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
|
||||
*/
|
||||
if (MyProc != (PROC *) NULL)
|
||||
{
|
||||
@@ -1002,7 +994,7 @@ CommitTransaction(void)
|
||||
AtCommit_Memory();
|
||||
AtEOXact_Files();
|
||||
|
||||
SharedBufferChanged = false;/* safest place to do it */
|
||||
SharedBufferChanged = false; /* safest place to do it */
|
||||
|
||||
/* Count transaction commit in statistics collector */
|
||||
pgstat_count_xact_commit();
|
||||
@@ -1032,8 +1024,8 @@ AbortTransaction(void)
|
||||
/*
|
||||
* Release any LW locks we might be holding as quickly as possible.
|
||||
* (Regular locks, however, must be held till we finish aborting.)
|
||||
* Releasing LW locks is critical since we might try to grab them again
|
||||
* while cleaning up!
|
||||
* Releasing LW locks is critical since we might try to grab them
|
||||
* again while cleaning up!
|
||||
*/
|
||||
LWLockReleaseAll();
|
||||
|
||||
@@ -1105,7 +1097,7 @@ AbortTransaction(void)
|
||||
AtEOXact_Files();
|
||||
AtAbort_Locks();
|
||||
|
||||
SharedBufferChanged = false;/* safest place to do it */
|
||||
SharedBufferChanged = false; /* safest place to do it */
|
||||
|
||||
/* Count transaction abort in statistics collector */
|
||||
pgstat_count_xact_rollback();
|
||||
@@ -1155,7 +1147,6 @@ StartTransactionCommand(void)
|
||||
|
||||
switch (s->blockState)
|
||||
{
|
||||
|
||||
/*
|
||||
* if we aren't in a transaction block, we just do our usual
|
||||
* start transaction.
|
||||
@@ -1238,7 +1229,6 @@ CommitTransactionCommand(void)
|
||||
|
||||
switch (s->blockState)
|
||||
{
|
||||
|
||||
/*
|
||||
* if we aren't in a transaction block, we just do our usual
|
||||
* transaction commit
|
||||
@@ -1313,7 +1303,6 @@ AbortCurrentTransaction(void)
|
||||
|
||||
switch (s->blockState)
|
||||
{
|
||||
|
||||
/*
|
||||
* if we aren't in a transaction block, we just do the basic
|
||||
* abort & cleanup transaction.
|
||||
@@ -1429,7 +1418,6 @@ EndTransactionBlock(void)
|
||||
*/
|
||||
if (s->blockState == TBLOCK_INPROGRESS)
|
||||
{
|
||||
|
||||
/*
|
||||
* here we are in a transaction block which should commit when we
|
||||
* get to the upcoming CommitTransactionCommand() so we set the
|
||||
@@ -1442,7 +1430,6 @@ EndTransactionBlock(void)
|
||||
|
||||
if (s->blockState == TBLOCK_ABORT)
|
||||
{
|
||||
|
||||
/*
|
||||
* here, we are in a transaction block which aborted and since the
|
||||
* AbortTransaction() was already done, we do whatever is needed
|
||||
@@ -1480,7 +1467,6 @@ AbortTransactionBlock(void)
|
||||
*/
|
||||
if (s->blockState == TBLOCK_INPROGRESS)
|
||||
{
|
||||
|
||||
/*
|
||||
* here we were inside a transaction block something screwed up
|
||||
* inside the system so we enter the abort state, do the abort
|
||||
@@ -1502,7 +1488,6 @@ AbortTransactionBlock(void)
|
||||
AbortTransaction();
|
||||
s->blockState = TBLOCK_ENDABORT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------
|
||||
@@ -1527,7 +1512,6 @@ UserAbortTransactionBlock(void)
|
||||
|
||||
if (s->blockState == TBLOCK_INPROGRESS)
|
||||
{
|
||||
|
||||
/*
|
||||
* here we were inside a transaction block and we got an abort
|
||||
* command from the user, so we move to the abort state, do the
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: xid.c,v 1.33 2001/08/26 16:55:59 tgl Exp $
|
||||
* $Id: xid.c,v 1.34 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -34,6 +34,7 @@ Datum
|
||||
xidout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
|
||||
|
||||
/* maximum 32 bit unsigned integer representation takes 10 chars */
|
||||
char *str = palloc(11);
|
||||
|
||||
@@ -64,7 +65,7 @@ xid_age(PG_FUNCTION_ARGS)
|
||||
TransactionId now = GetCurrentTransactionId();
|
||||
|
||||
/* Permanent XIDs are always infinitely old */
|
||||
if (! TransactionIdIsNormal(xid))
|
||||
if (!TransactionIdIsNormal(xid))
|
||||
PG_RETURN_INT32(INT_MAX);
|
||||
|
||||
PG_RETURN_INT32((int32) (now - xid));
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.78 2001/09/29 04:02:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.79 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ char XLOG_archive_dir[MAXPGPATH]; /* null string means
|
||||
* delete 'em */
|
||||
|
||||
/*
|
||||
* XLOGfileslop is used in the code as the allowed "fuzz" in the number of
|
||||
* XLOGfileslop is used in the code as the allowed "fuzz" in the number of
|
||||
* preallocated XLOG segments --- we try to have at least XLOGfiles advance
|
||||
* segments but no more than XLOGfiles+XLOGfileslop segments. This could
|
||||
* be made a separate GUC variable, but at present I think it's sufficient
|
||||
@@ -215,13 +215,13 @@ typedef struct XLogwrtRqst
|
||||
{
|
||||
XLogRecPtr Write; /* last byte + 1 to write out */
|
||||
XLogRecPtr Flush; /* last byte + 1 to flush */
|
||||
} XLogwrtRqst;
|
||||
} XLogwrtRqst;
|
||||
|
||||
typedef struct XLogwrtResult
|
||||
{
|
||||
XLogRecPtr Write; /* last byte + 1 written out */
|
||||
XLogRecPtr Flush; /* last byte + 1 flushed */
|
||||
} XLogwrtResult;
|
||||
} XLogwrtResult;
|
||||
|
||||
/*
|
||||
* Shared state data for XLogInsert.
|
||||
@@ -260,8 +260,9 @@ typedef struct XLogCtlData
|
||||
|
||||
/*
|
||||
* These values do not change after startup, although the pointed-to
|
||||
* pages and xlblocks values certainly do. Permission to read/write the
|
||||
* pages and xlblocks values depends on WALInsertLock and WALWriteLock.
|
||||
* pages and xlblocks values certainly do. Permission to read/write
|
||||
* the pages and xlblocks values depends on WALInsertLock and
|
||||
* WALWriteLock.
|
||||
*/
|
||||
char *pages; /* buffers for unwritten XLOG pages */
|
||||
XLogRecPtr *xlblocks; /* 1st byte ptr-s + BLCKSZ */
|
||||
@@ -428,8 +429,8 @@ static void XLogWrite(XLogwrtRqst WriteRqst);
|
||||
static int XLogFileInit(uint32 log, uint32 seg,
|
||||
bool *use_existent, bool use_lock);
|
||||
static bool InstallXLogFileSegment(uint32 log, uint32 seg, char *tmppath,
|
||||
bool find_free, int max_advance,
|
||||
bool use_lock);
|
||||
bool find_free, int max_advance,
|
||||
bool use_lock);
|
||||
static int XLogFileOpen(uint32 log, uint32 seg, bool econt);
|
||||
static void PreallocXlogFiles(XLogRecPtr endptr);
|
||||
static void MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr);
|
||||
@@ -621,8 +622,8 @@ begin:;
|
||||
SpinLockRelease_NoHoldoff(&XLogCtl->info_lck);
|
||||
|
||||
/*
|
||||
* If cache is half filled then try to acquire write lock and
|
||||
* do XLogWrite. Ignore any fractional blocks in performing this check.
|
||||
* If cache is half filled then try to acquire write lock and do
|
||||
* XLogWrite. Ignore any fractional blocks in performing this check.
|
||||
*/
|
||||
LogwrtRqst.Write.xrecoff -= LogwrtRqst.Write.xrecoff % BLCKSZ;
|
||||
if (LogwrtRqst.Write.xlogid != LogwrtResult.Write.xlogid ||
|
||||
@@ -939,9 +940,7 @@ AdvanceXLInsertBuffer(void)
|
||||
NewPageEndPtr.xrecoff = BLCKSZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewPageEndPtr.xrecoff += BLCKSZ;
|
||||
}
|
||||
XLogCtl->xlblocks[nextidx] = NewPageEndPtr;
|
||||
NewPage = (XLogPageHeader) (XLogCtl->pages + nextidx * BLCKSZ);
|
||||
Insert->curridx = nextidx;
|
||||
@@ -956,7 +955,7 @@ AdvanceXLInsertBuffer(void)
|
||||
|
||||
/* And fill the new page's header */
|
||||
NewPage->xlp_magic = XLOG_PAGE_MAGIC;
|
||||
/* NewPage->xlp_info = 0; */ /* done by memset */
|
||||
/* NewPage->xlp_info = 0; *//* done by memset */
|
||||
NewPage->xlp_sui = ThisStartUpID;
|
||||
NewPage->xlp_pageaddr.xlogid = NewPageEndPtr.xlogid;
|
||||
NewPage->xlp_pageaddr.xrecoff = NewPageEndPtr.xrecoff - BLCKSZ;
|
||||
@@ -985,7 +984,6 @@ XLogWrite(XLogwrtRqst WriteRqst)
|
||||
|
||||
while (XLByteLT(LogwrtResult.Write, WriteRqst.Write))
|
||||
{
|
||||
|
||||
/*
|
||||
* Make sure we're not ahead of the insert process. This could
|
||||
* happen if we're passed a bogus WriteRqst.Write that is past the
|
||||
@@ -1004,7 +1002,6 @@ XLogWrite(XLogwrtRqst WriteRqst)
|
||||
|
||||
if (!XLByteInPrevSeg(LogwrtResult.Write, openLogId, openLogSeg))
|
||||
{
|
||||
|
||||
/*
|
||||
* Switch to new logfile segment.
|
||||
*/
|
||||
@@ -1114,7 +1111,6 @@ XLogWrite(XLogwrtRqst WriteRqst)
|
||||
if (XLByteLT(LogwrtResult.Flush, WriteRqst.Flush) &&
|
||||
XLByteLT(LogwrtResult.Flush, LogwrtResult.Write))
|
||||
{
|
||||
|
||||
/*
|
||||
* Could get here without iterating above loop, in which case we
|
||||
* might have no open file or the wrong one. However, we do not
|
||||
@@ -1174,11 +1170,11 @@ XLogFlush(XLogRecPtr record)
|
||||
if (XLOG_DEBUG)
|
||||
{
|
||||
elog(DEBUG, "XLogFlush%s%s: request %X/%X; write %X/%X; flush %X/%X\n",
|
||||
(IsBootstrapProcessingMode()) ? "(bootstrap)" : "",
|
||||
(InRedo) ? "(redo)" : "",
|
||||
record.xlogid, record.xrecoff,
|
||||
LogwrtResult.Write.xlogid, LogwrtResult.Write.xrecoff,
|
||||
LogwrtResult.Flush.xlogid, LogwrtResult.Flush.xrecoff);
|
||||
(IsBootstrapProcessingMode()) ? "(bootstrap)" : "",
|
||||
(InRedo) ? "(redo)" : "",
|
||||
record.xlogid, record.xrecoff,
|
||||
LogwrtResult.Write.xlogid, LogwrtResult.Write.xrecoff,
|
||||
LogwrtResult.Flush.xlogid, LogwrtResult.Flush.xrecoff);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
@@ -1240,7 +1236,7 @@ XLogFlush(XLogRecPtr record)
|
||||
if (XLByteLT(LogwrtResult.Flush, record))
|
||||
elog(STOP, "XLogFlush: request %X/%X is not satisfied --- flushed only to %X/%X",
|
||||
record.xlogid, record.xrecoff,
|
||||
LogwrtResult.Flush.xlogid, LogwrtResult.Flush.xrecoff);
|
||||
LogwrtResult.Flush.xlogid, LogwrtResult.Flush.xrecoff);
|
||||
}
|
||||
LWLockRelease(WALWriteLock);
|
||||
}
|
||||
@@ -1565,8 +1561,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
|
||||
{
|
||||
/*
|
||||
* Before deleting the file, see if it can be recycled as
|
||||
* a future log segment. We allow recycling segments up to
|
||||
* XLOGfiles + XLOGfileslop segments beyond the current
|
||||
* a future log segment. We allow recycling segments up
|
||||
* to XLOGfiles + XLOGfileslop segments beyond the current
|
||||
* XLOG location.
|
||||
*/
|
||||
if (InstallXLogFileSegment(endlogId, endlogSeg, path,
|
||||
@@ -1719,7 +1715,6 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
|
||||
|
||||
if (readBuf == NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* First time through, permanently allocate readBuf. We do it
|
||||
* this way, rather than just making a static array, for two
|
||||
@@ -1767,7 +1762,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
|
||||
readFile = XLogFileOpen(readId, readSeg, (emode == LOG));
|
||||
if (readFile < 0)
|
||||
goto next_record_is_invalid;
|
||||
readOff = (uint32) (-1);/* force read to occur below */
|
||||
readOff = (uint32) (-1); /* force read to occur below */
|
||||
}
|
||||
|
||||
targetPageOff = ((RecPtr->xrecoff % XLogSegSize) / BLCKSZ) * BLCKSZ;
|
||||
@@ -2022,7 +2017,6 @@ WriteControlFile(void)
|
||||
|
||||
#ifdef USE_LOCALE
|
||||
char *localeptr;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -2054,10 +2048,10 @@ WriteControlFile(void)
|
||||
"\n\tsuch queries, you may wish to set LC_COLLATE to \"C\" and"
|
||||
"\n\tre-initdb. For more information see the Administrator's Guide.",
|
||||
ControlFile->lc_collate);
|
||||
#else /* not USE_LOCALE */
|
||||
#else /* not USE_LOCALE */
|
||||
strcpy(ControlFile->lc_collate, "C");
|
||||
strcpy(ControlFile->lc_ctype, "C");
|
||||
#endif /* not USE_LOCALE */
|
||||
#endif /* not USE_LOCALE */
|
||||
|
||||
/* Contents are protected with a CRC */
|
||||
INIT_CRC64(ControlFile->crc);
|
||||
@@ -2156,7 +2150,7 @@ ReadControlFile(void)
|
||||
if (ControlFile->catalog_version_no != CATALOG_VERSION_NO)
|
||||
elog(STOP,
|
||||
"The database cluster was initialized with CATALOG_VERSION_NO %d,\n"
|
||||
"\tbut the backend was compiled with CATALOG_VERSION_NO %d.\n"
|
||||
"\tbut the backend was compiled with CATALOG_VERSION_NO %d.\n"
|
||||
"\tIt looks like you need to initdb.",
|
||||
ControlFile->catalog_version_no, CATALOG_VERSION_NO);
|
||||
if (ControlFile->blcksz != BLCKSZ)
|
||||
@@ -2174,7 +2168,7 @@ ReadControlFile(void)
|
||||
#ifdef USE_LOCALE
|
||||
if (setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
|
||||
elog(STOP,
|
||||
"The database cluster was initialized with LC_COLLATE '%s',\n"
|
||||
"The database cluster was initialized with LC_COLLATE '%s',\n"
|
||||
"\twhich is not recognized by setlocale().\n"
|
||||
"\tIt looks like you need to initdb.",
|
||||
ControlFile->lc_collate);
|
||||
@@ -2184,15 +2178,15 @@ ReadControlFile(void)
|
||||
"\twhich is not recognized by setlocale().\n"
|
||||
"\tIt looks like you need to initdb.",
|
||||
ControlFile->lc_ctype);
|
||||
#else /* not USE_LOCALE */
|
||||
#else /* not USE_LOCALE */
|
||||
if (strcmp(ControlFile->lc_collate, "C") != 0 ||
|
||||
strcmp(ControlFile->lc_ctype, "C") != 0)
|
||||
elog(STOP,
|
||||
"The database cluster was initialized with LC_COLLATE '%s' and\n"
|
||||
"The database cluster was initialized with LC_COLLATE '%s' and\n"
|
||||
"\tLC_CTYPE '%s', but the server was compiled without locale support.\n"
|
||||
"\tIt looks like you need to initdb or recompile.",
|
||||
ControlFile->lc_collate, ControlFile->lc_ctype);
|
||||
#endif /* not USE_LOCALE */
|
||||
#endif /* not USE_LOCALE */
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2536,7 +2530,7 @@ StartupXLOG(void)
|
||||
{
|
||||
/* nextXid must be beyond record's xid */
|
||||
if (TransactionIdFollowsOrEquals(record->xl_xid,
|
||||
ShmemVariableCache->nextXid))
|
||||
ShmemVariableCache->nextXid))
|
||||
{
|
||||
ShmemVariableCache->nextXid = record->xl_xid;
|
||||
TransactionIdAdvance(ShmemVariableCache->nextXid);
|
||||
@@ -2585,8 +2579,8 @@ StartupXLOG(void)
|
||||
Insert->PrevRecord = LastRec;
|
||||
|
||||
/*
|
||||
* If the next record will go to the new page
|
||||
* then initialize for that one.
|
||||
* If the next record will go to the new page then initialize for that
|
||||
* one.
|
||||
*/
|
||||
if ((BLCKSZ - EndOfLog.xrecoff % BLCKSZ) < SizeOfXLogRecord)
|
||||
EndOfLog.xrecoff += (BLCKSZ - EndOfLog.xrecoff % BLCKSZ);
|
||||
@@ -2602,9 +2596,7 @@ StartupXLOG(void)
|
||||
NewPageEndPtr.xrecoff = BLCKSZ;
|
||||
}
|
||||
else
|
||||
{
|
||||
NewPageEndPtr.xrecoff += BLCKSZ;
|
||||
}
|
||||
XLogCtl->xlblocks[0] = NewPageEndPtr;
|
||||
Insert->currpage->xlp_magic = XLOG_PAGE_MAGIC;
|
||||
if (InRecovery)
|
||||
@@ -2621,9 +2613,10 @@ StartupXLOG(void)
|
||||
XLogCtl->xlblocks[0].xlogid = openLogId;
|
||||
XLogCtl->xlblocks[0].xrecoff =
|
||||
((EndOfLog.xrecoff - 1) / BLCKSZ + 1) * BLCKSZ;
|
||||
|
||||
/*
|
||||
* Tricky point here: readBuf contains the *last* block that the
|
||||
* LastRec record spans, not the one it starts in. The last block
|
||||
* LastRec record spans, not the one it starts in. The last block
|
||||
* is indeed the one we want to use.
|
||||
*/
|
||||
Assert(readOff == (XLogCtl->xlblocks[0].xrecoff - BLCKSZ) % XLogSegSize);
|
||||
@@ -2670,7 +2663,6 @@ StartupXLOG(void)
|
||||
|
||||
if (InRecovery)
|
||||
{
|
||||
|
||||
/*
|
||||
* In case we had to use the secondary checkpoint, make sure that
|
||||
* it will still be shown as the secondary checkpoint after this
|
||||
@@ -2748,8 +2740,8 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
|
||||
if (record->xl_rmid != RM_XLOG_ID)
|
||||
{
|
||||
elog(LOG, (whichChkpt == 1 ?
|
||||
"invalid resource manager id in primary checkpoint record" :
|
||||
"invalid resource manager id in secondary checkpoint record"));
|
||||
"invalid resource manager id in primary checkpoint record" :
|
||||
"invalid resource manager id in secondary checkpoint record"));
|
||||
return NULL;
|
||||
}
|
||||
if (record->xl_info != XLOG_CHECKPOINT_SHUTDOWN &&
|
||||
@@ -2845,11 +2837,11 @@ CreateCheckPoint(bool shutdown)
|
||||
|
||||
/*
|
||||
* The CheckpointLock can be held for quite a while, which is not good
|
||||
* because we won't respond to a cancel/die request while waiting for an
|
||||
* LWLock. (But the alternative of using a regular lock won't work for
|
||||
* background checkpoint processes, which are not regular backends.)
|
||||
* So, rather than use a plain LWLockAcquire, use this kluge to allow
|
||||
* an interrupt to be accepted while we are waiting:
|
||||
* because we won't respond to a cancel/die request while waiting for
|
||||
* an LWLock. (But the alternative of using a regular lock won't work
|
||||
* for background checkpoint processes, which are not regular
|
||||
* backends.) So, rather than use a plain LWLockAcquire, use this
|
||||
* kluge to allow an interrupt to be accepted while we are waiting:
|
||||
*/
|
||||
while (!LWLockConditionalAcquire(CheckpointLock, LW_EXCLUSIVE))
|
||||
{
|
||||
@@ -2996,7 +2988,8 @@ CreateCheckPoint(bool shutdown)
|
||||
* but watch out for case that undo = 0.
|
||||
*
|
||||
* Without UNDO support: just use the redo pointer. This allows xlog
|
||||
* space to be freed much faster when there are long-running transactions.
|
||||
* space to be freed much faster when there are long-running
|
||||
* transactions.
|
||||
*/
|
||||
#ifdef NOT_USED
|
||||
if (ControlFile->checkPointCopy.undo.xrecoff != 0 &&
|
||||
@@ -3230,7 +3223,6 @@ assign_xlog_sync_method(const char *method)
|
||||
|
||||
if (sync_method != new_sync_method || open_sync_bit != new_sync_bit)
|
||||
{
|
||||
|
||||
/*
|
||||
* To ensure that no blocks escape unsynced, force an fsync on the
|
||||
* currently open log segment (if any). Also, if the open flag is
|
||||
@@ -3264,7 +3256,7 @@ issue_xlog_fsync(void)
|
||||
{
|
||||
switch (sync_method)
|
||||
{
|
||||
case SYNC_METHOD_FSYNC:
|
||||
case SYNC_METHOD_FSYNC:
|
||||
if (pg_fsync(openLogFile) != 0)
|
||||
elog(STOP, "fsync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlogutils.c,v 1.20 2001/10/05 17:28:11 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlogutils.c,v 1.21 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -247,7 +247,7 @@ _xl_remove_hash_entry(XLogRelDesc *rdesc)
|
||||
rdesc->moreRecently->lessRecently = rdesc->lessRecently;
|
||||
|
||||
hentry = (XLogRelCacheEntry *) hash_search(_xlrelcache,
|
||||
(void *) &(rdesc->reldata.rd_node), HASH_REMOVE, NULL);
|
||||
(void *) &(rdesc->reldata.rd_node), HASH_REMOVE, NULL);
|
||||
if (hentry == NULL)
|
||||
elog(STOP, "_xl_remove_hash_entry: file was not found in cache");
|
||||
|
||||
@@ -304,9 +304,7 @@ XLogCloseRelationCache(void)
|
||||
hash_seq_init(&status, _xlrelcache);
|
||||
|
||||
while ((hentry = (XLogRelCacheEntry *) hash_seq_search(&status)) != NULL)
|
||||
{
|
||||
_xl_remove_hash_entry(hentry->rdesc);
|
||||
}
|
||||
|
||||
hash_destroy(_xlrelcache);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.118 2001/10/19 17:03:08 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.119 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -188,7 +188,7 @@ usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
gettext("Usage:\n"
|
||||
" postgres -boot [-d] [-D datadir] [-F] [-o file] [-x num] dbname\n"
|
||||
" postgres -boot [-d] [-D datadir] [-F] [-o file] [-x num] dbname\n"
|
||||
" -d debug mode\n"
|
||||
" -D datadir data directory\n"
|
||||
" -F turn off fsync\n"
|
||||
@@ -293,7 +293,7 @@ BootstrapMain(int argc, char *argv[])
|
||||
{
|
||||
if (!potential_DataDir)
|
||||
{
|
||||
fprintf(stderr,
|
||||
fprintf(stderr,
|
||||
gettext("%s does not know where to find the database system data.\n"
|
||||
"You must specify the directory that contains the database system\n"
|
||||
"either by specifying the -D invocation option or by setting the\n"
|
||||
@@ -377,7 +377,7 @@ BootstrapMain(int argc, char *argv[])
|
||||
|
||||
case BS_XLOG_CHECKPOINT:
|
||||
if (IsUnderPostmaster)
|
||||
InitDummyProcess(); /* needed to get LWLocks */
|
||||
InitDummyProcess(); /* needed to get LWLocks */
|
||||
CreateDummyCaches();
|
||||
CreateCheckPoint(false);
|
||||
SetRedoRecPtr();
|
||||
@@ -996,7 +996,6 @@ FindStr(char *str, int length, hashnode *mderef)
|
||||
node = hashtable[CompHash(str, length)];
|
||||
while (node != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* We must differentiate between string constants that might have
|
||||
* the same value as a identifier and the identifier itself.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.51 2001/06/18 16:13:21 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.52 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* See acl.h.
|
||||
@@ -61,8 +61,7 @@ dumpacl(Acl *acl)
|
||||
DatumGetCString(DirectFunctionCall1(aclitemout,
|
||||
PointerGetDatum(aip + i))));
|
||||
}
|
||||
|
||||
#endif /* ACLDEBUG */
|
||||
#endif /* ACLDEBUG */
|
||||
|
||||
|
||||
/*
|
||||
@@ -115,8 +114,8 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
relname);
|
||||
|
||||
/*
|
||||
* If there's no ACL, create a default using the
|
||||
* pg_class.relowner field.
|
||||
* If there's no ACL, create a default using the pg_class.relowner
|
||||
* field.
|
||||
*/
|
||||
aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
|
||||
&isNull);
|
||||
@@ -133,10 +132,10 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
|
||||
foreach(j, stmt->grantees)
|
||||
{
|
||||
PrivGrantee *grantee = (PrivGrantee *)lfirst(j);
|
||||
PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
|
||||
char *granteeString;
|
||||
char *aclString;
|
||||
AclItem aclitem;
|
||||
AclItem aclitem;
|
||||
unsigned modechg;
|
||||
|
||||
if (grantee->username)
|
||||
@@ -162,7 +161,8 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
{
|
||||
replaces[i] = ' ';
|
||||
nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
|
||||
values[i] = (Datum) NULL; /* ignored if replaces[i]==' ' anyway */
|
||||
values[i] = (Datum) NULL; /* ignored if replaces[i]==' '
|
||||
* anyway */
|
||||
}
|
||||
replaces[Anum_pg_class_relacl - 1] = 'r';
|
||||
values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
|
||||
@@ -175,6 +175,7 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
||||
{
|
||||
/* keep the catalog indexes up to date */
|
||||
Relation idescs[Num_pg_class_indices];
|
||||
|
||||
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
|
||||
idescs);
|
||||
CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple);
|
||||
@@ -322,8 +323,8 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
|
||||
}
|
||||
|
||||
/*
|
||||
* "World" rights are applicable regardless of the passed-in ID,
|
||||
* and since they're much the cheapest to check, check 'em first.
|
||||
* "World" rights are applicable regardless of the passed-in ID, and
|
||||
* since they're much the cheapest to check, check 'em first.
|
||||
*/
|
||||
if (aidat->ai_idtype != ACL_IDTYPE_WORLD)
|
||||
elog(ERROR, "aclcheck: first entry in ACL is not 'world' entry");
|
||||
@@ -376,7 +377,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
|
||||
for (i = 1, aip = aidat + 1; /* skip world entry */
|
||||
i < num && aip->ai_idtype == ACL_IDTYPE_UID;
|
||||
++i, ++aip)
|
||||
/* skip UID entry */;
|
||||
/* skip UID entry */ ;
|
||||
for (;
|
||||
i < num && aip->ai_idtype == ACL_IDTYPE_GID;
|
||||
++i, ++aip)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.178 2001/10/22 22:47:57 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.179 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -64,10 +64,10 @@
|
||||
|
||||
|
||||
static void AddNewRelationTuple(Relation pg_class_desc,
|
||||
Relation new_rel_desc,
|
||||
Oid new_rel_oid, Oid new_type_oid,
|
||||
char relkind, bool relhasoids,
|
||||
char *temp_relname);
|
||||
Relation new_rel_desc,
|
||||
Oid new_rel_oid, Oid new_type_oid,
|
||||
char relkind, bool relhasoids,
|
||||
char *temp_relname);
|
||||
static void DeleteAttributeTuples(Relation rel);
|
||||
static void DeleteRelationTuple(Relation rel);
|
||||
static void DeleteTypeTuple(Relation rel);
|
||||
@@ -156,7 +156,7 @@ static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
|
||||
Form_pg_attribute
|
||||
SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
|
||||
{
|
||||
if (attno >= 0 || attno < - (int) lengthof(SysAtt))
|
||||
if (attno >= 0 || attno < -(int) lengthof(SysAtt))
|
||||
elog(ERROR, "SystemAttributeDefinition: invalid attribute number %d",
|
||||
attno);
|
||||
if (attno == ObjectIdAttributeNumber && !relhasoids)
|
||||
@@ -167,12 +167,12 @@ SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
|
||||
|
||||
/*
|
||||
* If the given name is a system attribute name, return a Form_pg_attribute
|
||||
* pointer for a prototype definition. If not, return NULL.
|
||||
* pointer for a prototype definition. If not, return NULL.
|
||||
*/
|
||||
Form_pg_attribute
|
||||
SystemAttributeByName(const char *attname, bool relhasoids)
|
||||
{
|
||||
int j;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < (int) lengthof(SysAtt); j++)
|
||||
{
|
||||
@@ -237,8 +237,8 @@ heap_create(char *relname,
|
||||
|
||||
/*
|
||||
* Real ugly stuff to assign the proper relid in the relation
|
||||
* descriptor follows. Note that only "bootstrapped" relations
|
||||
* whose OIDs are hard-coded in pg_class.h need be listed here.
|
||||
* descriptor follows. Note that only "bootstrapped" relations whose
|
||||
* OIDs are hard-coded in pg_class.h need be listed here.
|
||||
*/
|
||||
if (relname && IsSystemRelationName(relname))
|
||||
{
|
||||
@@ -541,7 +541,11 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
||||
/* Fill in the correct relation OID in the copied tuple */
|
||||
attStruct = (Form_pg_attribute) GETSTRUCT(tup);
|
||||
attStruct->attrelid = new_rel_oid;
|
||||
/* Unneeded since they should be OK in the constant data anyway */
|
||||
|
||||
/*
|
||||
* Unneeded since they should be OK in the constant data
|
||||
* anyway
|
||||
*/
|
||||
/* attStruct->attstattarget = 0; */
|
||||
/* attStruct->attcacheoff = -1; */
|
||||
|
||||
@@ -613,7 +617,7 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||
case RELKIND_RELATION:
|
||||
case RELKIND_INDEX:
|
||||
case RELKIND_TOASTVALUE:
|
||||
new_rel_reltup->relpages = 10; /* bogus estimates */
|
||||
new_rel_reltup->relpages = 10; /* bogus estimates */
|
||||
new_rel_reltup->reltuples = 1000;
|
||||
break;
|
||||
case RELKIND_SEQUENCE:
|
||||
@@ -653,7 +657,6 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||
|
||||
if (!IsIgnoringSystemIndexes())
|
||||
{
|
||||
|
||||
/*
|
||||
* First, open the catalog indices and insert index tuples for the
|
||||
* new relation.
|
||||
@@ -1735,27 +1738,35 @@ AddRelationRawConstraints(Relation rel,
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
bool success;
|
||||
bool success;
|
||||
List *listptr2;
|
||||
|
||||
ccname = (char *) palloc(NAMEDATALEN);
|
||||
|
||||
/* Loop until we find a non-conflicting constraint name */
|
||||
/* What happens if this loops forever? */
|
||||
j = numchecks + 1;
|
||||
do {
|
||||
do
|
||||
{
|
||||
success = true;
|
||||
snprintf(ccname, NAMEDATALEN, "$%d", j);
|
||||
|
||||
/* Check against old constraints */
|
||||
for (i = 0; i < numoldchecks; i++)
|
||||
{
|
||||
if (strcmp(oldchecks[i].ccname, ccname) == 0) {
|
||||
if (strcmp(oldchecks[i].ccname, ccname) == 0)
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Check against other new constraints, if the check hasn't already failed */
|
||||
if (success) {
|
||||
|
||||
/*
|
||||
* Check against other new constraints, if the check
|
||||
* hasn't already failed
|
||||
*/
|
||||
if (success)
|
||||
{
|
||||
foreach(listptr2, rawConstraints)
|
||||
{
|
||||
Constraint *cdef2 = (Constraint *) lfirst(listptr2);
|
||||
@@ -1765,7 +1776,8 @@ AddRelationRawConstraints(Relation rel,
|
||||
cdef2->raw_expr == NULL ||
|
||||
cdef2->name == NULL)
|
||||
continue;
|
||||
if (strcmp(cdef2->name, ccname) == 0) {
|
||||
if (strcmp(cdef2->name, ccname) == 0)
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
@@ -1914,59 +1926,60 @@ RemoveRelCheck(Relation rel)
|
||||
int
|
||||
RemoveCheckConstraint(Relation rel, const char *constrName, bool inh)
|
||||
{
|
||||
Oid relid;
|
||||
Relation rcrel;
|
||||
Relation relrel;
|
||||
Relation inhrel;
|
||||
Relation relidescs[Num_pg_class_indices];
|
||||
TupleDesc tupleDesc;
|
||||
TupleConstr *oldconstr;
|
||||
int numoldchecks;
|
||||
int numchecks;
|
||||
HeapScanDesc rcscan;
|
||||
ScanKeyData key[2];
|
||||
HeapTuple rctup;
|
||||
HeapTuple reltup;
|
||||
Form_pg_class relStruct;
|
||||
int rel_deleted = 0;
|
||||
int all_deleted = 0;
|
||||
Oid relid;
|
||||
Relation rcrel;
|
||||
Relation relrel;
|
||||
Relation inhrel;
|
||||
Relation relidescs[Num_pg_class_indices];
|
||||
TupleDesc tupleDesc;
|
||||
TupleConstr *oldconstr;
|
||||
int numoldchecks;
|
||||
int numchecks;
|
||||
HeapScanDesc rcscan;
|
||||
ScanKeyData key[2];
|
||||
HeapTuple rctup;
|
||||
HeapTuple reltup;
|
||||
Form_pg_class relStruct;
|
||||
int rel_deleted = 0;
|
||||
int all_deleted = 0;
|
||||
|
||||
/* Find id of the relation */
|
||||
relid = RelationGetRelid(rel);
|
||||
/* Find id of the relation */
|
||||
relid = RelationGetRelid(rel);
|
||||
|
||||
/* Process child tables and remove constraints of the
|
||||
same name. */
|
||||
if (inh)
|
||||
{
|
||||
List *child,
|
||||
*children;
|
||||
/*
|
||||
* Process child tables and remove constraints of the same name.
|
||||
*/
|
||||
if (inh)
|
||||
{
|
||||
List *child,
|
||||
*children;
|
||||
|
||||
/* This routine is actually in the planner */
|
||||
children = find_all_inheritors(relid);
|
||||
/* This routine is actually in the planner */
|
||||
children = find_all_inheritors(relid);
|
||||
|
||||
/*
|
||||
* find_all_inheritors does the recursive search of the
|
||||
* inheritance hierarchy, so all we have to do is process all
|
||||
* of the relids in the list that it returns.
|
||||
*/
|
||||
foreach(child, children)
|
||||
{
|
||||
Oid childrelid = lfirsti(child);
|
||||
/*
|
||||
* find_all_inheritors does the recursive search of the
|
||||
* inheritance hierarchy, so all we have to do is process all of
|
||||
* the relids in the list that it returns.
|
||||
*/
|
||||
foreach(child, children)
|
||||
{
|
||||
Oid childrelid = lfirsti(child);
|
||||
|
||||
if (childrelid == relid)
|
||||
continue;
|
||||
inhrel = heap_open(childrelid, AccessExclusiveLock);
|
||||
all_deleted += RemoveCheckConstraint(inhrel, constrName, false);
|
||||
heap_close(inhrel, NoLock);
|
||||
}
|
||||
}
|
||||
if (childrelid == relid)
|
||||
continue;
|
||||
inhrel = heap_open(childrelid, AccessExclusiveLock);
|
||||
all_deleted += RemoveCheckConstraint(inhrel, constrName, false);
|
||||
heap_close(inhrel, NoLock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Grab an exclusive lock on the pg_relcheck relation */
|
||||
rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* Create two scan keys. We need to match on the oid of the table
|
||||
* the CHECK is in and also we need to match the name of the CHECK
|
||||
* Create two scan keys. We need to match on the oid of the table the
|
||||
* CHECK is in and also we need to match the name of the CHECK
|
||||
* constraint.
|
||||
*/
|
||||
ScanKeyEntryInitialize(&key[0], 0, Anum_pg_relcheck_rcrelid,
|
||||
@@ -1979,14 +1992,15 @@ RemoveCheckConstraint(Relation rel, const char *constrName, bool inh)
|
||||
rcscan = heap_beginscan(rcrel, 0, SnapshotNow, 2, key);
|
||||
|
||||
/*
|
||||
* Scan over the result set, removing any matching entries. Note
|
||||
* that this has the side-effect of removing ALL CHECK constraints
|
||||
* that share the specified constraint name.
|
||||
* Scan over the result set, removing any matching entries. Note that
|
||||
* this has the side-effect of removing ALL CHECK constraints that
|
||||
* share the specified constraint name.
|
||||
*/
|
||||
while (HeapTupleIsValid(rctup = heap_getnext(rcscan, 0))) {
|
||||
while (HeapTupleIsValid(rctup = heap_getnext(rcscan, 0)))
|
||||
{
|
||||
simple_heap_delete(rcrel, &rctup->t_self);
|
||||
++rel_deleted;
|
||||
++all_deleted;
|
||||
++all_deleted;
|
||||
}
|
||||
|
||||
/* Clean up after the scan */
|
||||
@@ -2001,7 +2015,7 @@ RemoveCheckConstraint(Relation rel, const char *constrName, bool inh)
|
||||
* message, but for ALTER TABLE ADD ATTRIBUTE this'd be important.)
|
||||
*/
|
||||
|
||||
/*
|
||||
/*
|
||||
* Get number of existing constraints.
|
||||
*/
|
||||
|
||||
@@ -2020,7 +2034,7 @@ RemoveCheckConstraint(Relation rel, const char *constrName, bool inh)
|
||||
|
||||
relrel = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||
reltup = SearchSysCacheCopy(RELOID,
|
||||
ObjectIdGetDatum(RelationGetRelid(rel)), 0, 0, 0);
|
||||
ObjectIdGetDatum(RelationGetRelid(rel)), 0, 0, 0);
|
||||
|
||||
if (!HeapTupleIsValid(reltup))
|
||||
elog(ERROR, "cache lookup of relation %u failed",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.165 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.166 2001/10/25 05:49:22 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -64,19 +64,19 @@
|
||||
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
|
||||
bool istemp);
|
||||
static TupleDesc BuildFuncTupleDesc(Oid funcOid,
|
||||
Oid *classObjectId);
|
||||
Oid *classObjectId);
|
||||
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
|
||||
int numatts, AttrNumber *attNums,
|
||||
Oid *classObjectId);
|
||||
int numatts, AttrNumber *attNums,
|
||||
Oid *classObjectId);
|
||||
static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
|
||||
static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
|
||||
static void InitializeAttributeOids(Relation indexRelation,
|
||||
int numatts, Oid indexoid);
|
||||
static void AppendAttributeTuples(Relation indexRelation, int numatts);
|
||||
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
||||
IndexInfo *indexInfo,
|
||||
Oid *classOids,
|
||||
bool primary);
|
||||
IndexInfo *indexInfo,
|
||||
Oid *classOids,
|
||||
bool primary);
|
||||
static Oid IndexGetRelation(Oid indexId);
|
||||
static bool activate_index(Oid indexId, bool activate, bool inplace);
|
||||
|
||||
@@ -255,7 +255,7 @@ ConstructTupleDescriptor(Relation heapRelation,
|
||||
* here we are indexing on a system attribute (-1...-n)
|
||||
*/
|
||||
from = SystemAttributeDefinition(atnum,
|
||||
heapRelation->rd_rel->relhasoids);
|
||||
heapRelation->rd_rel->relhasoids);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -319,11 +319,11 @@ ConstructTupleDescriptor(Relation heapRelation,
|
||||
elog(ERROR, "Type %u does not exist", keyType);
|
||||
typeTup = (Form_pg_type) GETSTRUCT(tuple);
|
||||
|
||||
to->atttypid = keyType;
|
||||
to->atttypmod = -1;
|
||||
to->attlen = typeTup->typlen;
|
||||
to->attbyval = typeTup->typbyval;
|
||||
to->attalign = typeTup->typalign;
|
||||
to->atttypid = keyType;
|
||||
to->atttypmod = -1;
|
||||
to->attlen = typeTup->typlen;
|
||||
to->attbyval = typeTup->typbyval;
|
||||
to->attalign = typeTup->typalign;
|
||||
to->attstorage = typeTup->typstorage;
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
@@ -405,14 +405,15 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
||||
* Fill in a copy of relevant pg_am entry
|
||||
*/
|
||||
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
|
||||
CacheMemoryContext);
|
||||
CacheMemoryContext);
|
||||
|
||||
/*
|
||||
* Set up some additional fields of the index' pg_class entry.
|
||||
* In particular, initialize knowledge of whether the index is shared.
|
||||
* Set up some additional fields of the index' pg_class entry. In
|
||||
* particular, initialize knowledge of whether the index is shared.
|
||||
*/
|
||||
indexRelation->rd_rel->relowner = GetUserId();
|
||||
indexRelation->rd_rel->relam = amoid;
|
||||
indexRelation->rd_rel->relisshared =
|
||||
indexRelation->rd_rel->relisshared =
|
||||
IsSharedSystemRelationName(RelationGetPhysicalRelationName(indexRelation));
|
||||
indexRelation->rd_rel->relkind = RELKIND_INDEX;
|
||||
indexRelation->rd_rel->relhasoids = false;
|
||||
@@ -521,10 +522,10 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
|
||||
for (i = 0; i < numatts; i++)
|
||||
{
|
||||
/*
|
||||
* There used to be very grotty code here to set these fields,
|
||||
* but I think it's unnecessary. They should be set already.
|
||||
* There used to be very grotty code here to set these fields, but
|
||||
* I think it's unnecessary. They should be set already.
|
||||
*/
|
||||
Assert(indexTupDesc->attrs[i]->attnum == i+1);
|
||||
Assert(indexTupDesc->attrs[i]->attnum == i + 1);
|
||||
Assert(indexTupDesc->attrs[i]->attcacheoff == -1);
|
||||
|
||||
new_tuple = heap_addheader(Natts_pg_attribute,
|
||||
@@ -592,7 +593,7 @@ UpdateIndexRelation(Oid indexoid,
|
||||
indexForm->indexrelid = indexoid;
|
||||
indexForm->indrelid = heapoid;
|
||||
indexForm->indproc = indexInfo->ii_FuncOid;
|
||||
indexForm->indisclustered = false; /* not used */
|
||||
indexForm->indisclustered = false; /* not used */
|
||||
indexForm->indisunique = indexInfo->ii_Unique;
|
||||
indexForm->indisprimary = primary;
|
||||
memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
|
||||
@@ -678,7 +679,7 @@ index_create(char *heapRelationName,
|
||||
elog(ERROR, "must index at least one column");
|
||||
|
||||
if (heapRelationName && !allow_system_table_mods &&
|
||||
IsSystemRelationName(heapRelationName) && IsNormalProcessingMode())
|
||||
IsSystemRelationName(heapRelationName) && IsNormalProcessingMode())
|
||||
elog(ERROR, "User-defined indexes on system catalogs are not supported");
|
||||
|
||||
/*
|
||||
@@ -700,7 +701,7 @@ index_create(char *heapRelationName,
|
||||
else
|
||||
indexTupDesc = ConstructTupleDescriptor(heapRelation,
|
||||
indexInfo->ii_NumKeyAttrs,
|
||||
indexInfo->ii_KeyAttrNumbers,
|
||||
indexInfo->ii_KeyAttrNumbers,
|
||||
classObjectId);
|
||||
|
||||
if (istemp)
|
||||
@@ -825,12 +826,13 @@ index_drop(Oid indexId)
|
||||
* To drop an index safely, we must grab exclusive lock on its parent
|
||||
* table; otherwise there could be other backends using the index!
|
||||
* Exclusive lock on the index alone is insufficient because another
|
||||
* backend might be in the midst of devising a query plan that will use
|
||||
* the index. The parser and planner take care to hold an appropriate
|
||||
* lock on the parent table while working, but having them hold locks on
|
||||
* all the indexes too seems overly complex. We do grab exclusive lock
|
||||
* on the index too, just to be safe. Both locks must be held till end of
|
||||
* transaction, else other backends will still see this index in pg_index.
|
||||
* backend might be in the midst of devising a query plan that will
|
||||
* use the index. The parser and planner take care to hold an
|
||||
* appropriate lock on the parent table while working, but having them
|
||||
* hold locks on all the indexes too seems overly complex. We do grab
|
||||
* exclusive lock on the index too, just to be safe. Both locks must
|
||||
* be held till end of transaction, else other backends will still see
|
||||
* this index in pg_index.
|
||||
*/
|
||||
heapId = IndexGetRelation(indexId);
|
||||
userHeapRelation = heap_open(heapId, AccessExclusiveLock);
|
||||
@@ -873,8 +875,8 @@ index_drop(Oid indexId)
|
||||
* ensure other backends update their relcache lists of indexes. So,
|
||||
* unconditionally do setRelhasindex(true).
|
||||
*
|
||||
* Possible future improvement: skip the physical tuple update and
|
||||
* just send out an invalidation message.
|
||||
* Possible future improvement: skip the physical tuple update and just
|
||||
* send out an invalidation message.
|
||||
*/
|
||||
setRelhasindex(heapId, true, false, InvalidOid);
|
||||
|
||||
@@ -950,7 +952,7 @@ index_drop(Oid indexId)
|
||||
* just once per command, and then use it for (potentially) many tuples.
|
||||
* ----------------
|
||||
*/
|
||||
IndexInfo *
|
||||
IndexInfo *
|
||||
BuildIndexInfo(HeapTuple indexTuple)
|
||||
{
|
||||
Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
|
||||
@@ -974,8 +976,8 @@ BuildIndexInfo(HeapTuple indexTuple)
|
||||
* Handle functional index.
|
||||
*
|
||||
* If we have a functional index then the number of attributes defined in
|
||||
* the index must be 1 (the function's single return value).
|
||||
* Otherwise it's same as number of keys.
|
||||
* the index must be 1 (the function's single return value). Otherwise
|
||||
* it's same as number of keys.
|
||||
*/
|
||||
ii->ii_FuncOid = indexStruct->indproc;
|
||||
|
||||
@@ -1041,7 +1043,6 @@ FormIndexDatum(IndexInfo *indexInfo,
|
||||
|
||||
if (OidIsValid(indexInfo->ii_FuncOid))
|
||||
{
|
||||
|
||||
/*
|
||||
* Functional index --- compute the single index attribute
|
||||
*/
|
||||
@@ -1076,7 +1077,6 @@ FormIndexDatum(IndexInfo *indexInfo,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Plain index --- for each attribute we need from the heap tuple,
|
||||
* get the attribute and stick it into the datum and nullv arrays.
|
||||
@@ -1198,7 +1198,7 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
|
||||
* set relhasindex of relation's pg_class entry
|
||||
*
|
||||
* If isprimary is TRUE, we are defining a primary index, so also set
|
||||
* relhaspkey to TRUE. Otherwise, leave relhaspkey alone.
|
||||
* relhaspkey to TRUE. Otherwise, leave relhaspkey alone.
|
||||
*
|
||||
* If reltoastidxid is not InvalidOid, also set reltoastidxid to that value.
|
||||
* This is only used for TOAST relations.
|
||||
@@ -1390,7 +1390,7 @@ UpdateStats(Oid relid, double reltuples)
|
||||
Relation pg_class;
|
||||
HeapTuple tuple;
|
||||
HeapTuple newtup;
|
||||
BlockNumber relpages;
|
||||
BlockNumber relpages;
|
||||
int i;
|
||||
Form_pg_class rd_rel;
|
||||
Relation idescs[Num_pg_class_indices];
|
||||
@@ -1473,8 +1473,8 @@ UpdateStats(Oid relid, double reltuples)
|
||||
* when it is actually sizable. See also CREATE TABLE in heap.c.
|
||||
*
|
||||
* Note: this path is also taken during bootstrap, because bootstrap.c
|
||||
* passes reltuples = 0 after loading a table. We have to estimate some
|
||||
* number for reltuples based on the actual number of pages.
|
||||
* passes reltuples = 0 after loading a table. We have to estimate
|
||||
* some number for reltuples based on the actual number of pages.
|
||||
*/
|
||||
relpages = RelationGetNumberOfBlocks(whichRel);
|
||||
|
||||
@@ -1492,7 +1492,7 @@ UpdateStats(Oid relid, double reltuples)
|
||||
reltuples = 1000;
|
||||
}
|
||||
else
|
||||
reltuples = (double) relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
|
||||
reltuples = (double) relpages *NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1508,7 +1508,6 @@ UpdateStats(Oid relid, double reltuples)
|
||||
*/
|
||||
if (in_place_upd)
|
||||
{
|
||||
|
||||
/*
|
||||
* At bootstrap time, we don't need to worry about concurrency or
|
||||
* visibility of changes, so we cheat. Also cheat if REINDEX.
|
||||
@@ -1599,8 +1598,8 @@ index_build(Relation heapRelation,
|
||||
* build procedure does whatever cleanup is needed; in particular, it should
|
||||
* close the heap and index relations.
|
||||
*
|
||||
* The total count of heap tuples is returned. This is for updating pg_class
|
||||
* statistics. (It's annoying not to be able to do that here, but we can't
|
||||
* The total count of heap tuples is returned. This is for updating pg_class
|
||||
* statistics. (It's annoying not to be able to do that here, but we can't
|
||||
* do it until after the relation is closed.) Note that the index AM itself
|
||||
* must keep track of the number of index tuples; we don't do so here because
|
||||
* the AM might reject some of the tuples for its own reasons, such as being
|
||||
@@ -1658,7 +1657,8 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
|
||||
/*
|
||||
* Ok, begin our scan of the base relation. We use SnapshotAny
|
||||
* because we must retrieve all tuples and do our own time qual checks.
|
||||
* because we must retrieve all tuples and do our own time qual
|
||||
* checks.
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
{
|
||||
@@ -1673,7 +1673,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
|
||||
scan = heap_beginscan(heapRelation, /* relation */
|
||||
0, /* start at end */
|
||||
snapshot, /* seeself */
|
||||
snapshot, /* seeself */
|
||||
0, /* number of keys */
|
||||
(ScanKey) NULL); /* scan key */
|
||||
|
||||
@@ -1689,14 +1689,14 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
if (snapshot == SnapshotAny)
|
||||
{
|
||||
/* do our own time qual check */
|
||||
bool indexIt;
|
||||
uint16 sv_infomask;
|
||||
bool indexIt;
|
||||
uint16 sv_infomask;
|
||||
|
||||
/*
|
||||
* HeapTupleSatisfiesVacuum may update tuple's hint status bits.
|
||||
* We could possibly get away with not locking the buffer here,
|
||||
* since caller should hold ShareLock on the relation, but let's
|
||||
* be conservative about it.
|
||||
* HeapTupleSatisfiesVacuum may update tuple's hint status
|
||||
* bits. We could possibly get away with not locking the
|
||||
* buffer here, since caller should hold ShareLock on the
|
||||
* relation, but let's be conservative about it.
|
||||
*/
|
||||
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
|
||||
sv_infomask = heapTuple->t_data->t_infomask;
|
||||
@@ -1712,6 +1712,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
tupleIsAlive = true;
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
|
||||
/*
|
||||
* If tuple is recently deleted then we must index it
|
||||
* anyway to keep VACUUM from complaining.
|
||||
@@ -1720,32 +1721,36 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
tupleIsAlive = false;
|
||||
break;
|
||||
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
||||
|
||||
/*
|
||||
* Since caller should hold ShareLock or better, we should
|
||||
* not see any tuples inserted by open transactions ---
|
||||
* unless it's our own transaction. (Consider INSERT
|
||||
* followed by CREATE INDEX within a transaction.)
|
||||
* Since caller should hold ShareLock or better, we
|
||||
* should not see any tuples inserted by open
|
||||
* transactions --- unless it's our own transaction.
|
||||
* (Consider INSERT followed by CREATE INDEX within a
|
||||
* transaction.)
|
||||
*/
|
||||
if (! TransactionIdIsCurrentTransactionId(heapTuple->t_data->t_xmin))
|
||||
if (!TransactionIdIsCurrentTransactionId(heapTuple->t_data->t_xmin))
|
||||
elog(ERROR, "IndexBuildHeapScan: concurrent insert in progress");
|
||||
indexIt = true;
|
||||
tupleIsAlive = true;
|
||||
break;
|
||||
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
||||
|
||||
/*
|
||||
* Since caller should hold ShareLock or better, we should
|
||||
* not see any tuples deleted by open transactions ---
|
||||
* unless it's our own transaction. (Consider DELETE
|
||||
* followed by CREATE INDEX within a transaction.)
|
||||
* Since caller should hold ShareLock or better, we
|
||||
* should not see any tuples deleted by open
|
||||
* transactions --- unless it's our own transaction.
|
||||
* (Consider DELETE followed by CREATE INDEX within a
|
||||
* transaction.)
|
||||
*/
|
||||
if (! TransactionIdIsCurrentTransactionId(heapTuple->t_data->t_xmax))
|
||||
if (!TransactionIdIsCurrentTransactionId(heapTuple->t_data->t_xmax))
|
||||
elog(ERROR, "IndexBuildHeapScan: concurrent delete in progress");
|
||||
indexIt = true;
|
||||
tupleIsAlive = false;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "Unexpected HeapTupleSatisfiesVacuum result");
|
||||
indexIt = tupleIsAlive = false; /* keep compiler quiet */
|
||||
indexIt = tupleIsAlive = false; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1755,7 +1760,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
|
||||
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
|
||||
|
||||
if (! indexIt)
|
||||
if (!indexIt)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@@ -1776,7 +1781,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
*/
|
||||
if (predicate != NIL)
|
||||
{
|
||||
if (! tupleIsAlive)
|
||||
if (!tupleIsAlive)
|
||||
continue;
|
||||
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
|
||||
if (!ExecQual(predicate, econtext, false))
|
||||
@@ -1785,7 +1790,7 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
|
||||
/*
|
||||
* For the current heap tuple, extract all the attributes we use
|
||||
* in this index, and note which are null. This also performs
|
||||
* in this index, and note which are null. This also performs
|
||||
* evaluation of the function, if this is a functional index.
|
||||
*/
|
||||
FormIndexDatum(indexInfo,
|
||||
@@ -1797,8 +1802,8 @@ IndexBuildHeapScan(Relation heapRelation,
|
||||
|
||||
/*
|
||||
* You'd think we should go ahead and build the index tuple here,
|
||||
* but some index AMs want to do further processing on the
|
||||
* data first. So pass the attdata and nulls arrays, instead.
|
||||
* but some index AMs want to do further processing on the data
|
||||
* first. So pass the attdata and nulls arrays, instead.
|
||||
*/
|
||||
|
||||
/* Call the AM's callback routine to process the tuple */
|
||||
@@ -1919,7 +1924,6 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
||||
|
||||
if (inplace)
|
||||
{
|
||||
|
||||
/*
|
||||
* Release any buffers associated with this index. If they're
|
||||
* dirty, they're just dropped without bothering to flush to disk.
|
||||
@@ -2002,11 +2006,12 @@ reindex_relation(Oid relid, bool force)
|
||||
upd_pg_class_inplace = true;
|
||||
|
||||
/*
|
||||
* Ensure to hold an exclusive lock throughout the
|
||||
* transaction. The lock could be less intensive
|
||||
* but now it's AccessExclusiveLock for simplicity.
|
||||
* Ensure to hold an exclusive lock throughout the transaction. The
|
||||
* lock could be less intensive but now it's AccessExclusiveLock for
|
||||
* simplicity.
|
||||
*/
|
||||
rel = heap_open(relid, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* ignore the indexes of the target system relation while processing
|
||||
* reindex.
|
||||
@@ -2045,8 +2050,9 @@ reindex_relation(Oid relid, bool force)
|
||||
else
|
||||
elog(ERROR, "the target relation %u is shared", relid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Continue to hold the lock.
|
||||
* Continue to hold the lock.
|
||||
*/
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
@@ -2087,7 +2093,6 @@ reindex_relation(Oid relid, bool force)
|
||||
heap_close(indexRelation, AccessShareLock);
|
||||
if (reindexed)
|
||||
{
|
||||
|
||||
/*
|
||||
* Ok,we could use the reindexed indexes of the target system
|
||||
* relation now.
|
||||
@@ -2096,7 +2101,6 @@ reindex_relation(Oid relid, bool force)
|
||||
{
|
||||
if (!overwrite && relid == RelOid_pg_class)
|
||||
{
|
||||
|
||||
/*
|
||||
* For pg_class, relhasindex should be set to true here in
|
||||
* place.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.39 2001/08/10 15:49:39 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.40 2001/10/25 05:49:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -167,7 +167,6 @@ AggregateCreate(char *aggName,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* If no finalfn, aggregate result type is type of the state value
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.62 2001/10/22 19:34:13 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.63 2001/10/25 05:49:23 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||
@@ -74,7 +74,7 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
|
||||
static bool
|
||||
validOperatorName(const char *name)
|
||||
{
|
||||
size_t len = strlen(name);
|
||||
size_t len = strlen(name);
|
||||
|
||||
/* Can't be empty or too long */
|
||||
if (len == 0 || len >= NAMEDATALEN)
|
||||
@@ -90,20 +90,19 @@ validOperatorName(const char *name)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* For SQL92 compatibility, '+' and '-' cannot be the
|
||||
* last char of a multi-char operator unless the operator
|
||||
* contains chars that are not in SQL92 operators.
|
||||
* The idea is to lex '=-' as two operators, but not
|
||||
* to forbid operator names like '?-' that could not be
|
||||
* sequences of SQL92 operators.
|
||||
* For SQL92 compatibility, '+' and '-' cannot be the last char of a
|
||||
* multi-char operator unless the operator contains chars that are not
|
||||
* in SQL92 operators. The idea is to lex '=-' as two operators, but
|
||||
* not to forbid operator names like '?-' that could not be sequences
|
||||
* of SQL92 operators.
|
||||
*/
|
||||
if (len > 1 &&
|
||||
(name[len-1] == '+' ||
|
||||
name[len-1] == '-'))
|
||||
(name[len - 1] == '+' ||
|
||||
name[len - 1] == '-'))
|
||||
{
|
||||
int ic;
|
||||
int ic;
|
||||
|
||||
for (ic = len-2; ic >= 0; ic--)
|
||||
for (ic = len - 2; ic >= 0; ic--)
|
||||
{
|
||||
if (strchr("~!@#^&|`?$%", name[ic]))
|
||||
break;
|
||||
@@ -143,7 +142,7 @@ OperatorGetWithOpenRelation(Relation pg_operator_desc,
|
||||
HeapScanDesc pg_operator_scan;
|
||||
Oid operatorObjectId;
|
||||
HeapTuple tup;
|
||||
ScanKeyData opKey[3];
|
||||
ScanKeyData opKey[3];
|
||||
|
||||
/*
|
||||
* form scan key
|
||||
@@ -495,7 +494,7 @@ OperatorDef(char *operatorName,
|
||||
int nargs;
|
||||
NameData oname;
|
||||
TupleDesc tupDesc;
|
||||
ScanKeyData opKey[3];
|
||||
ScanKeyData opKey[3];
|
||||
|
||||
operatorObjectId = OperatorGet(operatorName,
|
||||
leftTypeName,
|
||||
@@ -743,7 +742,6 @@ OperatorDef(char *operatorName,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* self-linkage to this operator; will fix below. Note
|
||||
* that only self-linkage for commutation makes sense.
|
||||
@@ -867,7 +865,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId)
|
||||
char nulls[Natts_pg_operator];
|
||||
char replaces[Natts_pg_operator];
|
||||
Datum values[Natts_pg_operator];
|
||||
ScanKeyData opKey[1];
|
||||
ScanKeyData opKey[1];
|
||||
|
||||
for (i = 0; i < Natts_pg_operator; ++i)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.61 2001/10/06 23:21:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.62 2001/10/25 05:49:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -125,7 +125,6 @@ ProcedureCreate(char *procedureName,
|
||||
|
||||
if (languageObjectId == SQLlanguageId)
|
||||
{
|
||||
|
||||
/*
|
||||
* If this call is defining a set, check if the set is already
|
||||
* defined by looking to see whether this call's function text
|
||||
@@ -230,7 +229,7 @@ ProcedureCreate(char *procedureName,
|
||||
prosrc = procedureName;
|
||||
if (fmgr_internal_function(prosrc) == InvalidOid)
|
||||
elog(ERROR,
|
||||
"there is no built-in function named \"%s\"",
|
||||
"there is no built-in function named \"%s\"",
|
||||
prosrc);
|
||||
}
|
||||
|
||||
@@ -246,7 +245,7 @@ ProcedureCreate(char *procedureName,
|
||||
|
||||
if (languageObjectId == ClanguageId)
|
||||
{
|
||||
void *libraryhandle;
|
||||
void *libraryhandle;
|
||||
|
||||
/* If link symbol is specified as "-", substitute procedure name */
|
||||
if (strcmp(prosrc, "-") == 0)
|
||||
@@ -303,7 +302,7 @@ ProcedureCreate(char *procedureName,
|
||||
if (HeapTupleIsValid(oldtup))
|
||||
{
|
||||
/* There is one; okay to replace it? */
|
||||
Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
|
||||
Form_pg_proc oldproc = (Form_pg_proc) GETSTRUCT(oldtup);
|
||||
|
||||
if (!replace)
|
||||
elog(ERROR, "function %s already exists with same argument types",
|
||||
@@ -311,6 +310,7 @@ ProcedureCreate(char *procedureName,
|
||||
if (GetUserId() != oldproc->proowner && !superuser())
|
||||
elog(ERROR, "ProcedureCreate: you do not have permission to replace function %s",
|
||||
procedureName);
|
||||
|
||||
/*
|
||||
* Not okay to change the return type of the existing proc, since
|
||||
* existing rules, views, etc may depend on the return type.
|
||||
@@ -321,8 +321,8 @@ ProcedureCreate(char *procedureName,
|
||||
"\n\tUse DROP FUNCTION first.");
|
||||
|
||||
/* Okay, do it... */
|
||||
tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
tup = heap_modifytuple(oldtup, rel, values, nulls, replaces);
|
||||
simple_heap_update(rel, &tup->t_self, tup);
|
||||
|
||||
ReleaseSysCache(oldtup);
|
||||
}
|
||||
@@ -412,8 +412,8 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
|
||||
/*
|
||||
* For base-type returns, the target list should have exactly one
|
||||
* entry, and its type should agree with what the user declared.
|
||||
* (As of Postgres 7.2, we accept binary-compatible types too.)
|
||||
* entry, and its type should agree with what the user declared. (As
|
||||
* of Postgres 7.2, we accept binary-compatible types too.)
|
||||
*/
|
||||
typerelid = typeidTypeRelid(rettype);
|
||||
if (typerelid == InvalidOid)
|
||||
@@ -433,9 +433,9 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
/*
|
||||
* If the target list is of length 1, and the type of the varnode in
|
||||
* the target list matches the declared return type, this is okay.
|
||||
* This can happen, for example, where the body of the function
|
||||
* is 'SELECT func2()', where func2 has the same return type as
|
||||
* the function that's calling it.
|
||||
* This can happen, for example, where the body of the function is
|
||||
* 'SELECT func2()', where func2 has the same return type as the
|
||||
* function that's calling it.
|
||||
*/
|
||||
if (tlistlen == 1)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.64 2001/10/12 00:07:14 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.65 2001/10/25 05:49:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -318,13 +318,13 @@ TypeCreate(char *typeName,
|
||||
}
|
||||
|
||||
/*
|
||||
* validate size specifications: either positive (fixed-length) or
|
||||
* -1 (variable-length).
|
||||
* validate size specifications: either positive (fixed-length) or -1
|
||||
* (variable-length).
|
||||
*/
|
||||
if (! (internalSize > 0 || internalSize == -1))
|
||||
if (!(internalSize > 0 || internalSize == -1))
|
||||
elog(ERROR, "TypeCreate: invalid type internal size %d",
|
||||
internalSize);
|
||||
if (! (externalSize > 0 || externalSize == -1))
|
||||
if (!(externalSize > 0 || externalSize == -1))
|
||||
elog(ERROR, "TypeCreate: invalid type external size %d",
|
||||
externalSize);
|
||||
|
||||
@@ -382,7 +382,6 @@ TypeCreate(char *typeName,
|
||||
|
||||
if (!OidIsValid(procOid))
|
||||
{
|
||||
|
||||
/*
|
||||
* For array types, the input procedures may take 3 args (data
|
||||
* value, element OID, atttypmod); the pg_proc argtype
|
||||
@@ -434,7 +433,7 @@ TypeCreate(char *typeName,
|
||||
*/
|
||||
if (defaultTypeValue)
|
||||
values[i] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(defaultTypeValue));
|
||||
CStringGetDatum(defaultTypeValue));
|
||||
else
|
||||
nulls[i] = 'n';
|
||||
i++; /* 17 */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/recipe.c,v 1.13 2001/03/22 06:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/recipe.c,v 1.14 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -431,7 +431,6 @@ tg_replaceNumberedParam(Node *expression,
|
||||
{
|
||||
case T_Param:
|
||||
{
|
||||
|
||||
/*
|
||||
* the node is a parameter, substitute the entry from the
|
||||
* target list of the child that corresponds to the
|
||||
@@ -445,7 +444,6 @@ tg_replaceNumberedParam(Node *expression,
|
||||
|
||||
if (p->param_tlist)
|
||||
{
|
||||
|
||||
/*
|
||||
* we have a parameter with an attribute like
|
||||
* $N.foo so replace it with a new var node
|
||||
@@ -506,7 +504,6 @@ tg_replaceNumberedParam(Node *expression,
|
||||
break;
|
||||
case T_Expr:
|
||||
{
|
||||
|
||||
/*
|
||||
* the node is an expression, we need to recursively call
|
||||
* ourselves until we find parameter nodes
|
||||
@@ -578,7 +575,6 @@ tg_rewriteParamsInExpr(Node *expression, QueryTreeList * inputQlist)
|
||||
{
|
||||
case T_Param:
|
||||
{
|
||||
|
||||
/*
|
||||
* the node is a parameter, substitute the entry from the
|
||||
* target list of the child that corresponds to the
|
||||
@@ -594,7 +590,6 @@ tg_rewriteParamsInExpr(Node *expression, QueryTreeList * inputQlist)
|
||||
|
||||
if (p->param_tlist)
|
||||
{
|
||||
|
||||
/*
|
||||
* we have a parameter with an attribute like
|
||||
* $N.foo so match the resname "foo" against the
|
||||
@@ -634,7 +629,6 @@ tg_rewriteParamsInExpr(Node *expression, QueryTreeList * inputQlist)
|
||||
break;
|
||||
case T_Expr:
|
||||
{
|
||||
|
||||
/*
|
||||
* the node is an expression, we need to recursively call
|
||||
* ourselves until we find parameter nodes
|
||||
@@ -834,7 +828,6 @@ tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||
{
|
||||
case TG_SQL:
|
||||
{
|
||||
|
||||
/*
|
||||
* for SQL ingredients, the SQL query is contained in
|
||||
* the 'src' field
|
||||
@@ -940,7 +933,6 @@ tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||
}
|
||||
else if (n->nodeType == TG_EYE_NODE)
|
||||
{
|
||||
|
||||
/*
|
||||
* if we hit an eye, we need to stop and make what we have into a
|
||||
* subrecipe query block
|
||||
@@ -949,7 +941,6 @@ tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||
}
|
||||
else if (n->nodeType == TG_TEE_NODE)
|
||||
{
|
||||
|
||||
/*
|
||||
* if we hit a tee, check to see if the parsing has been done for
|
||||
* this tee already by the other parent
|
||||
@@ -958,7 +949,6 @@ tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||
rel = RelationNameGetRelation(n->nodeName);
|
||||
if (RelationIsValid(rel))
|
||||
{
|
||||
|
||||
/*
|
||||
* this tee has already been visited, no need to do any
|
||||
* further processing
|
||||
@@ -1014,7 +1004,6 @@ tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||
|
||||
if (RelationIsValid(rel))
|
||||
{
|
||||
|
||||
/*
|
||||
* for complex types, create new relation with the same
|
||||
* tuple descriptor as the output table type
|
||||
@@ -1028,7 +1017,6 @@ tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* we have to create a relation with one attribute of the
|
||||
* simple base type. That attribute will have an attr
|
||||
@@ -1197,7 +1185,6 @@ replaceSeqScan(Plan *plan, Plan *parent,
|
||||
snode = (Scan *) plan;
|
||||
if (snode->scanrelid == rt_ind)
|
||||
{
|
||||
|
||||
/*
|
||||
* found the sequential scan that should be replaced with the
|
||||
* tplan.
|
||||
@@ -1328,5 +1315,4 @@ replaceTeeScans(Plan *plan, Query *parsetree, TeeInfo * teeInfo)
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* TIOGA */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: recipe.h,v 1.3 2001/01/24 19:42:53 momjian Exp $
|
||||
* $Id: recipe.h,v 1.4 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -16,5 +16,4 @@
|
||||
#include "nodes/parsenodes.h"
|
||||
|
||||
extern void beginRecipe(RecipeStmt *stmt);
|
||||
|
||||
#endif /* RECIPE_H */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* doesn't work! - jolly 8/19/95
|
||||
*
|
||||
*
|
||||
* $Id: version.c,v 1.26 2001/03/23 04:49:52 momjian Exp $
|
||||
* $Id: version.c,v 1.27 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* At the point the version is defined, 2 physical relations are created
|
||||
@@ -87,7 +87,6 @@ eval_as_new_xact(char *query)
|
||||
CommandCounterIncrement();
|
||||
pg_exec_query(query);
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Define a version.
|
||||
@@ -129,7 +128,6 @@ DefineVersion(char *name, char *fromRelname, char *date)
|
||||
VersionReplace(name, saved_basename, saved_snapshot);
|
||||
VersionRetrieve(name, saved_basename, saved_snapshot);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -162,7 +160,6 @@ VersionCreate(char *vname, char *bname)
|
||||
sprintf(query_buf, "CREATE TABLE %s_del (DOID oid)", vname);
|
||||
eval_as_new_xact(query_buf);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -210,7 +207,6 @@ setAttrList(char *bname)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -228,7 +224,6 @@ VersionAppend(char *vname, char *bname)
|
||||
|
||||
eval_as_new_xact(rule_buf);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -257,7 +252,6 @@ where _%s.oid !!= '%s_del.DOID'",
|
||||
/* printf("%s\n",rule_buf); */
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -295,7 +289,6 @@ VersionDelete(char *vname, char *bname, char *snapshot)
|
||||
eval_as_new_xact(rule_buf);
|
||||
#endif /* OLD_REWRITE */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -349,5 +342,4 @@ VersionReplace(char *vname, char *bname, char *snapshot)
|
||||
/* printf("%s\n",rule_buf); */
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.22 2001/07/05 19:33:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.23 2001/10/25 05:49:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,9 +37,11 @@
|
||||
/*
|
||||
* Analysis algorithms supported
|
||||
*/
|
||||
typedef enum {
|
||||
typedef enum
|
||||
{
|
||||
ALG_MINIMAL = 1, /* Compute only most-common-values */
|
||||
ALG_SCALAR /* Compute MCV, histogram, sort correlation */
|
||||
ALG_SCALAR /* Compute MCV, histogram, sort
|
||||
* correlation */
|
||||
} AlgCode;
|
||||
|
||||
/*
|
||||
@@ -70,7 +72,10 @@ typedef struct
|
||||
Oid eqfunc; /* and associated function */
|
||||
Oid ltopr; /* '<' operator for datatype, if any */
|
||||
|
||||
/* These fields are filled in by the actual statistics-gathering routine */
|
||||
/*
|
||||
* These fields are filled in by the actual statistics-gathering
|
||||
* routine
|
||||
*/
|
||||
bool stats_valid;
|
||||
float4 stanullfrac; /* fraction of entries that are NULL */
|
||||
int4 stawidth; /* average width */
|
||||
@@ -101,7 +106,7 @@ typedef struct
|
||||
#define swapDatum(a,b) do {Datum _tmp; _tmp=a; a=b; b=_tmp;} while(0)
|
||||
|
||||
|
||||
static int MESSAGE_LEVEL;
|
||||
static int MESSAGE_LEVEL;
|
||||
|
||||
/* context information for compare_scalars() */
|
||||
static FmgrInfo *datumCmpFn;
|
||||
@@ -111,19 +116,19 @@ static int *datumCmpTupnoLink;
|
||||
|
||||
static VacAttrStats *examine_attribute(Relation onerel, int attnum);
|
||||
static int acquire_sample_rows(Relation onerel, HeapTuple *rows,
|
||||
int targrows, double *totalrows);
|
||||
int targrows, double *totalrows);
|
||||
static double random_fract(void);
|
||||
static double init_selection_state(int n);
|
||||
static double select_next_random_record(double t, int n, double *stateptr);
|
||||
static int compare_rows(const void *a, const void *b);
|
||||
static int compare_scalars(const void *a, const void *b);
|
||||
static int compare_mcvs(const void *a, const void *b);
|
||||
static int compare_rows(const void *a, const void *b);
|
||||
static int compare_scalars(const void *a, const void *b);
|
||||
static int compare_mcvs(const void *a, const void *b);
|
||||
static void compute_minimal_stats(VacAttrStats *stats,
|
||||
TupleDesc tupDesc, double totalrows,
|
||||
HeapTuple *rows, int numrows);
|
||||
TupleDesc tupDesc, double totalrows,
|
||||
HeapTuple *rows, int numrows);
|
||||
static void compute_scalar_stats(VacAttrStats *stats,
|
||||
TupleDesc tupDesc, double totalrows,
|
||||
HeapTuple *rows, int numrows);
|
||||
TupleDesc tupDesc, double totalrows,
|
||||
HeapTuple *rows, int numrows);
|
||||
static void update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats);
|
||||
|
||||
|
||||
@@ -154,8 +159,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
* Begin a transaction for analyzing this relation.
|
||||
*
|
||||
* Note: All memory allocated during ANALYZE will live in
|
||||
* TransactionCommandContext or a subcontext thereof, so it will
|
||||
* all be released by transaction commit at the end of this routine.
|
||||
* TransactionCommandContext or a subcontext thereof, so it will all
|
||||
* be released by transaction commit at the end of this routine.
|
||||
*/
|
||||
StartTransactionCommand();
|
||||
|
||||
@@ -191,14 +196,14 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/*
|
||||
* Open the class, getting only a read lock on it, and check permissions.
|
||||
* Permissions check should match vacuum's check!
|
||||
* Open the class, getting only a read lock on it, and check
|
||||
* permissions. Permissions check should match vacuum's check!
|
||||
*/
|
||||
onerel = heap_open(relid, AccessShareLock);
|
||||
|
||||
if (! (pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
|
||||
RELNAME) ||
|
||||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
|
||||
if (!(pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
|
||||
RELNAME) ||
|
||||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
|
||||
{
|
||||
/* No need for a notice if we already complained during VACUUM */
|
||||
if (!vacstmt->vacuum)
|
||||
@@ -238,7 +243,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
if (i >= attr_cnt)
|
||||
elog(ERROR, "ANALYZE: there is no attribute %s in %s",
|
||||
col, RelationGetRelationName(onerel));
|
||||
vacattrstats[tcnt] = examine_attribute(onerel, i+1);
|
||||
vacattrstats[tcnt] = examine_attribute(onerel, i + 1);
|
||||
if (vacattrstats[tcnt] != NULL)
|
||||
tcnt++;
|
||||
}
|
||||
@@ -251,7 +256,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
tcnt = 0;
|
||||
for (i = 0; i < attr_cnt; i++)
|
||||
{
|
||||
vacattrstats[tcnt] = examine_attribute(onerel, i+1);
|
||||
vacattrstats[tcnt] = examine_attribute(onerel, i + 1);
|
||||
if (vacattrstats[tcnt] != NULL)
|
||||
tcnt++;
|
||||
}
|
||||
@@ -270,8 +275,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
|
||||
/*
|
||||
* Determine how many rows we need to sample, using the worst case
|
||||
* from all analyzable columns. We use a lower bound of 100 rows
|
||||
* to avoid possible overflow in Vitter's algorithm.
|
||||
* from all analyzable columns. We use a lower bound of 100 rows to
|
||||
* avoid possible overflow in Vitter's algorithm.
|
||||
*/
|
||||
targrows = 100;
|
||||
for (i = 0; i < attr_cnt; i++)
|
||||
@@ -289,8 +294,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
/*
|
||||
* If we are running a standalone ANALYZE, update pages/tuples stats
|
||||
* in pg_class. We have the accurate page count from heap_beginscan,
|
||||
* but only an approximate number of tuples; therefore, if we are
|
||||
* part of VACUUM ANALYZE do *not* overwrite the accurate count already
|
||||
* but only an approximate number of tuples; therefore, if we are part
|
||||
* of VACUUM ANALYZE do *not* overwrite the accurate count already
|
||||
* inserted by VACUUM.
|
||||
*/
|
||||
if (!vacstmt->vacuum)
|
||||
@@ -300,7 +305,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
RelationGetForm(onerel)->relhasindex);
|
||||
|
||||
/*
|
||||
* Compute the statistics. Temporary results during the calculations
|
||||
* Compute the statistics. Temporary results during the calculations
|
||||
* for each column are stored in a child context. The calc routines
|
||||
* are responsible to make sure that whatever they store into the
|
||||
* VacAttrStats structure is allocated in TransactionCommandContext.
|
||||
@@ -338,8 +343,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
|
||||
/*
|
||||
* Emit the completed stats rows into pg_statistic, replacing any
|
||||
* previous statistics for the target columns. (If there are stats
|
||||
* in pg_statistic for columns we didn't process, we leave them alone.)
|
||||
* previous statistics for the target columns. (If there are
|
||||
* stats in pg_statistic for columns we didn't process, we leave
|
||||
* them alone.)
|
||||
*/
|
||||
update_attstats(relid, attr_cnt, vacattrstats);
|
||||
}
|
||||
@@ -364,7 +370,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
static VacAttrStats *
|
||||
examine_attribute(Relation onerel, int attnum)
|
||||
{
|
||||
Form_pg_attribute attr = onerel->rd_att->attrs[attnum-1];
|
||||
Form_pg_attribute attr = onerel->rd_att->attrs[attnum - 1];
|
||||
Operator func_operator;
|
||||
Oid oprrest;
|
||||
HeapTuple typtuple;
|
||||
@@ -396,8 +402,8 @@ examine_attribute(Relation onerel, int attnum)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If we have "=" then we're at least able to do the minimal algorithm,
|
||||
* so start filling in a VacAttrStats struct.
|
||||
* If we have "=" then we're at least able to do the minimal
|
||||
* algorithm, so start filling in a VacAttrStats struct.
|
||||
*/
|
||||
stats = (VacAttrStats *) palloc(sizeof(VacAttrStats));
|
||||
MemSet(stats, 0, sizeof(VacAttrStats));
|
||||
@@ -424,15 +430,14 @@ examine_attribute(Relation onerel, int attnum)
|
||||
{
|
||||
oprrest = ((Form_pg_operator) GETSTRUCT(func_operator))->oprrest;
|
||||
if (oprrest == F_SCALARLTSEL)
|
||||
{
|
||||
ltopr = oprid(func_operator);
|
||||
}
|
||||
ReleaseSysCache(func_operator);
|
||||
}
|
||||
stats->ltopr = ltopr;
|
||||
|
||||
/*
|
||||
* Determine the algorithm to use (this will get more complicated later)
|
||||
* Determine the algorithm to use (this will get more complicated
|
||||
* later)
|
||||
*/
|
||||
if (OidIsValid(ltopr))
|
||||
{
|
||||
@@ -474,7 +479,7 @@ examine_attribute(Relation onerel, int attnum)
|
||||
* acquire_sample_rows -- acquire a random sample of rows from the table
|
||||
*
|
||||
* Up to targrows rows are collected (if there are fewer than that many
|
||||
* rows in the table, all rows are collected). When the table is larger
|
||||
* rows in the table, all rows are collected). When the table is larger
|
||||
* than targrows, a truly random sample is collected: every row has an
|
||||
* equal chance of ending up in the final sample.
|
||||
*
|
||||
@@ -491,8 +496,8 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
int numrows = 0;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
ItemPointer lasttuple;
|
||||
BlockNumber lastblock,
|
||||
ItemPointer lasttuple;
|
||||
BlockNumber lastblock,
|
||||
estblock;
|
||||
OffsetNumber lastoffset;
|
||||
int numest;
|
||||
@@ -501,6 +506,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
double rstate;
|
||||
|
||||
Assert(targrows > 1);
|
||||
|
||||
/*
|
||||
* Do a simple linear scan until we reach the target number of rows.
|
||||
*/
|
||||
@@ -512,8 +518,9 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
break;
|
||||
}
|
||||
heap_endscan(scan);
|
||||
|
||||
/*
|
||||
* If we ran out of tuples then we're done, no matter how few we
|
||||
* If we ran out of tuples then we're done, no matter how few we
|
||||
* collected. No sort is needed, since they're already in order.
|
||||
*/
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
@@ -521,35 +528,40 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
*totalrows = (double) numrows;
|
||||
return numrows;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, start replacing tuples in the sample until we reach the
|
||||
* end of the relation. This algorithm is from Jeff Vitter's paper
|
||||
* (see full citation below). It works by repeatedly computing the number
|
||||
* of the next tuple we want to fetch, which will replace a randomly
|
||||
* chosen element of the reservoir (current set of tuples). At all times
|
||||
* the reservoir is a true random sample of the tuples we've passed over
|
||||
* so far, so when we fall off the end of the relation we're done.
|
||||
* (see full citation below). It works by repeatedly computing the
|
||||
* number of the next tuple we want to fetch, which will replace a
|
||||
* randomly chosen element of the reservoir (current set of tuples).
|
||||
* At all times the reservoir is a true random sample of the tuples
|
||||
* we've passed over so far, so when we fall off the end of the
|
||||
* relation we're done.
|
||||
*
|
||||
* A slight difficulty is that since we don't want to fetch tuples or even
|
||||
* pages that we skip over, it's not possible to fetch *exactly* the N'th
|
||||
* tuple at each step --- we don't know how many valid tuples are on
|
||||
* the skipped pages. We handle this by assuming that the average number
|
||||
* of valid tuples/page on the pages already scanned over holds good for
|
||||
* the rest of the relation as well; this lets us estimate which page
|
||||
* the next tuple should be on and its position in the page. Then we
|
||||
* fetch the first valid tuple at or after that position, being careful
|
||||
* not to use the same tuple twice. This approach should still give a
|
||||
* good random sample, although it's not perfect.
|
||||
* A slight difficulty is that since we don't want to fetch tuples or
|
||||
* even pages that we skip over, it's not possible to fetch *exactly*
|
||||
* the N'th tuple at each step --- we don't know how many valid tuples
|
||||
* are on the skipped pages. We handle this by assuming that the
|
||||
* average number of valid tuples/page on the pages already scanned
|
||||
* over holds good for the rest of the relation as well; this lets us
|
||||
* estimate which page the next tuple should be on and its position in
|
||||
* the page. Then we fetch the first valid tuple at or after that
|
||||
* position, being careful not to use the same tuple twice. This
|
||||
* approach should still give a good random sample, although it's not
|
||||
* perfect.
|
||||
*/
|
||||
lasttuple = &(rows[numrows-1]->t_self);
|
||||
lasttuple = &(rows[numrows - 1]->t_self);
|
||||
lastblock = ItemPointerGetBlockNumber(lasttuple);
|
||||
lastoffset = ItemPointerGetOffsetNumber(lasttuple);
|
||||
|
||||
/*
|
||||
* If possible, estimate tuples/page using only completely-scanned pages.
|
||||
* If possible, estimate tuples/page using only completely-scanned
|
||||
* pages.
|
||||
*/
|
||||
for (numest = numrows; numest > 0; numest--)
|
||||
{
|
||||
if (ItemPointerGetBlockNumber(&(rows[numest-1]->t_self)) != lastblock)
|
||||
if (ItemPointerGetBlockNumber(&(rows[numest - 1]->t_self)) != lastblock)
|
||||
break;
|
||||
}
|
||||
if (numest == 0)
|
||||
@@ -558,27 +570,25 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
estblock = lastblock + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
estblock = lastblock;
|
||||
}
|
||||
tuplesperpage = (double) numest / (double) estblock;
|
||||
|
||||
t = (double) numrows; /* t is the # of records processed so far */
|
||||
rstate = init_selection_state(targrows);
|
||||
for (;;)
|
||||
{
|
||||
double targpos;
|
||||
BlockNumber targblock;
|
||||
Buffer targbuffer;
|
||||
Page targpage;
|
||||
OffsetNumber targoffset,
|
||||
maxoffset;
|
||||
double targpos;
|
||||
BlockNumber targblock;
|
||||
Buffer targbuffer;
|
||||
Page targpage;
|
||||
OffsetNumber targoffset,
|
||||
maxoffset;
|
||||
|
||||
t = select_next_random_record(t, targrows, &rstate);
|
||||
/* Try to read the t'th record in the table */
|
||||
targpos = t / tuplesperpage;
|
||||
targblock = (BlockNumber) targpos;
|
||||
targoffset = ((int) ((targpos - targblock) * tuplesperpage)) +
|
||||
targoffset = ((int) ((targpos - targblock) * tuplesperpage)) +
|
||||
FirstOffsetNumber;
|
||||
/* Make sure we are past the last selected record */
|
||||
if (targblock <= lastblock)
|
||||
@@ -588,19 +598,22 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
targoffset = lastoffset + 1;
|
||||
}
|
||||
/* Loop to find first valid record at or after given position */
|
||||
pageloop:;
|
||||
pageloop:;
|
||||
|
||||
/*
|
||||
* Have we fallen off the end of the relation? (We rely on
|
||||
* Have we fallen off the end of the relation? (We rely on
|
||||
* heap_beginscan to have updated rd_nblocks.)
|
||||
*/
|
||||
if (targblock >= onerel->rd_nblocks)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We must maintain a pin on the target page's buffer to ensure that
|
||||
* the maxoffset value stays good (else concurrent VACUUM might
|
||||
* delete tuples out from under us). Hence, pin the page until we
|
||||
* are done looking at it. We don't maintain a lock on the page,
|
||||
* so tuples could get added to it, but we ignore such tuples.
|
||||
* We must maintain a pin on the target page's buffer to ensure
|
||||
* that the maxoffset value stays good (else concurrent VACUUM
|
||||
* might delete tuples out from under us). Hence, pin the page
|
||||
* until we are done looking at it. We don't maintain a lock on
|
||||
* the page, so tuples could get added to it, but we ignore such
|
||||
* tuples.
|
||||
*/
|
||||
targbuffer = ReadBuffer(onerel, targblock);
|
||||
if (!BufferIsValid(targbuffer))
|
||||
@@ -632,7 +645,7 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
* Found a suitable tuple, so save it, replacing one old
|
||||
* tuple at random
|
||||
*/
|
||||
int k = (int) (targrows * random_fract());
|
||||
int k = (int) (targrows * random_fract());
|
||||
|
||||
Assert(k >= 0 && k < targrows);
|
||||
heap_freetuple(rows[k]);
|
||||
@@ -667,13 +680,13 @@ acquire_sample_rows(Relation onerel, HeapTuple *rows, int targrows,
|
||||
static double
|
||||
random_fract(void)
|
||||
{
|
||||
long z;
|
||||
long z;
|
||||
|
||||
/* random() can produce endpoint values, try again if so */
|
||||
do
|
||||
{
|
||||
z = random();
|
||||
} while (! (z > 0 && z < MAX_RANDOM_VALUE));
|
||||
} while (!(z > 0 && z < MAX_RANDOM_VALUE));
|
||||
return (double) z / (double) MAX_RANDOM_VALUE;
|
||||
}
|
||||
|
||||
@@ -702,7 +715,7 @@ static double
|
||||
init_selection_state(int n)
|
||||
{
|
||||
/* Initial value of W (for use when Algorithm Z is first applied) */
|
||||
return exp(- log(random_fract())/n);
|
||||
return exp(-log(random_fract()) / n);
|
||||
}
|
||||
|
||||
static double
|
||||
@@ -712,8 +725,8 @@ select_next_random_record(double t, int n, double *stateptr)
|
||||
if (t <= (22.0 * n))
|
||||
{
|
||||
/* Process records using Algorithm X until t is large enough */
|
||||
double V,
|
||||
quot;
|
||||
double V,
|
||||
quot;
|
||||
|
||||
V = random_fract(); /* Generate V */
|
||||
t += 1;
|
||||
@@ -728,21 +741,21 @@ select_next_random_record(double t, int n, double *stateptr)
|
||||
else
|
||||
{
|
||||
/* Now apply Algorithm Z */
|
||||
double W = *stateptr;
|
||||
double term = t - (double) n + 1;
|
||||
double S;
|
||||
double W = *stateptr;
|
||||
double term = t - (double) n + 1;
|
||||
double S;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
double numer,
|
||||
numer_lim,
|
||||
denom;
|
||||
double U,
|
||||
X,
|
||||
lhs,
|
||||
rhs,
|
||||
y,
|
||||
tmp;
|
||||
double numer,
|
||||
numer_lim,
|
||||
denom;
|
||||
double U,
|
||||
X,
|
||||
lhs,
|
||||
rhs,
|
||||
y,
|
||||
tmp;
|
||||
|
||||
/* Generate U and X */
|
||||
U = random_fract();
|
||||
@@ -750,15 +763,15 @@ select_next_random_record(double t, int n, double *stateptr)
|
||||
S = floor(X); /* S is tentatively set to floor(X) */
|
||||
/* Test if U <= h(S)/cg(X) in the manner of (6.3) */
|
||||
tmp = (t + 1) / term;
|
||||
lhs = exp(log(((U * tmp * tmp) * (term + S))/(t + X))/n);
|
||||
rhs = (((t + X)/(term + S)) * term)/t;
|
||||
lhs = exp(log(((U * tmp * tmp) * (term + S)) / (t + X)) / n);
|
||||
rhs = (((t + X) / (term + S)) * term) / t;
|
||||
if (lhs <= rhs)
|
||||
{
|
||||
W = rhs/lhs;
|
||||
W = rhs / lhs;
|
||||
break;
|
||||
}
|
||||
/* Test if U <= f(S)/cg(X) */
|
||||
y = (((U * (t + 1))/term) * (t + S + 1))/(t + X);
|
||||
y = (((U * (t + 1)) / term) * (t + S + 1)) / (t + X);
|
||||
if ((double) n < S)
|
||||
{
|
||||
denom = t;
|
||||
@@ -774,8 +787,8 @@ select_next_random_record(double t, int n, double *stateptr)
|
||||
y *= numer / denom;
|
||||
denom -= 1;
|
||||
}
|
||||
W = exp(- log(random_fract())/n); /* Generate W in advance */
|
||||
if (exp(log(y)/n) <= (t + X)/t)
|
||||
W = exp(-log(random_fract()) / n); /* Generate W in advance */
|
||||
if (exp(log(y) / n) <= (t + X) / t)
|
||||
break;
|
||||
}
|
||||
t += S + 1;
|
||||
@@ -790,11 +803,11 @@ select_next_random_record(double t, int n, double *stateptr)
|
||||
static int
|
||||
compare_rows(const void *a, const void *b)
|
||||
{
|
||||
HeapTuple ha = * (HeapTuple *) a;
|
||||
HeapTuple hb = * (HeapTuple *) b;
|
||||
BlockNumber ba = ItemPointerGetBlockNumber(&ha->t_self);
|
||||
HeapTuple ha = *(HeapTuple *) a;
|
||||
HeapTuple hb = *(HeapTuple *) b;
|
||||
BlockNumber ba = ItemPointerGetBlockNumber(&ha->t_self);
|
||||
OffsetNumber oa = ItemPointerGetOffsetNumber(&ha->t_self);
|
||||
BlockNumber bb = ItemPointerGetBlockNumber(&hb->t_self);
|
||||
BlockNumber bb = ItemPointerGetBlockNumber(&hb->t_self);
|
||||
OffsetNumber ob = ItemPointerGetOffsetNumber(&hb->t_self);
|
||||
|
||||
if (ba < bb)
|
||||
@@ -839,15 +852,18 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
FmgrInfo f_cmpeq;
|
||||
typedef struct
|
||||
{
|
||||
Datum value;
|
||||
int count;
|
||||
Datum value;
|
||||
int count;
|
||||
} TrackItem;
|
||||
TrackItem *track;
|
||||
int track_cnt,
|
||||
track_max;
|
||||
int num_mcv = stats->attr->attstattarget;
|
||||
|
||||
/* We track up to 2*n values for an n-element MCV list; but at least 10 */
|
||||
/*
|
||||
* We track up to 2*n values for an n-element MCV list; but at least
|
||||
* 10
|
||||
*/
|
||||
track_max = 2 * num_mcv;
|
||||
if (track_max < 10)
|
||||
track_max = 10;
|
||||
@@ -877,19 +893,20 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
|
||||
/*
|
||||
* If it's a varlena field, add up widths for average width
|
||||
* calculation. Note that if the value is toasted, we
|
||||
* use the toasted width. We don't bother with this calculation
|
||||
* if it's a fixed-width type.
|
||||
* calculation. Note that if the value is toasted, we use the
|
||||
* toasted width. We don't bother with this calculation if it's a
|
||||
* fixed-width type.
|
||||
*/
|
||||
if (is_varlena)
|
||||
{
|
||||
total_width += VARSIZE(DatumGetPointer(value));
|
||||
|
||||
/*
|
||||
* If the value is toasted, we want to detoast it just once to
|
||||
* avoid repeated detoastings and resultant excess memory usage
|
||||
* during the comparisons. Also, check to see if the value is
|
||||
* excessively wide, and if so don't detoast at all --- just
|
||||
* ignore the value.
|
||||
* avoid repeated detoastings and resultant excess memory
|
||||
* usage during the comparisons. Also, check to see if the
|
||||
* value is excessively wide, and if so don't detoast at all
|
||||
* --- just ignore the value.
|
||||
*/
|
||||
if (toast_raw_datum_size(value) > WIDTH_THRESHOLD)
|
||||
{
|
||||
@@ -920,10 +937,10 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
/* Found a match */
|
||||
track[j].count++;
|
||||
/* This value may now need to "bubble up" in the track list */
|
||||
while (j > 0 && track[j].count > track[j-1].count)
|
||||
while (j > 0 && track[j].count > track[j - 1].count)
|
||||
{
|
||||
swapDatum(track[j].value, track[j-1].value);
|
||||
swapInt(track[j].count, track[j-1].count);
|
||||
swapDatum(track[j].value, track[j - 1].value);
|
||||
swapInt(track[j].count, track[j - 1].count);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
@@ -932,10 +949,10 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
/* No match. Insert at head of count-1 list */
|
||||
if (track_cnt < track_max)
|
||||
track_cnt++;
|
||||
for (j = track_cnt-1; j > firstcount1; j--)
|
||||
for (j = track_cnt - 1; j > firstcount1; j--)
|
||||
{
|
||||
track[j].value = track[j-1].value;
|
||||
track[j].count = track[j-1].count;
|
||||
track[j].value = track[j - 1].value;
|
||||
track[j].count = track[j - 1].count;
|
||||
}
|
||||
if (firstcount1 < track_cnt)
|
||||
{
|
||||
@@ -948,8 +965,8 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
/* We can only compute valid stats if we found some non-null values. */
|
||||
if (nonnull_cnt > 0)
|
||||
{
|
||||
int nmultiple,
|
||||
summultiple;
|
||||
int nmultiple,
|
||||
summultiple;
|
||||
|
||||
stats->stats_valid = true;
|
||||
/* Do the simple null-frac and width stats */
|
||||
@@ -977,9 +994,9 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
nmultiple == track_cnt)
|
||||
{
|
||||
/*
|
||||
* Our track list includes every value in the sample, and every
|
||||
* value appeared more than once. Assume the column has just
|
||||
* these values.
|
||||
* Our track list includes every value in the sample, and
|
||||
* every value appeared more than once. Assume the column has
|
||||
* just these values.
|
||||
*/
|
||||
stats->stadistinct = track_cnt;
|
||||
}
|
||||
@@ -994,12 +1011,12 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
* We assume (not very reliably!) that all the multiply-occurring
|
||||
* values are reflected in the final track[] list, and the other
|
||||
* nonnull values all appeared but once. (XXX this usually
|
||||
* results in a drastic overestimate of ndistinct. Can we do
|
||||
* results in a drastic overestimate of ndistinct. Can we do
|
||||
* any better?)
|
||||
*----------
|
||||
*/
|
||||
int f1 = nonnull_cnt - summultiple;
|
||||
double term1;
|
||||
int f1 = nonnull_cnt - summultiple;
|
||||
double term1;
|
||||
|
||||
if (f1 < 1)
|
||||
f1 = 1;
|
||||
@@ -1014,16 +1031,16 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
* a fixed value.
|
||||
*/
|
||||
if (stats->stadistinct > 0.1 * totalrows)
|
||||
stats->stadistinct = - (stats->stadistinct / totalrows);
|
||||
stats->stadistinct = -(stats->stadistinct / totalrows);
|
||||
|
||||
/*
|
||||
* Decide how many values are worth storing as most-common values.
|
||||
* If we are able to generate a complete MCV list (all the values
|
||||
* in the sample will fit, and we think these are all the ones in
|
||||
* the table), then do so. Otherwise, store only those values
|
||||
* that are significantly more common than the (estimated) average.
|
||||
* We set the threshold rather arbitrarily at 25% more than average,
|
||||
* with at least 2 instances in the sample.
|
||||
* the table), then do so. Otherwise, store only those values
|
||||
* that are significantly more common than the (estimated)
|
||||
* average. We set the threshold rather arbitrarily at 25% more
|
||||
* than average, with at least 2 instances in the sample.
|
||||
*/
|
||||
if (track_cnt < track_max && toowide_cnt == 0 &&
|
||||
stats->stadistinct > 0 &&
|
||||
@@ -1034,12 +1051,12 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
}
|
||||
else
|
||||
{
|
||||
double ndistinct = stats->stadistinct;
|
||||
double avgcount,
|
||||
mincount;
|
||||
double ndistinct = stats->stadistinct;
|
||||
double avgcount,
|
||||
mincount;
|
||||
|
||||
if (ndistinct < 0)
|
||||
ndistinct = - ndistinct * totalrows;
|
||||
ndistinct = -ndistinct * totalrows;
|
||||
/* estimate # of occurrences in sample of a typical value */
|
||||
avgcount = (double) numrows / ndistinct;
|
||||
/* set minimum threshold count to store a value */
|
||||
@@ -1062,8 +1079,8 @@ compute_minimal_stats(VacAttrStats *stats,
|
||||
if (num_mcv > 0)
|
||||
{
|
||||
MemoryContext old_context;
|
||||
Datum *mcv_values;
|
||||
float4 *mcv_freqs;
|
||||
Datum *mcv_values;
|
||||
float4 *mcv_freqs;
|
||||
|
||||
/* Must copy the target values into TransactionCommandContext */
|
||||
old_context = MemoryContextSwitchTo(TransactionCommandContext);
|
||||
@@ -1153,19 +1170,20 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
|
||||
/*
|
||||
* If it's a varlena field, add up widths for average width
|
||||
* calculation. Note that if the value is toasted, we
|
||||
* use the toasted width. We don't bother with this calculation
|
||||
* if it's a fixed-width type.
|
||||
* calculation. Note that if the value is toasted, we use the
|
||||
* toasted width. We don't bother with this calculation if it's a
|
||||
* fixed-width type.
|
||||
*/
|
||||
if (is_varlena)
|
||||
{
|
||||
total_width += VARSIZE(DatumGetPointer(value));
|
||||
|
||||
/*
|
||||
* If the value is toasted, we want to detoast it just once to
|
||||
* avoid repeated detoastings and resultant excess memory usage
|
||||
* during the comparisons. Also, check to see if the value is
|
||||
* excessively wide, and if so don't detoast at all --- just
|
||||
* ignore the value.
|
||||
* avoid repeated detoastings and resultant excess memory
|
||||
* usage during the comparisons. Also, check to see if the
|
||||
* value is excessively wide, and if so don't detoast at all
|
||||
* --- just ignore the value.
|
||||
*/
|
||||
if (toast_raw_datum_size(value) > WIDTH_THRESHOLD)
|
||||
{
|
||||
@@ -1185,11 +1203,11 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
/* We can only compute valid stats if we found some sortable values. */
|
||||
if (values_cnt > 0)
|
||||
{
|
||||
int ndistinct, /* # distinct values in sample */
|
||||
nmultiple, /* # that appear multiple times */
|
||||
num_hist,
|
||||
dups_cnt;
|
||||
int slot_idx = 0;
|
||||
int ndistinct, /* # distinct values in sample */
|
||||
nmultiple, /* # that appear multiple times */
|
||||
num_hist,
|
||||
dups_cnt;
|
||||
int slot_idx = 0;
|
||||
|
||||
/* Sort the collected values */
|
||||
datumCmpFn = &f_cmpfn;
|
||||
@@ -1199,23 +1217,24 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
sizeof(ScalarItem), compare_scalars);
|
||||
|
||||
/*
|
||||
* Now scan the values in order, find the most common ones,
|
||||
* and also accumulate ordering-correlation statistics.
|
||||
* Now scan the values in order, find the most common ones, and
|
||||
* also accumulate ordering-correlation statistics.
|
||||
*
|
||||
* To determine which are most common, we first have to count the
|
||||
* number of duplicates of each value. The duplicates are adjacent
|
||||
* in the sorted list, so a brute-force approach is to compare
|
||||
* successive datum values until we find two that are not equal.
|
||||
* However, that requires N-1 invocations of the datum comparison
|
||||
* routine, which are completely redundant with work that was done
|
||||
* during the sort. (The sort algorithm must at some point have
|
||||
* compared each pair of items that are adjacent in the sorted order;
|
||||
* otherwise it could not know that it's ordered the pair correctly.)
|
||||
* We exploit this by having compare_scalars remember the highest
|
||||
* tupno index that each ScalarItem has been found equal to. At the
|
||||
* end of the sort, a ScalarItem's tupnoLink will still point to
|
||||
* itself if and only if it is the last item of its group of
|
||||
* duplicates (since the group will be ordered by tupno).
|
||||
* number of duplicates of each value. The duplicates are
|
||||
* adjacent in the sorted list, so a brute-force approach is to
|
||||
* compare successive datum values until we find two that are not
|
||||
* equal. However, that requires N-1 invocations of the datum
|
||||
* comparison routine, which are completely redundant with work
|
||||
* that was done during the sort. (The sort algorithm must at
|
||||
* some point have compared each pair of items that are adjacent
|
||||
* in the sorted order; otherwise it could not know that it's
|
||||
* ordered the pair correctly.) We exploit this by having
|
||||
* compare_scalars remember the highest tupno index that each
|
||||
* ScalarItem has been found equal to. At the end of the sort, a
|
||||
* ScalarItem's tupnoLink will still point to itself if and only
|
||||
* if it is the last item of its group of duplicates (since the
|
||||
* group will be ordered by tupno).
|
||||
*/
|
||||
corr_xysum = 0;
|
||||
ndistinct = 0;
|
||||
@@ -1225,7 +1244,8 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
{
|
||||
int tupno = values[i].tupno;
|
||||
|
||||
corr_xysum += (double) i * (double) tupno;
|
||||
corr_xysum += (double) i *(double) tupno;
|
||||
|
||||
dups_cnt++;
|
||||
if (tupnoLink[tupno] == tupno)
|
||||
{
|
||||
@@ -1235,7 +1255,7 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
{
|
||||
nmultiple++;
|
||||
if (track_cnt < num_mcv ||
|
||||
dups_cnt > track[track_cnt-1].count)
|
||||
dups_cnt > track[track_cnt - 1].count)
|
||||
{
|
||||
/*
|
||||
* Found a new item for the mcv list; find its
|
||||
@@ -1243,16 +1263,16 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
* Loop invariant is that j points at an empty/
|
||||
* replaceable slot.
|
||||
*/
|
||||
int j;
|
||||
int j;
|
||||
|
||||
if (track_cnt < num_mcv)
|
||||
track_cnt++;
|
||||
for (j = track_cnt-1; j > 0; j--)
|
||||
for (j = track_cnt - 1; j > 0; j--)
|
||||
{
|
||||
if (dups_cnt <= track[j-1].count)
|
||||
if (dups_cnt <= track[j - 1].count)
|
||||
break;
|
||||
track[j].count = track[j-1].count;
|
||||
track[j].first = track[j-1].first;
|
||||
track[j].count = track[j - 1].count;
|
||||
track[j].first = track[j - 1].first;
|
||||
}
|
||||
track[j].count = dups_cnt;
|
||||
track[j].first = i + 1 - dups_cnt;
|
||||
@@ -1278,8 +1298,8 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
else if (toowide_cnt == 0 && nmultiple == ndistinct)
|
||||
{
|
||||
/*
|
||||
* Every value in the sample appeared more than once. Assume the
|
||||
* column has just these values.
|
||||
* Every value in the sample appeared more than once. Assume
|
||||
* the column has just these values.
|
||||
*/
|
||||
stats->stadistinct = ndistinct;
|
||||
}
|
||||
@@ -1294,8 +1314,8 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
* Overwidth values are assumed to have been distinct.
|
||||
*----------
|
||||
*/
|
||||
int f1 = ndistinct - nmultiple + toowide_cnt;
|
||||
double term1;
|
||||
int f1 = ndistinct - nmultiple + toowide_cnt;
|
||||
double term1;
|
||||
|
||||
if (f1 < 1)
|
||||
f1 = 1;
|
||||
@@ -1310,19 +1330,20 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
* a fixed value.
|
||||
*/
|
||||
if (stats->stadistinct > 0.1 * totalrows)
|
||||
stats->stadistinct = - (stats->stadistinct / totalrows);
|
||||
stats->stadistinct = -(stats->stadistinct / totalrows);
|
||||
|
||||
/*
|
||||
* Decide how many values are worth storing as most-common values.
|
||||
* If we are able to generate a complete MCV list (all the values
|
||||
* in the sample will fit, and we think these are all the ones in
|
||||
* the table), then do so. Otherwise, store only those values
|
||||
* that are significantly more common than the (estimated) average.
|
||||
* We set the threshold rather arbitrarily at 25% more than average,
|
||||
* with at least 2 instances in the sample. Also, we won't suppress
|
||||
* values that have a frequency of at least 1/K where K is the
|
||||
* intended number of histogram bins; such values might otherwise
|
||||
* cause us to emit duplicate histogram bin boundaries.
|
||||
* the table), then do so. Otherwise, store only those values
|
||||
* that are significantly more common than the (estimated)
|
||||
* average. We set the threshold rather arbitrarily at 25% more
|
||||
* than average, with at least 2 instances in the sample. Also,
|
||||
* we won't suppress values that have a frequency of at least 1/K
|
||||
* where K is the intended number of histogram bins; such values
|
||||
* might otherwise cause us to emit duplicate histogram bin
|
||||
* boundaries.
|
||||
*/
|
||||
if (track_cnt == ndistinct && toowide_cnt == 0 &&
|
||||
stats->stadistinct > 0 &&
|
||||
@@ -1333,13 +1354,13 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
}
|
||||
else
|
||||
{
|
||||
double ndistinct = stats->stadistinct;
|
||||
double avgcount,
|
||||
mincount,
|
||||
maxmincount;
|
||||
double ndistinct = stats->stadistinct;
|
||||
double avgcount,
|
||||
mincount,
|
||||
maxmincount;
|
||||
|
||||
if (ndistinct < 0)
|
||||
ndistinct = - ndistinct * totalrows;
|
||||
ndistinct = -ndistinct * totalrows;
|
||||
/* estimate # of occurrences in sample of a typical value */
|
||||
avgcount = (double) numrows / ndistinct;
|
||||
/* set minimum threshold count to store a value */
|
||||
@@ -1366,8 +1387,8 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
if (num_mcv > 0)
|
||||
{
|
||||
MemoryContext old_context;
|
||||
Datum *mcv_values;
|
||||
float4 *mcv_freqs;
|
||||
Datum *mcv_values;
|
||||
float4 *mcv_freqs;
|
||||
|
||||
/* Must copy the target values into TransactionCommandContext */
|
||||
old_context = MemoryContextSwitchTo(TransactionCommandContext);
|
||||
@@ -1402,8 +1423,8 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
if (num_hist >= 2)
|
||||
{
|
||||
MemoryContext old_context;
|
||||
Datum *hist_values;
|
||||
int nvals;
|
||||
Datum *hist_values;
|
||||
int nvals;
|
||||
|
||||
/* Sort the MCV items into position order to speed next loop */
|
||||
qsort((void *) track, num_mcv,
|
||||
@@ -1413,24 +1434,25 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
* Collapse out the MCV items from the values[] array.
|
||||
*
|
||||
* Note we destroy the values[] array here... but we don't need
|
||||
* it for anything more. We do, however, still need values_cnt.
|
||||
* nvals will be the number of remaining entries in values[].
|
||||
* it for anything more. We do, however, still need
|
||||
* values_cnt. nvals will be the number of remaining entries
|
||||
* in values[].
|
||||
*/
|
||||
if (num_mcv > 0)
|
||||
{
|
||||
int src,
|
||||
dest;
|
||||
int j;
|
||||
int src,
|
||||
dest;
|
||||
int j;
|
||||
|
||||
src = dest = 0;
|
||||
j = 0; /* index of next interesting MCV item */
|
||||
while (src < values_cnt)
|
||||
{
|
||||
int ncopy;
|
||||
int ncopy;
|
||||
|
||||
if (j < num_mcv)
|
||||
{
|
||||
int first = track[j].first;
|
||||
int first = track[j].first;
|
||||
|
||||
if (src >= first)
|
||||
{
|
||||
@@ -1442,9 +1464,7 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
ncopy = first - src;
|
||||
}
|
||||
else
|
||||
{
|
||||
ncopy = values_cnt - src;
|
||||
}
|
||||
memmove(&values[dest], &values[src],
|
||||
ncopy * sizeof(ScalarItem));
|
||||
src += ncopy;
|
||||
@@ -1461,7 +1481,7 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
hist_values = (Datum *) palloc(num_hist * sizeof(Datum));
|
||||
for (i = 0; i < num_hist; i++)
|
||||
{
|
||||
int pos;
|
||||
int pos;
|
||||
|
||||
pos = (i * (nvals - 1)) / (num_hist - 1);
|
||||
hist_values[i] = datumCopy(values[pos].value,
|
||||
@@ -1481,9 +1501,9 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
if (values_cnt > 1)
|
||||
{
|
||||
MemoryContext old_context;
|
||||
float4 *corrs;
|
||||
double corr_xsum,
|
||||
corr_x2sum;
|
||||
float4 *corrs;
|
||||
double corr_xsum,
|
||||
corr_x2sum;
|
||||
|
||||
/* Must copy the target values into TransactionCommandContext */
|
||||
old_context = MemoryContextSwitchTo(TransactionCommandContext);
|
||||
@@ -1499,9 +1519,10 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
* (values_cnt-1)*values_cnt*(2*values_cnt-1) / 6.
|
||||
*----------
|
||||
*/
|
||||
corr_xsum = (double) (values_cnt-1) * (double) values_cnt / 2.0;
|
||||
corr_x2sum = (double) (values_cnt-1) * (double) values_cnt *
|
||||
(double) (2*values_cnt-1) / 6.0;
|
||||
corr_xsum = (double) (values_cnt - 1) * (double) values_cnt / 2.0;
|
||||
corr_x2sum = (double) (values_cnt - 1) * (double) values_cnt *
|
||||
(double) (2 * values_cnt - 1) / 6.0;
|
||||
|
||||
/* And the correlation coefficient reduces to */
|
||||
corrs[0] = (values_cnt * corr_xysum - corr_xsum * corr_xsum) /
|
||||
(values_cnt * corr_x2sum - corr_xsum * corr_xsum);
|
||||
@@ -1521,7 +1542,7 @@ compute_scalar_stats(VacAttrStats *stats,
|
||||
* qsort comparator for sorting ScalarItems
|
||||
*
|
||||
* Aside from sorting the items, we update the datumCmpTupnoLink[] array
|
||||
* whenever two ScalarItems are found to contain equal datums. The array
|
||||
* whenever two ScalarItems are found to contain equal datums. The array
|
||||
* is indexed by tupno; for each ScalarItem, it contains the highest
|
||||
* tupno that that item's datum has been found to be equal to. This allows
|
||||
* us to avoid additional comparisons in compute_scalar_stats().
|
||||
@@ -1573,7 +1594,7 @@ compare_mcvs(const void *a, const void *b)
|
||||
* Statistics are stored in several places: the pg_class row for the
|
||||
* relation has stats about the whole relation, and there is a
|
||||
* pg_statistic row for each (non-system) attribute that has ever
|
||||
* been analyzed. The pg_class values are updated by VACUUM, not here.
|
||||
* been analyzed. The pg_class values are updated by VACUUM, not here.
|
||||
*
|
||||
* pg_statistic rows are just added or updated normally. This means
|
||||
* that pg_statistic will probably contain some deleted rows at the
|
||||
@@ -1604,7 +1625,9 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
|
||||
FmgrInfo out_function;
|
||||
HeapTuple stup,
|
||||
oldtup;
|
||||
int i, k, n;
|
||||
int i,
|
||||
k,
|
||||
n;
|
||||
Datum values[Natts_pg_statistic];
|
||||
char nulls[Natts_pg_statistic];
|
||||
char replaces[Natts_pg_statistic];
|
||||
@@ -1626,22 +1649,22 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
|
||||
}
|
||||
|
||||
i = 0;
|
||||
values[i++] = ObjectIdGetDatum(relid); /* starelid */
|
||||
values[i++] = Int16GetDatum(stats->attnum); /* staattnum */
|
||||
values[i++] = Float4GetDatum(stats->stanullfrac); /* stanullfrac */
|
||||
values[i++] = Int32GetDatum(stats->stawidth); /* stawidth */
|
||||
values[i++] = Float4GetDatum(stats->stadistinct); /* stadistinct */
|
||||
values[i++] = ObjectIdGetDatum(relid); /* starelid */
|
||||
values[i++] = Int16GetDatum(stats->attnum); /* staattnum */
|
||||
values[i++] = Float4GetDatum(stats->stanullfrac); /* stanullfrac */
|
||||
values[i++] = Int32GetDatum(stats->stawidth); /* stawidth */
|
||||
values[i++] = Float4GetDatum(stats->stadistinct); /* stadistinct */
|
||||
for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
|
||||
{
|
||||
values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */
|
||||
values[i++] = Int16GetDatum(stats->stakind[k]); /* stakindN */
|
||||
}
|
||||
for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
|
||||
{
|
||||
values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */
|
||||
values[i++] = ObjectIdGetDatum(stats->staop[k]); /* staopN */
|
||||
}
|
||||
for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
|
||||
{
|
||||
int nnum = stats->numnumbers[k];
|
||||
int nnum = stats->numnumbers[k];
|
||||
|
||||
if (nnum > 0)
|
||||
{
|
||||
@@ -1653,7 +1676,7 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
|
||||
/* XXX knows more than it should about type float4: */
|
||||
arry = construct_array(numdatums, nnum,
|
||||
false, sizeof(float4), 'i');
|
||||
values[i++] = PointerGetDatum(arry); /* stanumbersN */
|
||||
values[i++] = PointerGetDatum(arry); /* stanumbersN */
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1663,7 +1686,7 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
|
||||
}
|
||||
for (k = 0; k < STATISTIC_NUM_SLOTS; k++)
|
||||
{
|
||||
int ntxt = stats->numvalues[k];
|
||||
int ntxt = stats->numvalues[k];
|
||||
|
||||
if (ntxt > 0)
|
||||
{
|
||||
@@ -1676,20 +1699,20 @@ update_attstats(Oid relid, int natts, VacAttrStats **vacattrstats)
|
||||
* Convert data values to a text string to be inserted
|
||||
* into the text array.
|
||||
*/
|
||||
Datum stringdatum;
|
||||
Datum stringdatum;
|
||||
|
||||
stringdatum =
|
||||
FunctionCall3(&out_function,
|
||||
stats->stavalues[k][n],
|
||||
ObjectIdGetDatum(stats->attrtype->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod));
|
||||
ObjectIdGetDatum(stats->attrtype->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod));
|
||||
txtdatums[n] = DirectFunctionCall1(textin, stringdatum);
|
||||
pfree(DatumGetPointer(stringdatum));
|
||||
}
|
||||
/* XXX knows more than it should about type text: */
|
||||
arry = construct_array(txtdatums, ntxt,
|
||||
false, -1, 'i');
|
||||
values[i++] = PointerGetDatum(arry); /* stavaluesN */
|
||||
values[i++] = PointerGetDatum(arry); /* stavaluesN */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.80 2001/09/08 01:10:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.81 2001/10/25 05:49:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -120,7 +120,7 @@ static volatile int notifyInterruptOccurred = 0;
|
||||
/* True if we've registered an on_shmem_exit cleanup */
|
||||
static bool unlistenExitRegistered = false;
|
||||
|
||||
bool Trace_notify = false;
|
||||
bool Trace_notify = false;
|
||||
|
||||
|
||||
static void Async_UnlistenAll(void);
|
||||
@@ -153,13 +153,13 @@ Async_Notify(char *relname)
|
||||
elog(DEBUG, "Async_Notify: %s", relname);
|
||||
|
||||
/* no point in making duplicate entries in the list ... */
|
||||
if (! AsyncExistsPendingNotify(relname))
|
||||
if (!AsyncExistsPendingNotify(relname))
|
||||
{
|
||||
/*
|
||||
* The name list needs to live until end of transaction, so
|
||||
* store it in the top transaction context.
|
||||
* The name list needs to live until end of transaction, so store
|
||||
* it in the top transaction context.
|
||||
*/
|
||||
MemoryContext oldcontext;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(TopTransactionContext);
|
||||
|
||||
@@ -209,7 +209,7 @@ Async_Listen(char *relname, int pid)
|
||||
Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(tuple);
|
||||
|
||||
if (listener->listenerpid == pid &&
|
||||
strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0)
|
||||
strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0)
|
||||
{
|
||||
alreadyListener = true;
|
||||
/* No need to scan the rest of the table */
|
||||
@@ -310,13 +310,14 @@ Async_Unlisten(char *relname, int pid)
|
||||
Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(tuple);
|
||||
|
||||
if (listener->listenerpid == pid &&
|
||||
strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0)
|
||||
strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0)
|
||||
{
|
||||
/* Found the matching tuple, delete it */
|
||||
simple_heap_delete(lRel, &tuple->t_self);
|
||||
|
||||
/*
|
||||
* We assume there can be only one match, so no need
|
||||
* to scan the rest of the table
|
||||
* We assume there can be only one match, so no need to scan
|
||||
* the rest of the table
|
||||
*/
|
||||
break;
|
||||
}
|
||||
@@ -478,16 +479,16 @@ AtCommit_Notify(void)
|
||||
char *relname = NameStr(listener->relname);
|
||||
int32 listenerPID = listener->listenerpid;
|
||||
|
||||
if (! AsyncExistsPendingNotify(relname))
|
||||
if (!AsyncExistsPendingNotify(relname))
|
||||
continue;
|
||||
|
||||
if (listenerPID == MyProcPid)
|
||||
{
|
||||
/*
|
||||
* Self-notify: no need to bother with table update.
|
||||
* Indeed, we *must not* clear the notification field in
|
||||
* this path, or we could lose an outside notify, which'd
|
||||
* be bad for applications that ignore self-notify messages.
|
||||
* Self-notify: no need to bother with table update. Indeed,
|
||||
* we *must not* clear the notification field in this path, or
|
||||
* we could lose an outside notify, which'd be bad for
|
||||
* applications that ignore self-notify messages.
|
||||
*/
|
||||
|
||||
if (Trace_notify)
|
||||
@@ -503,22 +504,20 @@ AtCommit_Notify(void)
|
||||
|
||||
/*
|
||||
* If someone has already notified this listener, we don't
|
||||
* bother modifying the table, but we do still send a
|
||||
* SIGUSR2 signal, just in case that backend missed the
|
||||
* earlier signal for some reason. It's OK to send the
|
||||
* signal first, because the other guy can't read
|
||||
* pg_listener until we unlock it.
|
||||
* bother modifying the table, but we do still send a SIGUSR2
|
||||
* signal, just in case that backend missed the earlier signal
|
||||
* for some reason. It's OK to send the signal first, because
|
||||
* the other guy can't read pg_listener until we unlock it.
|
||||
*/
|
||||
if (kill(listenerPID, SIGUSR2) < 0)
|
||||
{
|
||||
/*
|
||||
* Get rid of pg_listener entry if it refers to a PID
|
||||
* that no longer exists. Presumably, that backend
|
||||
* crashed without deleting its pg_listener entries.
|
||||
* This code used to only delete the entry if
|
||||
* errno==ESRCH, but as far as I can see we should
|
||||
* just do it for any failure (certainly at least for
|
||||
* EPERM too...)
|
||||
* Get rid of pg_listener entry if it refers to a PID that
|
||||
* no longer exists. Presumably, that backend crashed
|
||||
* without deleting its pg_listener entries. This code
|
||||
* used to only delete the entry if errno==ESRCH, but as
|
||||
* far as I can see we should just do it for any failure
|
||||
* (certainly at least for EPERM too...)
|
||||
*/
|
||||
simple_heap_delete(lRel, &lTuple->t_self);
|
||||
}
|
||||
@@ -610,7 +609,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
||||
|
||||
if (notifyInterruptEnabled)
|
||||
{
|
||||
|
||||
/*
|
||||
* I'm not sure whether some flavors of Unix might allow another
|
||||
* SIGUSR2 occurrence to recursively interrupt this routine. To
|
||||
@@ -641,7 +639,6 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* In this path it is NOT SAFE to do much of anything, except
|
||||
* this:
|
||||
@@ -888,11 +885,11 @@ static void
|
||||
ClearPendingNotifies(void)
|
||||
{
|
||||
/*
|
||||
* We used to have to explicitly deallocate the list members and nodes,
|
||||
* because they were malloc'd. Now, since we know they are palloc'd
|
||||
* in TopTransactionContext, we need not do that --- they'll go away
|
||||
* automatically at transaction exit. We need only reset the list head
|
||||
* pointer.
|
||||
* We used to have to explicitly deallocate the list members and
|
||||
* nodes, because they were malloc'd. Now, since we know they are
|
||||
* palloc'd in TopTransactionContext, we need not do that --- they'll
|
||||
* go away automatically at transaction exit. We need only reset the
|
||||
* list head pointer.
|
||||
*/
|
||||
pendingNotifies = NIL;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.69 2001/08/21 16:36:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.70 2001/10/25 05:49:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -267,10 +267,9 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
||||
LocalHeapTuple.t_datamcxt = NULL;
|
||||
LocalHeapTuple.t_data = NULL;
|
||||
heap_fetch(LocalOldHeap, SnapshotNow, &LocalHeapTuple, &LocalBuffer,
|
||||
ScanDesc);
|
||||
ScanDesc);
|
||||
if (LocalHeapTuple.t_data != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* We must copy the tuple because heap_insert() will overwrite
|
||||
* the commit-status fields of the tuple it's handed, and the
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.33 2001/10/03 20:54:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.34 2001/10/25 05:49:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -332,9 +332,10 @@ CommentRelation(int reltype, char *relname, char *comment)
|
||||
elog(ERROR, "you are not permitted to comment on class '%s'", relname);
|
||||
|
||||
/*
|
||||
* Open the relation. We do this mainly to acquire a lock that ensures
|
||||
* no one else drops the relation before we commit. (If they did, they'd
|
||||
* fail to remove the entry we are about to make in pg_description.)
|
||||
* Open the relation. We do this mainly to acquire a lock that
|
||||
* ensures no one else drops the relation before we commit. (If they
|
||||
* did, they'd fail to remove the entry we are about to make in
|
||||
* pg_description.)
|
||||
*
|
||||
* heap_openr will complain if it's an index, so we must do this:
|
||||
*/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.141 2001/08/10 18:57:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.142 2001/10/25 05:49:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -76,7 +76,6 @@ static StringInfoData attribute_buf;
|
||||
#ifdef MULTIBYTE
|
||||
static int client_encoding;
|
||||
static int server_encoding;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -209,7 +208,6 @@ CopyDonePeek(FILE *fp, int c, int pickup)
|
||||
{
|
||||
if (pickup)
|
||||
{
|
||||
|
||||
/*
|
||||
* We want to pick it up - just receive again into dummy
|
||||
* buffer
|
||||
@@ -240,8 +238,8 @@ CopyDonePeek(FILE *fp, int c, int pickup)
|
||||
* (<from> = TRUE means we are inserting into the table.)
|
||||
*
|
||||
* If <pipe> is false, transfer is between the table and the file named
|
||||
* <filename>. Otherwise, transfer is between the table and our regular
|
||||
* input/output stream. The latter could be either stdin/stdout or a
|
||||
* <filename>. Otherwise, transfer is between the table and our regular
|
||||
* input/output stream. The latter could be either stdin/stdout or a
|
||||
* socket, depending on whether we're running under Postmaster control.
|
||||
*
|
||||
* Iff <binary>, unload or reload in the binary format, as opposed to the
|
||||
@@ -257,7 +255,7 @@ CopyDonePeek(FILE *fp, int c, int pickup)
|
||||
* NULL values as <null_print>.
|
||||
*
|
||||
* When loading in the text format from an input stream (as opposed to
|
||||
* a file), recognize a "." on a line by itself as EOF. Also recognize
|
||||
* a file), recognize a "." on a line by itself as EOF. Also recognize
|
||||
* a stream EOF. When unloading in the text format to an output stream,
|
||||
* write a "." on a line by itself at the end of the data.
|
||||
*
|
||||
@@ -534,7 +532,6 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it to
|
||||
* avoid memory leakage inside the type's output routine
|
||||
@@ -1197,7 +1194,6 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
|
||||
char *string_start;
|
||||
int mblen;
|
||||
int i;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.80 2001/08/16 20:38:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.81 2001/10/25 05:49:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,7 +37,7 @@ static List *MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
List **supOids, List **supconstr, bool *supHasOids);
|
||||
static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
|
||||
static void StoreCatalogInheritance(Oid relationId, List *supers);
|
||||
static int findAttrByName(const char *attributeName, List *schema);
|
||||
static int findAttrByName(const char *attributeName, List *schema);
|
||||
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
* including inherited attributes.
|
||||
*/
|
||||
schema = MergeAttributes(schema, stmt->inhRelnames, stmt->istemp,
|
||||
&inheritOids, &old_constraints, &parentHasOids);
|
||||
&inheritOids, &old_constraints, &parentHasOids);
|
||||
|
||||
numberOfAttributes = length(schema);
|
||||
if (numberOfAttributes <= 0)
|
||||
@@ -305,7 +305,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
List *constraints = NIL;
|
||||
bool parentHasOids = false;
|
||||
bool have_bogus_defaults = false;
|
||||
char *bogus_marker = "Bogus!"; /* marks conflicting defaults */
|
||||
char *bogus_marker = "Bogus!"; /* marks conflicting
|
||||
* defaults */
|
||||
int child_attno;
|
||||
|
||||
/*
|
||||
@@ -329,6 +330,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
coldef->colname);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reject duplicate names in the list of parents, too.
|
||||
*/
|
||||
@@ -346,7 +348,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
|
||||
/*
|
||||
* Scan the parents left-to-right, and merge their attributes to form
|
||||
* a list of inherited attributes (inhSchema). Also check to see if
|
||||
* a list of inherited attributes (inhSchema). Also check to see if
|
||||
* we need to inherit an OID column.
|
||||
*/
|
||||
child_attno = 0;
|
||||
@@ -387,7 +389,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
* the attributes of this parent table. (They are not the same
|
||||
* for parents after the first one.)
|
||||
*/
|
||||
newattno = (AttrNumber *) palloc(tupleDesc->natts*sizeof(AttrNumber));
|
||||
newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
|
||||
|
||||
for (parent_attno = 1; parent_attno <= tupleDesc->natts;
|
||||
parent_attno++)
|
||||
@@ -420,8 +422,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
if (exist_attno > 0)
|
||||
{
|
||||
/*
|
||||
* Yes, try to merge the two column definitions.
|
||||
* They must have the same type and typmod.
|
||||
* Yes, try to merge the two column definitions. They must
|
||||
* have the same type and typmod.
|
||||
*/
|
||||
elog(NOTICE, "CREATE TABLE: merging multiple inherited definitions of attribute \"%s\"",
|
||||
attributeName);
|
||||
@@ -429,7 +431,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
if (strcmp(def->typename->name, attributeType) != 0 ||
|
||||
def->typename->typmod != attribute->atttypmod)
|
||||
elog(ERROR, "CREATE TABLE: inherited attribute \"%s\" type conflict (%s and %s)",
|
||||
attributeName, def->typename->name, attributeType);
|
||||
attributeName, def->typename->name, attributeType);
|
||||
/* Merge of NOT NULL constraints = OR 'em together */
|
||||
def->is_not_null |= attribute->attnotnull;
|
||||
/* Default and other constraints are handled below */
|
||||
@@ -453,6 +455,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
inhSchema = lappend(inhSchema, def);
|
||||
newattno[parent_attno - 1] = ++child_attno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy default if any
|
||||
*/
|
||||
@@ -474,15 +477,17 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
}
|
||||
}
|
||||
Assert(this_default != NULL);
|
||||
|
||||
/*
|
||||
* If default expr could contain any vars, we'd need to fix
|
||||
* 'em, but it can't; so default is ready to apply to child.
|
||||
* If default expr could contain any vars, we'd need to
|
||||
* fix 'em, but it can't; so default is ready to apply to
|
||||
* child.
|
||||
*
|
||||
* If we already had a default from some prior parent,
|
||||
* check to see if they are the same. If so, no problem;
|
||||
* if not, mark the column as having a bogus default.
|
||||
* Below, we will complain if the bogus default isn't
|
||||
* overridden by the child schema.
|
||||
* If we already had a default from some prior parent, check
|
||||
* to see if they are the same. If so, no problem; if
|
||||
* not, mark the column as having a bogus default. Below,
|
||||
* we will complain if the bogus default isn't overridden
|
||||
* by the child schema.
|
||||
*/
|
||||
Assert(def->raw_default == NULL);
|
||||
if (def->cooked_default == NULL)
|
||||
@@ -494,6 +499,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now copy the constraints of this parent, adjusting attnos using
|
||||
* the completed newattno[] map
|
||||
@@ -555,8 +561,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
ColumnDef *def;
|
||||
|
||||
/*
|
||||
* Yes, try to merge the two column definitions.
|
||||
* They must have the same type and typmod.
|
||||
* Yes, try to merge the two column definitions. They must
|
||||
* have the same type and typmod.
|
||||
*/
|
||||
elog(NOTICE, "CREATE TABLE: merging attribute \"%s\" with inherited definition",
|
||||
attributeName);
|
||||
@@ -564,7 +570,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
if (strcmp(def->typename->name, attributeType) != 0 ||
|
||||
def->typename->typmod != newdef->typename->typmod)
|
||||
elog(ERROR, "CREATE TABLE: attribute \"%s\" type conflict (%s and %s)",
|
||||
attributeName, def->typename->name, attributeType);
|
||||
attributeName, def->typename->name, attributeType);
|
||||
/* Merge of NOT NULL constraints = OR 'em together */
|
||||
def->is_not_null |= newdef->is_not_null;
|
||||
/* If new def has a default, override previous default */
|
||||
@@ -630,7 +636,6 @@ change_varattnos_walker(Node *node, const AttrNumber *newattno)
|
||||
if (var->varlevelsup == 0 && var->varno == 1 &&
|
||||
var->varattno > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* ??? the following may be a problem when the node is
|
||||
* multiply referenced though stringToNode() doesn't create
|
||||
@@ -783,7 +788,6 @@ again:
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
|
||||
/*
|
||||
* found a later duplicate, so remove this entry.
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.80 2001/09/06 04:57:28 ishii Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.81 2001/10/25 05:49:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
#include "mb/pg_wchar.h" /* encoding check */
|
||||
#include "mb/pg_wchar.h" /* encoding check */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -148,11 +148,12 @@ createdb(const char *dbname, const char *dbpath,
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
/* Some encodings are client only */
|
||||
if (!PG_VALID_BE_ENCODING( encoding ))
|
||||
if (!PG_VALID_BE_ENCODING(encoding))
|
||||
elog(ERROR, "CREATE DATABASE: invalid backend encoding");
|
||||
#else
|
||||
Assert(encoding == 0); /* zero is PG_SQL_ASCII */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Preassign OID for pg_database tuple, so that we can compute db
|
||||
* path.
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.62 2001/10/13 01:35:25 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.63 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@@ -64,7 +64,7 @@ static void
|
||||
case_translate_language_name(const char *input, char *output)
|
||||
{
|
||||
/*
|
||||
* Translate the input language name to lower case, except if it's "C",
|
||||
* Translate the input language name to lower case, except if it's "C",
|
||||
* translate to upper case.
|
||||
*/
|
||||
int i;
|
||||
@@ -85,8 +85,8 @@ compute_return_type(TypeName *returnType,
|
||||
char **prorettype_p, bool *returnsSet_p)
|
||||
{
|
||||
/*
|
||||
* Examine the "returns" clause returnType of the CREATE FUNCTION statement
|
||||
* and return information about it as *prorettype_p and *returnsSet.
|
||||
* Examine the "returns" clause returnType of the CREATE FUNCTION statement
|
||||
* and return information about it as *prorettype_p and *returnsSet.
|
||||
*/
|
||||
*prorettype_p = TypeNameToInternalName(returnType);
|
||||
*returnsSet_p = returnType->setof;
|
||||
@@ -100,26 +100,26 @@ compute_full_attributes(List *parameters,
|
||||
bool *canCache_p, bool *isStrict_p)
|
||||
{
|
||||
/*-------------
|
||||
* Interpret the parameters *parameters and return their contents as
|
||||
* *byte_pct_p, etc.
|
||||
* Interpret the parameters *parameters and return their contents as
|
||||
* *byte_pct_p, etc.
|
||||
*
|
||||
* These parameters supply optional information about a function.
|
||||
* All have defaults if not specified.
|
||||
* These parameters supply optional information about a function.
|
||||
* All have defaults if not specified.
|
||||
*
|
||||
* Note: currently, only two of these parameters actually do anything:
|
||||
* Note: currently, only two of these parameters actually do anything:
|
||||
*
|
||||
* * canCache means the optimizer's constant-folder is allowed to
|
||||
* pre-evaluate the function when all its inputs are constants.
|
||||
* * canCache means the optimizer's constant-folder is allowed to
|
||||
* pre-evaluate the function when all its inputs are constants.
|
||||
*
|
||||
* * isStrict means the function should not be called when any NULL
|
||||
* inputs are present; instead a NULL result value should be assumed.
|
||||
* * isStrict means the function should not be called when any NULL
|
||||
* inputs are present; instead a NULL result value should be assumed.
|
||||
*
|
||||
* The other four parameters are not used anywhere. They used to be
|
||||
* used in the "expensive functions" optimizer, but that's been dead code
|
||||
* for a long time.
|
||||
* The other four parameters are not used anywhere. They used to be
|
||||
* used in the "expensive functions" optimizer, but that's been dead code
|
||||
* for a long time.
|
||||
*
|
||||
* Since canCache and isStrict are useful for any function, we now allow
|
||||
* attributes to be supplied for all functions regardless of language.
|
||||
* Since canCache and isStrict are useful for any function, we now allow
|
||||
* attributes to be supplied for all functions regardless of language.
|
||||
*------------
|
||||
*/
|
||||
List *pl;
|
||||
@@ -142,7 +142,6 @@ compute_full_attributes(List *parameters,
|
||||
*isStrict_p = true;
|
||||
else if (strcasecmp(param->defname, "trusted") == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* we don't have untrusted functions any more. The 4.2
|
||||
* implementation is lousy anyway so I took it out. -ay 10/94
|
||||
@@ -183,7 +182,6 @@ interpret_AS_clause(const char *languageName, const List *as,
|
||||
|
||||
if (strcmp(languageName, "C") == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* For "C" language, store the file name in probin and, when
|
||||
* given, the link symbol name in prosrc.
|
||||
@@ -358,7 +356,7 @@ DefineOperator(char *oprName,
|
||||
List *parameters)
|
||||
{
|
||||
uint16 precedence = 0; /* operator precedence */
|
||||
bool canHash = false;/* operator hashes */
|
||||
bool canHash = false; /* operator hashes */
|
||||
bool isLeftAssociative = true; /* operator is left
|
||||
* associative */
|
||||
char *functionName = NULL; /* function for operator */
|
||||
@@ -369,7 +367,7 @@ DefineOperator(char *oprName,
|
||||
char *negatorName = NULL; /* optional negator operator name */
|
||||
char *restrictionName = NULL; /* optional restrict. sel.
|
||||
* procedure */
|
||||
char *joinName = NULL;/* optional join sel. procedure name */
|
||||
char *joinName = NULL; /* optional join sel. procedure name */
|
||||
char *sortName1 = NULL; /* optional first sort operator */
|
||||
char *sortName2 = NULL; /* optional second sort operator */
|
||||
List *pl;
|
||||
@@ -534,8 +532,8 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
void
|
||||
DefineType(char *typeName, List *parameters)
|
||||
{
|
||||
int16 internalLength = -1; /* int2 */
|
||||
int16 externalLength = -1; /* int2 */
|
||||
int16 internalLength = -1; /* int2 */
|
||||
int16 externalLength = -1; /* int2 */
|
||||
char *elemName = NULL;
|
||||
char *inputName = NULL;
|
||||
char *outputName = NULL;
|
||||
@@ -546,7 +544,7 @@ DefineType(char *typeName, List *parameters)
|
||||
char delimiter = DEFAULT_TYPDELIM;
|
||||
char *shadow_type;
|
||||
List *pl;
|
||||
char alignment = 'i'; /* default alignment */
|
||||
char alignment = 'i'; /* default alignment */
|
||||
char storage = 'p'; /* default TOAST storage method */
|
||||
|
||||
/*
|
||||
@@ -591,9 +589,10 @@ DefineType(char *typeName, List *parameters)
|
||||
char *a = defGetString(defel);
|
||||
|
||||
/*
|
||||
* Note: if argument was an unquoted identifier, parser will have
|
||||
* applied xlateSqlType() to it, so be prepared to recognize
|
||||
* translated type names as well as the nominal form.
|
||||
* Note: if argument was an unquoted identifier, parser will
|
||||
* have applied xlateSqlType() to it, so be prepared to
|
||||
* recognize translated type names as well as the nominal
|
||||
* form.
|
||||
*/
|
||||
if (strcasecmp(a, "double") == 0)
|
||||
alignment = 'd';
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.66 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.67 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -114,8 +114,8 @@ ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest)
|
||||
struct timeval endtime;
|
||||
|
||||
/*
|
||||
* Set up the instrumentation for the top node.
|
||||
* This will cascade during plan initialisation
|
||||
* Set up the instrumentation for the top node. This will cascade
|
||||
* during plan initialisation
|
||||
*/
|
||||
plan->instrument = InstrAlloc();
|
||||
|
||||
@@ -124,7 +124,7 @@ ExplainOneQuery(Query *query, bool verbose, bool analyze, CommandDest dest)
|
||||
CommandCounterIncrement();
|
||||
gettimeofday(&endtime, NULL);
|
||||
|
||||
endtime.tv_sec -= starttime.tv_sec;
|
||||
endtime.tv_sec -= starttime.tv_sec;
|
||||
endtime.tv_usec -= starttime.tv_usec;
|
||||
while (endtime.tv_usec < 0)
|
||||
{
|
||||
@@ -328,9 +328,9 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
plan->startup_cost, plan->total_cost,
|
||||
plan->plan_rows, plan->plan_width);
|
||||
|
||||
if ( plan->instrument && plan->instrument->nloops > 0 )
|
||||
if (plan->instrument && plan->instrument->nloops > 0)
|
||||
{
|
||||
double nloops = plan->instrument->nloops;
|
||||
double nloops = plan->instrument->nloops;
|
||||
|
||||
appendStringInfo(str, " (actual time=%.2f..%.2f rows=%.0f loops=%.0f)",
|
||||
1000.0 * plan->instrument->startup / nloops,
|
||||
@@ -442,7 +442,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
static StringInfo
|
||||
Explain_PlanToString(Plan *plan, ExplainState *es)
|
||||
{
|
||||
StringInfo str = makeStringInfo();
|
||||
StringInfo str = makeStringInfo();
|
||||
|
||||
if (plan != NULL)
|
||||
explain_outNode(str, plan, 0, es);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.59 2001/10/24 09:28:31 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.60 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -49,7 +49,7 @@ static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId);
|
||||
static Oid GetDefaultOpClass(Oid attrType, Oid accessMethodId);
|
||||
|
||||
/*
|
||||
* DefineIndex
|
||||
@@ -97,7 +97,8 @@ DefineIndex(char *heapRelationName,
|
||||
heapRelationName);
|
||||
|
||||
/*
|
||||
* look up the access method, verify it can handle the requested features
|
||||
* look up the access method, verify it can handle the requested
|
||||
* features
|
||||
*/
|
||||
tuple = SearchSysCache(AMNAME,
|
||||
PointerGetDatum(accessMethodName),
|
||||
@@ -108,18 +109,18 @@ DefineIndex(char *heapRelationName,
|
||||
accessMethodId = tuple->t_data->t_oid;
|
||||
accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
|
||||
|
||||
if (unique && ! accessMethodForm->amcanunique)
|
||||
if (unique && !accessMethodForm->amcanunique)
|
||||
elog(ERROR, "DefineIndex: access method \"%s\" does not support UNIQUE indexes",
|
||||
accessMethodName);
|
||||
if (numberOfAttributes > 1 && ! accessMethodForm->amcanmulticol)
|
||||
if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol)
|
||||
elog(ERROR, "DefineIndex: access method \"%s\" does not support multi-column indexes",
|
||||
accessMethodName);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/*
|
||||
* Convert the partial-index predicate from parsetree form to
|
||||
* an implicit-AND qual expression, for easier evaluation at runtime.
|
||||
* Convert the partial-index predicate from parsetree form to an
|
||||
* implicit-AND qual expression, for easier evaluation at runtime.
|
||||
* While we are at it, we reduce it to a canonical (CNF or DNF) form
|
||||
* to simplify the task of proving implications.
|
||||
*/
|
||||
@@ -196,7 +197,7 @@ DefineIndex(char *heapRelationName,
|
||||
* (via the given range table) only to the given base relation oid.
|
||||
*
|
||||
* This used to also constrain the form of the predicate to forms that
|
||||
* indxpath.c could do something with. However, that seems overly
|
||||
* indxpath.c could do something with. However, that seems overly
|
||||
* restrictive. One useful application of partial indexes is to apply
|
||||
* a UNIQUE constraint across a subset of a table, and in that scenario
|
||||
* any evaluatable predicate will work. So accept any predicate here
|
||||
@@ -208,11 +209,12 @@ CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
|
||||
{
|
||||
if (length(rangeTable) != 1 || getrelid(1, rangeTable) != baseRelOid)
|
||||
elog(ERROR,
|
||||
"Partial-index predicates may refer only to the base relation");
|
||||
"Partial-index predicates may refer only to the base relation");
|
||||
|
||||
/*
|
||||
* We don't currently support generation of an actual query plan for a
|
||||
* predicate, only simple scalar expressions; hence these restrictions.
|
||||
* predicate, only simple scalar expressions; hence these
|
||||
* restrictions.
|
||||
*/
|
||||
if (contain_subplans((Node *) predList))
|
||||
elog(ERROR, "Cannot use subselect in index predicate");
|
||||
@@ -240,7 +242,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
||||
List *arglist;
|
||||
int nargs = 0;
|
||||
int i;
|
||||
FuncDetailCode fdresult;
|
||||
FuncDetailCode fdresult;
|
||||
Oid funcid;
|
||||
Oid rettype;
|
||||
bool retset;
|
||||
@@ -309,9 +311,9 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
||||
|
||||
/*
|
||||
* Require that the function be marked cachable. Using a noncachable
|
||||
* function for a functional index is highly questionable, since if you
|
||||
* aren't going to get the same result for the same data every time,
|
||||
* it's not clear what the index entries mean at all.
|
||||
* function for a functional index is highly questionable, since if
|
||||
* you aren't going to get the same result for the same data every
|
||||
* time, it's not clear what the index entries mean at all.
|
||||
*/
|
||||
if (!func_iscachable(funcid))
|
||||
elog(ERROR, "DefineIndex: index function must be marked iscachable");
|
||||
@@ -431,11 +433,11 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
|
||||
* (either exactly or binary-compatibly, but prefer an exact match).
|
||||
*
|
||||
* We could find more than one binary-compatible match, in which case we
|
||||
* require the user to specify which one he wants. If we find more than
|
||||
* one exact match, then someone put bogus entries in pg_opclass.
|
||||
* require the user to specify which one he wants. If we find more
|
||||
* than one exact match, then someone put bogus entries in pg_opclass.
|
||||
*
|
||||
* We could use an indexscan here, but since pg_opclass is small
|
||||
* and a scan on opcamid won't be very selective, the indexscan would
|
||||
* We could use an indexscan here, but since pg_opclass is small and a
|
||||
* scan on opcamid won't be very selective, the indexscan would
|
||||
* probably actually be slower than heapscan.
|
||||
*/
|
||||
ScanKeyEntryInitialize(&entry[0], 0x0,
|
||||
@@ -612,7 +614,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
||||
if (strcmp(dbname, DatabaseName) != 0)
|
||||
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
|
||||
|
||||
if (! (superuser() || is_dbadmin(MyDatabaseId)))
|
||||
if (!(superuser() || is_dbadmin(MyDatabaseId)))
|
||||
elog(ERROR, "REINDEX DATABASE: Permission denied.");
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.63 2001/10/03 20:54:20 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.64 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -227,7 +227,6 @@ AttributeAndRelationRemove(Oid typeOid)
|
||||
}
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
#endif /* NOTYET */
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.58 2001/10/08 18:40:04 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.59 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -167,7 +167,8 @@ renameatt(char *relname,
|
||||
heap_freetuple(atttup);
|
||||
|
||||
/*
|
||||
* Update column names of indexes that refer to the column being renamed.
|
||||
* Update column names of indexes that refer to the column being
|
||||
* renamed.
|
||||
*/
|
||||
indexoidlist = RelationGetIndexList(targetrelation);
|
||||
|
||||
@@ -177,9 +178,8 @@ renameatt(char *relname,
|
||||
HeapTuple indextup;
|
||||
|
||||
/*
|
||||
* First check to see if index is a functional index.
|
||||
* If so, its column name is a function name and shouldn't
|
||||
* be renamed here.
|
||||
* First check to see if index is a functional index. If so, its
|
||||
* column name is a function name and shouldn't be renamed here.
|
||||
*/
|
||||
indextup = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexoid),
|
||||
@@ -192,9 +192,10 @@ renameatt(char *relname,
|
||||
continue;
|
||||
}
|
||||
ReleaseSysCache(indextup);
|
||||
|
||||
/*
|
||||
* Okay, look to see if any column name of the index matches
|
||||
* the old attribute name.
|
||||
* Okay, look to see if any column name of the index matches the
|
||||
* old attribute name.
|
||||
*/
|
||||
atttup = SearchSysCacheCopy(ATTNAME,
|
||||
ObjectIdGetDatum(indexoid),
|
||||
@@ -206,20 +207,20 @@ renameatt(char *relname,
|
||||
/*
|
||||
* Update the (copied) attribute tuple.
|
||||
*/
|
||||
StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
|
||||
newattname, NAMEDATALEN);
|
||||
StrNCpy(NameStr(((Form_pg_attribute) GETSTRUCT(atttup))->attname),
|
||||
newattname, NAMEDATALEN);
|
||||
|
||||
simple_heap_update(attrelation, &atttup->t_self, atttup);
|
||||
simple_heap_update(attrelation, &atttup->t_self, atttup);
|
||||
|
||||
/* keep system catalog indices current */
|
||||
{
|
||||
Relation irelations[Num_pg_attr_indices];
|
||||
{
|
||||
Relation irelations[Num_pg_attr_indices];
|
||||
|
||||
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
|
||||
CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
|
||||
CatalogCloseIndices(Num_pg_attr_indices, irelations);
|
||||
}
|
||||
heap_freetuple(atttup);
|
||||
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations);
|
||||
CatalogIndexInsert(irelations, Num_pg_attr_indices, attrelation, atttup);
|
||||
CatalogCloseIndices(Num_pg_attr_indices, irelations);
|
||||
}
|
||||
heap_freetuple(atttup);
|
||||
}
|
||||
|
||||
freeList(indexoidlist);
|
||||
@@ -332,8 +333,8 @@ renamerel(const char *oldrelname, const char *newrelname)
|
||||
*/
|
||||
if (relkind == RELKIND_VIEW)
|
||||
{
|
||||
char *oldrulename,
|
||||
*newrulename;
|
||||
char *oldrulename,
|
||||
*newrulename;
|
||||
|
||||
oldrulename = MakeRetrieveViewRuleName(oldrelname);
|
||||
newrulename = MakeRetrieveViewRuleName(newrelname);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.64 2001/09/19 09:48:42 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.65 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,9 +36,9 @@
|
||||
#else
|
||||
#define SEQ_MAXVALUE ((int64) 0x7FFFFFFFFFFFFFFF)
|
||||
#endif
|
||||
#else /* INT64_IS_BUSTED */
|
||||
#else /* INT64_IS_BUSTED */
|
||||
#define SEQ_MAXVALUE ((int64) 0x7FFFFFFF)
|
||||
#endif /* INT64_IS_BUSTED */
|
||||
#endif /* INT64_IS_BUSTED */
|
||||
|
||||
#define SEQ_MINVALUE (-SEQ_MAXVALUE)
|
||||
|
||||
@@ -204,17 +204,17 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
heap_insert(rel, tuple);
|
||||
|
||||
/*
|
||||
* After crash REDO of heap_insert above would re-init page and
|
||||
* our magic number would be lost. We have to log sequence creation.
|
||||
* This means two log records instead of one -:(
|
||||
* After crash REDO of heap_insert above would re-init page and our
|
||||
* magic number would be lost. We have to log sequence creation. This
|
||||
* means two log records instead of one -:(
|
||||
*/
|
||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||
START_CRIT_SECTION();
|
||||
{
|
||||
xl_seq_rec xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);
|
||||
xl_seq_rec xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
Form_pg_sequence newseq = (Form_pg_sequence) GETSTRUCT(tuple);
|
||||
|
||||
/* We do not log first nextval call, so "advance" sequence here */
|
||||
newseq->is_called = true;
|
||||
@@ -582,12 +582,12 @@ get_seq_name(text *seqin)
|
||||
if (strlen(seqname) >= NAMEDATALEN)
|
||||
{
|
||||
#ifdef MULTIBYTE
|
||||
int len;
|
||||
int len;
|
||||
|
||||
len = pg_mbcliplen(seqname, rawlen, NAMEDATALEN-1);
|
||||
len = pg_mbcliplen(seqname, rawlen, NAMEDATALEN - 1);
|
||||
seqname[len] = '\0';
|
||||
#else
|
||||
seqname[NAMEDATALEN-1] = '\0';
|
||||
seqname[NAMEDATALEN - 1] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -658,7 +658,6 @@ init_sequence(char *caller, char *name)
|
||||
|
||||
if (elm != (SeqTable) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* We are using a seqtable entry left over from a previous xact;
|
||||
* must check for relid change.
|
||||
@@ -674,7 +673,6 @@ init_sequence(char *caller, char *name)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Time to make a new seqtable entry. These entries live as long
|
||||
* as the backend does, so we use plain malloc for them.
|
||||
@@ -713,7 +711,7 @@ CloseSequences(void)
|
||||
for (elm = seqtab; elm != (SeqTable) NULL; elm = elm->next)
|
||||
{
|
||||
rel = elm->rel;
|
||||
if (rel != (Relation) NULL) /* opened in current xact */
|
||||
if (rel != (Relation) NULL) /* opened in current xact */
|
||||
{
|
||||
elm->rel = (Relation) NULL;
|
||||
heap_close(rel, AccessShareLock);
|
||||
@@ -737,17 +735,17 @@ init_params(CreateSeqStmt *seq, Form_pg_sequence new)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
|
||||
if (strcmp(defel->defname, "increment")==0)
|
||||
if (strcmp(defel->defname, "increment") == 0)
|
||||
increment_by = defel;
|
||||
else if (strcmp(defel->defname, "start")==0)
|
||||
else if (strcmp(defel->defname, "start") == 0)
|
||||
last_value = defel;
|
||||
else if (strcmp(defel->defname, "maxvalue")==0)
|
||||
else if (strcmp(defel->defname, "maxvalue") == 0)
|
||||
max_value = defel;
|
||||
else if (strcmp(defel->defname, "minvalue")==0)
|
||||
else if (strcmp(defel->defname, "minvalue") == 0)
|
||||
min_value = defel;
|
||||
else if (strcmp(defel->defname, "cache")==0)
|
||||
else if (strcmp(defel->defname, "cache") == 0)
|
||||
cache_value = defel;
|
||||
else if (strcmp(defel->defname, "cycle")==0)
|
||||
else if (strcmp(defel->defname, "cycle") == 0)
|
||||
{
|
||||
if (defel->arg != (Node *) NULL)
|
||||
elog(ERROR, "DefineSequence: CYCLE ??");
|
||||
@@ -768,7 +766,7 @@ init_params(CreateSeqStmt *seq, Form_pg_sequence new)
|
||||
if (new->increment_by > 0)
|
||||
new->max_value = SEQ_MAXVALUE; /* ascending seq */
|
||||
else
|
||||
new->max_value = -1; /* descending seq */
|
||||
new->max_value = -1; /* descending seq */
|
||||
}
|
||||
else
|
||||
new->max_value = get_param(max_value);
|
||||
@@ -822,12 +820,12 @@ get_param(DefElem *def)
|
||||
return (int64) intVal(def->arg);
|
||||
|
||||
/*
|
||||
* Values too large for int4 will be represented as Float constants
|
||||
* by the lexer. Accept these if they are valid int8 strings.
|
||||
* Values too large for int4 will be represented as Float constants by
|
||||
* the lexer. Accept these if they are valid int8 strings.
|
||||
*/
|
||||
if (IsA(def->arg, Float))
|
||||
return DatumGetInt64(DirectFunctionCall1(int8in,
|
||||
CStringGetDatum(strVal(def->arg))));
|
||||
CStringGetDatum(strVal(def->arg))));
|
||||
|
||||
/* Shouldn't get here unless parser messed up */
|
||||
elog(ERROR, "DefineSequence: \"%s\" value must be integer", def->defname);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.96 2001/08/23 23:06:37 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.97 2001/10/25 05:49:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -34,17 +34,17 @@
|
||||
|
||||
static void InsertTrigger(TriggerDesc *trigdesc, Trigger *trigger, int indx);
|
||||
static HeapTuple GetTupleForTrigger(EState *estate,
|
||||
ResultRelInfo *relinfo,
|
||||
ItemPointer tid,
|
||||
TupleTableSlot **newSlot);
|
||||
ResultRelInfo *relinfo,
|
||||
ItemPointer tid,
|
||||
TupleTableSlot **newSlot);
|
||||
static HeapTuple ExecCallTriggerFunc(TriggerData *trigdata,
|
||||
FmgrInfo *finfo,
|
||||
MemoryContext per_tuple_context);
|
||||
FmgrInfo *finfo,
|
||||
MemoryContext per_tuple_context);
|
||||
static void DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
HeapTuple oldtup, HeapTuple newtup);
|
||||
HeapTuple oldtup, HeapTuple newtup);
|
||||
static void DeferredTriggerExecute(DeferredTriggerEvent event, int itemno,
|
||||
Relation rel, FmgrInfo *finfo,
|
||||
MemoryContext per_tuple_context);
|
||||
Relation rel, FmgrInfo *finfo,
|
||||
MemoryContext per_tuple_context);
|
||||
|
||||
|
||||
void
|
||||
@@ -93,7 +93,6 @@ CreateTrigger(CreateTrigStmt *stmt)
|
||||
constrrelid = InvalidOid;
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* NoLock is probably sufficient here, since we're only
|
||||
* interested in getting the relation's OID...
|
||||
@@ -849,8 +848,8 @@ ExecCallTriggerFunc(TriggerData *trigdata,
|
||||
MemoryContext oldContext;
|
||||
|
||||
/*
|
||||
* We cache fmgr lookup info, to avoid making the lookup
|
||||
* again on each call.
|
||||
* We cache fmgr lookup info, to avoid making the lookup again on each
|
||||
* call.
|
||||
*/
|
||||
if (finfo->fn_oid == InvalidOid)
|
||||
fmgr_info(trigdata->tg_trigger->tgfoid, finfo);
|
||||
@@ -915,14 +914,14 @@ ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
|
||||
LocTriggerData.tg_newtuple = NULL;
|
||||
for (i = 0; i < ntrigs; i++)
|
||||
{
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
|
||||
if (!trigger->tgenabled)
|
||||
continue;
|
||||
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
|
||||
LocTriggerData.tg_trigger = trigger;
|
||||
newtuple = ExecCallTriggerFunc(&LocTriggerData,
|
||||
relinfo->ri_TrigFunctions + tgindx[i],
|
||||
relinfo->ri_TrigFunctions + tgindx[i],
|
||||
GetPerTupleMemoryContext(estate));
|
||||
if (oldtuple != newtuple && oldtuple != trigtuple)
|
||||
heap_freetuple(oldtuple);
|
||||
@@ -978,14 +977,14 @@ ExecBRDeleteTriggers(EState *estate, ResultRelInfo *relinfo,
|
||||
LocTriggerData.tg_newtuple = NULL;
|
||||
for (i = 0; i < ntrigs; i++)
|
||||
{
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
|
||||
if (!trigger->tgenabled)
|
||||
continue;
|
||||
LocTriggerData.tg_trigtuple = trigtuple;
|
||||
LocTriggerData.tg_trigger = trigger;
|
||||
newtuple = ExecCallTriggerFunc(&LocTriggerData,
|
||||
relinfo->ri_TrigFunctions + tgindx[i],
|
||||
relinfo->ri_TrigFunctions + tgindx[i],
|
||||
GetPerTupleMemoryContext(estate));
|
||||
if (newtuple == NULL)
|
||||
break;
|
||||
@@ -1055,7 +1054,7 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
|
||||
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
|
||||
for (i = 0; i < ntrigs; i++)
|
||||
{
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
|
||||
if (!trigger->tgenabled)
|
||||
continue;
|
||||
@@ -1063,7 +1062,7 @@ ExecBRUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
|
||||
LocTriggerData.tg_newtuple = oldtuple = newtuple;
|
||||
LocTriggerData.tg_trigger = trigger;
|
||||
newtuple = ExecCallTriggerFunc(&LocTriggerData,
|
||||
relinfo->ri_TrigFunctions + tgindx[i],
|
||||
relinfo->ri_TrigFunctions + tgindx[i],
|
||||
GetPerTupleMemoryContext(estate));
|
||||
if (oldtuple != newtuple && oldtuple != intuple)
|
||||
heap_freetuple(oldtuple);
|
||||
@@ -1130,8 +1129,8 @@ ltrmark:;
|
||||
else if (!(ItemPointerEquals(&(tuple.t_self), tid)))
|
||||
{
|
||||
TupleTableSlot *epqslot = EvalPlanQual(estate,
|
||||
relinfo->ri_RangeTableIndex,
|
||||
&(tuple.t_self));
|
||||
relinfo->ri_RangeTableIndex,
|
||||
&(tuple.t_self));
|
||||
|
||||
if (!(TupIsNull(epqslot)))
|
||||
{
|
||||
@@ -1293,7 +1292,6 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
|
||||
static void
|
||||
deferredTriggerAddEvent(DeferredTriggerEvent event)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since the event list could grow quite long, we keep track of the
|
||||
* list tail and append there, rather than just doing a stupid
|
||||
@@ -1359,7 +1357,7 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
|
||||
* single trigger function.
|
||||
*
|
||||
* Frequently, this will be fired many times in a row for triggers of
|
||||
* a single relation. Therefore, we cache the open relation and provide
|
||||
* a single relation. Therefore, we cache the open relation and provide
|
||||
* fmgr lookup cache space at the caller level.
|
||||
*
|
||||
* event: event currently being fired.
|
||||
@@ -1535,8 +1533,8 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
||||
}
|
||||
|
||||
/*
|
||||
* So let's fire it... but first, open the correct relation
|
||||
* if this is not the same relation as before.
|
||||
* So let's fire it... but first, open the correct relation if
|
||||
* this is not the same relation as before.
|
||||
*/
|
||||
if (rel == NULL || rel->rd_id != event->dte_relid)
|
||||
{
|
||||
@@ -1544,11 +1542,13 @@ deferredTriggerInvokeEvents(bool immediate_only)
|
||||
heap_close(rel, NoLock);
|
||||
if (finfo)
|
||||
pfree(finfo);
|
||||
|
||||
/*
|
||||
* We assume that an appropriate lock is still held by the
|
||||
* executor, so grab no new lock here.
|
||||
*/
|
||||
rel = heap_open(event->dte_relid, NoLock);
|
||||
|
||||
/*
|
||||
* Allocate space to cache fmgr lookup info for triggers
|
||||
* of this relation.
|
||||
@@ -1667,7 +1667,6 @@ DeferredTriggerBeginXact(void)
|
||||
void
|
||||
DeferredTriggerEndQuery(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Ignore call if we aren't in a transaction.
|
||||
*/
|
||||
@@ -1688,7 +1687,6 @@ DeferredTriggerEndQuery(void)
|
||||
void
|
||||
DeferredTriggerEndXact(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Ignore call if we aren't in a transaction.
|
||||
*/
|
||||
@@ -1713,7 +1711,6 @@ DeferredTriggerEndXact(void)
|
||||
void
|
||||
DeferredTriggerAbortXact(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Ignore call if we aren't in a transaction.
|
||||
*/
|
||||
@@ -1751,7 +1748,6 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
||||
{
|
||||
if (!IsTransactionBlock())
|
||||
{
|
||||
|
||||
/*
|
||||
* ... outside of a transaction block
|
||||
*
|
||||
@@ -1779,7 +1775,6 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* ... inside of a transaction block
|
||||
*
|
||||
@@ -2050,7 +2045,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
new_event->dte_n_items = ntriggers;
|
||||
for (i = 0; i < ntriggers; i++)
|
||||
{
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
|
||||
new_event->dte_item[i].dti_tgoid = trigger->tgoid;
|
||||
new_event->dte_item[i].dti_state =
|
||||
@@ -2090,7 +2085,7 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
*/
|
||||
for (i = 0; i < ntriggers; i++)
|
||||
{
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
Trigger *trigger = &trigdesc->triggers[tgindx[i]];
|
||||
bool is_ri_trigger;
|
||||
bool key_unchanged;
|
||||
|
||||
@@ -2125,7 +2120,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
|
||||
if (key_unchanged)
|
||||
{
|
||||
|
||||
/*
|
||||
* The key hasn't changed, so no need later to invoke
|
||||
* the trigger at all. But remember other states from
|
||||
@@ -2138,7 +2132,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
if (prev_event->dte_event &
|
||||
TRIGGER_DEFERRED_ROW_INSERTED)
|
||||
{
|
||||
|
||||
/*
|
||||
* This is a row inserted during our
|
||||
* transaction. So any key value is considered
|
||||
@@ -2153,7 +2146,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is a row, previously updated. So if
|
||||
* this key has been changed before, we still
|
||||
@@ -2172,7 +2164,6 @@ DeferredTriggerSaveEvent(ResultRelInfo *relinfo, int event,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Bomb out if this key has been changed before.
|
||||
* Otherwise remember that we do so.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.84 2001/09/19 09:48:42 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.85 2001/10/25 05:49:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -170,7 +170,7 @@ update_pg_pwd(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/*
|
||||
* ExclusiveLock ensures no one modifies pg_shadow while we read it,
|
||||
* and that only one backend rewrites the flat file at a time. It's
|
||||
* and that only one backend rewrites the flat file at a time. It's
|
||||
* OK to allow normal reads of pg_shadow in parallel, however.
|
||||
*/
|
||||
Relation rel = heap_openr(ShadowRelationName, ExclusiveLock);
|
||||
@@ -199,15 +199,17 @@ CreateUser(CreateUserStmt *stmt)
|
||||
sysid_exists = false,
|
||||
havesysid = false;
|
||||
int max_id;
|
||||
List *item, *option;
|
||||
char *password = NULL; /* PostgreSQL user password */
|
||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||
char encrypted_password[MD5_PASSWD_LEN+1];
|
||||
int sysid = 0; /* PgSQL system id (valid if havesysid) */
|
||||
bool createdb = false; /* Can the user create databases? */
|
||||
bool createuser = false; /* Can this user create users? */
|
||||
List *groupElts = NIL; /* The groups the user is a member of */
|
||||
char *validUntil = NULL; /* The time the login is valid until */
|
||||
List *item,
|
||||
*option;
|
||||
char *password = NULL; /* PostgreSQL user password */
|
||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||
char encrypted_password[MD5_PASSWD_LEN + 1];
|
||||
int sysid = 0; /* PgSQL system id (valid if havesysid) */
|
||||
bool createdb = false; /* Can the user create databases? */
|
||||
bool createuser = false; /* Can this user create users? */
|
||||
List *groupElts = NIL; /* The groups the user is a member of */
|
||||
char *validUntil = NULL; /* The time the login is valid
|
||||
* until */
|
||||
DefElem *dpassword = NULL;
|
||||
DefElem *dsysid = NULL;
|
||||
DefElem *dcreatedb = NULL;
|
||||
@@ -218,11 +220,12 @@ CreateUser(CreateUserStmt *stmt)
|
||||
/* Extract options from the statement node tree */
|
||||
foreach(option, stmt->options)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
|
||||
if (strcmp(defel->defname, "password") == 0 ||
|
||||
strcmp(defel->defname, "encryptedPassword") == 0 ||
|
||||
strcmp(defel->defname, "unencryptedPassword") == 0) {
|
||||
strcmp(defel->defname, "unencryptedPassword") == 0)
|
||||
{
|
||||
if (dpassword)
|
||||
elog(ERROR, "CREATE USER: conflicting options");
|
||||
dpassword = defel;
|
||||
@@ -231,33 +234,38 @@ CreateUser(CreateUserStmt *stmt)
|
||||
else if (strcmp(defel->defname, "unencryptedPassword") == 0)
|
||||
encrypt_password = false;
|
||||
}
|
||||
else if (strcmp(defel->defname, "sysid") == 0) {
|
||||
else if (strcmp(defel->defname, "sysid") == 0)
|
||||
{
|
||||
if (dsysid)
|
||||
elog(ERROR, "CREATE USER: conflicting options");
|
||||
dsysid = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "createdb") == 0) {
|
||||
else if (strcmp(defel->defname, "createdb") == 0)
|
||||
{
|
||||
if (dcreatedb)
|
||||
elog(ERROR, "CREATE USER: conflicting options");
|
||||
dcreatedb = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "createuser") == 0) {
|
||||
else if (strcmp(defel->defname, "createuser") == 0)
|
||||
{
|
||||
if (dcreateuser)
|
||||
elog(ERROR, "CREATE USER: conflicting options");
|
||||
dcreateuser = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "groupElts") == 0) {
|
||||
else if (strcmp(defel->defname, "groupElts") == 0)
|
||||
{
|
||||
if (dgroupElts)
|
||||
elog(ERROR, "CREATE USER: conflicting options");
|
||||
dgroupElts = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "validUntil") == 0) {
|
||||
else if (strcmp(defel->defname, "validUntil") == 0)
|
||||
{
|
||||
if (dvalidUntil)
|
||||
elog(ERROR, "CREATE USER: conflicting options");
|
||||
dvalidUntil = defel;
|
||||
}
|
||||
else
|
||||
elog(ERROR,"CREATE USER: option \"%s\" not recognized",
|
||||
elog(ERROR, "CREATE USER: option \"%s\" not recognized",
|
||||
defel->defname);
|
||||
}
|
||||
|
||||
@@ -329,7 +337,7 @@ CreateUser(CreateUserStmt *stmt)
|
||||
elog(ERROR, "CREATE USER: sysid %d is already assigned", sysid);
|
||||
|
||||
/* If no sysid given, use max existing id + 1 */
|
||||
if (! havesysid)
|
||||
if (!havesysid)
|
||||
sysid = max_id + 1;
|
||||
|
||||
/*
|
||||
@@ -355,7 +363,7 @@ CreateUser(CreateUserStmt *stmt)
|
||||
else
|
||||
{
|
||||
if (!EncryptMD5(password, stmt->user, strlen(stmt->user),
|
||||
encrypted_password))
|
||||
encrypted_password))
|
||||
elog(ERROR, "CREATE USER: password encryption failed");
|
||||
new_record[Anum_pg_shadow_passwd - 1] =
|
||||
DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
|
||||
@@ -438,26 +446,28 @@ AlterUser(AlterUserStmt *stmt)
|
||||
HeapTuple tuple,
|
||||
new_tuple;
|
||||
bool null;
|
||||
List *option;
|
||||
char *password = NULL; /* PostgreSQL user password */
|
||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||
char encrypted_password[MD5_PASSWD_LEN+1];
|
||||
int createdb = -1; /* Can the user create databases? */
|
||||
int createuser = -1; /* Can this user create users? */
|
||||
char *validUntil = NULL; /* The time the login is valid until */
|
||||
List *option;
|
||||
char *password = NULL; /* PostgreSQL user password */
|
||||
bool encrypt_password = Password_encryption; /* encrypt password? */
|
||||
char encrypted_password[MD5_PASSWD_LEN + 1];
|
||||
int createdb = -1; /* Can the user create databases? */
|
||||
int createuser = -1; /* Can this user create users? */
|
||||
char *validUntil = NULL; /* The time the login is valid
|
||||
* until */
|
||||
DefElem *dpassword = NULL;
|
||||
DefElem *dcreatedb = NULL;
|
||||
DefElem *dcreateuser = NULL;
|
||||
DefElem *dvalidUntil = NULL;
|
||||
|
||||
/* Extract options from the statement node tree */
|
||||
foreach(option,stmt->options)
|
||||
foreach(option, stmt->options)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
|
||||
if (strcmp(defel->defname, "password") == 0 ||
|
||||
strcmp(defel->defname, "encryptedPassword") == 0 ||
|
||||
strcmp(defel->defname, "unencryptedPassword") == 0) {
|
||||
strcmp(defel->defname, "unencryptedPassword") == 0)
|
||||
{
|
||||
if (dpassword)
|
||||
elog(ERROR, "ALTER USER: conflicting options");
|
||||
dpassword = defel;
|
||||
@@ -466,23 +476,26 @@ AlterUser(AlterUserStmt *stmt)
|
||||
else if (strcmp(defel->defname, "unencryptedPassword") == 0)
|
||||
encrypt_password = false;
|
||||
}
|
||||
else if (strcmp(defel->defname, "createdb") == 0) {
|
||||
else if (strcmp(defel->defname, "createdb") == 0)
|
||||
{
|
||||
if (dcreatedb)
|
||||
elog(ERROR, "ALTER USER: conflicting options");
|
||||
dcreatedb = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "createuser") == 0) {
|
||||
else if (strcmp(defel->defname, "createuser") == 0)
|
||||
{
|
||||
if (dcreateuser)
|
||||
elog(ERROR, "ALTER USER: conflicting options");
|
||||
dcreateuser = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "validUntil") == 0) {
|
||||
else if (strcmp(defel->defname, "validUntil") == 0)
|
||||
{
|
||||
if (dvalidUntil)
|
||||
elog(ERROR, "ALTER USER: conflicting options");
|
||||
dvalidUntil = defel;
|
||||
}
|
||||
else
|
||||
elog(ERROR,"ALTER USER: option \"%s\" not recognized",
|
||||
elog(ERROR, "ALTER USER: option \"%s\" not recognized",
|
||||
defel->defname);
|
||||
}
|
||||
|
||||
@@ -556,10 +569,10 @@ AlterUser(AlterUserStmt *stmt)
|
||||
/*
|
||||
* createuser (superuser) and catupd
|
||||
*
|
||||
* XXX It's rather unclear how to handle catupd. It's probably
|
||||
* best to keep it equal to the superuser status, otherwise you
|
||||
* could end up with a situation where no existing superuser can
|
||||
* alter the catalogs, including pg_shadow!
|
||||
* XXX It's rather unclear how to handle catupd. It's probably best to
|
||||
* keep it equal to the superuser status, otherwise you could end up
|
||||
* with a situation where no existing superuser can alter the
|
||||
* catalogs, including pg_shadow!
|
||||
*/
|
||||
if (createuser < 0)
|
||||
{
|
||||
@@ -588,7 +601,7 @@ AlterUser(AlterUserStmt *stmt)
|
||||
else
|
||||
{
|
||||
if (!EncryptMD5(password, stmt->user, strlen(stmt->user),
|
||||
encrypted_password))
|
||||
encrypted_password))
|
||||
elog(ERROR, "CREATE USER: password encryption failed");
|
||||
new_record[Anum_pg_shadow_passwd - 1] =
|
||||
DirectFunctionCall1(textin, CStringGetDatum(encrypted_password));
|
||||
@@ -719,7 +732,7 @@ DropUser(DropUserStmt *stmt)
|
||||
|
||||
if (HeapTupleIsValid(tmp_tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
char *dbname;
|
||||
char *dbname;
|
||||
|
||||
datum = heap_getattr(tmp_tuple, Anum_pg_database_datname,
|
||||
pg_dsc, &null);
|
||||
@@ -847,20 +860,22 @@ CreateGroup(CreateGroupStmt *stmt)
|
||||
|
||||
foreach(option, stmt->options)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
DefElem *defel = (DefElem *) lfirst(option);
|
||||
|
||||
if (strcmp(defel->defname, "sysid") == 0) {
|
||||
if (strcmp(defel->defname, "sysid") == 0)
|
||||
{
|
||||
if (dsysid)
|
||||
elog(ERROR, "CREATE GROUP: conflicting options");
|
||||
dsysid = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "userElts") == 0) {
|
||||
else if (strcmp(defel->defname, "userElts") == 0)
|
||||
{
|
||||
if (duserElts)
|
||||
elog(ERROR, "CREATE GROUP: conflicting options");
|
||||
duserElts = defel;
|
||||
}
|
||||
else
|
||||
elog(ERROR,"CREATE GROUP: option \"%s\" not recognized",
|
||||
elog(ERROR, "CREATE GROUP: option \"%s\" not recognized",
|
||||
defel->defname);
|
||||
}
|
||||
|
||||
@@ -900,7 +915,7 @@ CreateGroup(CreateGroupStmt *stmt)
|
||||
datum = heap_getattr(tuple, Anum_pg_group_grosysid,
|
||||
pg_group_dsc, &null);
|
||||
Assert(!null);
|
||||
if (havesysid) /* customized id wanted */
|
||||
if (havesysid) /* customized id wanted */
|
||||
sysid_exists = (DatumGetInt32(datum) == sysid);
|
||||
else
|
||||
{
|
||||
@@ -939,7 +954,7 @@ CreateGroup(CreateGroupStmt *stmt)
|
||||
userarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32));
|
||||
userarray->size = ARR_OVERHEAD(1) + length(newlist) * sizeof(int32);
|
||||
userarray->flags = 0;
|
||||
ARR_NDIM(userarray) = 1;/* one dimensional array */
|
||||
ARR_NDIM(userarray) = 1; /* one dimensional array */
|
||||
ARR_LBOUND(userarray)[0] = 1; /* axis starts at one */
|
||||
ARR_DIMS(userarray)[0] = length(newlist); /* axis is this long */
|
||||
/* fill the array */
|
||||
@@ -1088,6 +1103,7 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
|
||||
if (!member(v, newlist))
|
||||
newlist = lappend(newlist, v);
|
||||
else
|
||||
|
||||
/*
|
||||
* we silently assume here that this error will only come
|
||||
* up in a ALTER GROUP statement
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* The postgres vacuum cleaner.
|
||||
*
|
||||
* This file includes the "full" version of VACUUM, as well as control code
|
||||
* used by all three of full VACUUM, lazy VACUUM, and ANALYZE. See
|
||||
* used by all three of full VACUUM, lazy VACUUM, and ANALYZE. See
|
||||
* vacuumlazy.c and analyze.c for the rest of the code for the latter two.
|
||||
*
|
||||
*
|
||||
@@ -13,7 +13,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.209 2001/09/04 19:12:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.210 2001/10/25 05:49:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -68,11 +68,11 @@ typedef VacPageData *VacPage;
|
||||
|
||||
typedef struct VacPageListData
|
||||
{
|
||||
BlockNumber empty_end_pages; /* Number of "empty" end-pages */
|
||||
int num_pages; /* Number of pages in pagedesc */
|
||||
BlockNumber empty_end_pages; /* Number of "empty" end-pages */
|
||||
int num_pages; /* Number of pages in pagedesc */
|
||||
int num_allocated_pages; /* Number of allocated pages in
|
||||
* pagedesc */
|
||||
VacPage *pagedesc; /* Descriptions of pages */
|
||||
VacPage *pagedesc; /* Descriptions of pages */
|
||||
} VacPageListData;
|
||||
|
||||
typedef VacPageListData *VacPageList;
|
||||
@@ -96,7 +96,7 @@ typedef VTupleMoveData *VTupleMove;
|
||||
|
||||
typedef struct VRelStats
|
||||
{
|
||||
BlockNumber rel_pages;
|
||||
BlockNumber rel_pages;
|
||||
double rel_tuples;
|
||||
Size min_tlen;
|
||||
Size max_tlen;
|
||||
@@ -122,32 +122,32 @@ static void vacuum_init(VacuumStmt *vacstmt);
|
||||
static void vacuum_shutdown(VacuumStmt *vacstmt);
|
||||
static VRelList getrels(Name VacRelP, const char *stmttype);
|
||||
static void vac_update_dbstats(Oid dbid,
|
||||
TransactionId vacuumXID,
|
||||
TransactionId frozenXID);
|
||||
TransactionId vacuumXID,
|
||||
TransactionId frozenXID);
|
||||
static void vac_truncate_clog(TransactionId vacuumXID,
|
||||
TransactionId frozenXID);
|
||||
TransactionId frozenXID);
|
||||
static void vacuum_rel(Oid relid, VacuumStmt *vacstmt);
|
||||
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
|
||||
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages);
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages);
|
||||
static void repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages,
|
||||
int nindexes, Relation *Irel);
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages,
|
||||
int nindexes, Relation *Irel);
|
||||
static void vacuum_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
VacPageList vacpagelist);
|
||||
VacPageList vacpagelist);
|
||||
static void vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage);
|
||||
static void vacuum_index(VacPageList vacpagelist, Relation indrel,
|
||||
double num_tuples, int keep_tuples);
|
||||
double num_tuples, int keep_tuples);
|
||||
static void scan_index(Relation indrel, double num_tuples);
|
||||
static bool tid_reaped(ItemPointer itemptr, void *state);
|
||||
static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
|
||||
static void vac_update_fsm(Relation onerel, VacPageList fraged_pages,
|
||||
BlockNumber rel_pages);
|
||||
BlockNumber rel_pages);
|
||||
static VacPage copy_vac_page(VacPage vacpage);
|
||||
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
|
||||
static void *vac_bsearch(const void *key, const void *base,
|
||||
size_t nelem, size_t size,
|
||||
int (*compar) (const void *, const void *));
|
||||
size_t nelem, size_t size,
|
||||
int (*compar) (const void *, const void *));
|
||||
static int vac_cmp_blk(const void *left, const void *right);
|
||||
static int vac_cmp_offno(const void *left, const void *right);
|
||||
static int vac_cmp_vtlinks(const void *left, const void *right);
|
||||
@@ -227,11 +227,11 @@ vacuum(VacuumStmt *vacstmt)
|
||||
vacuum_init(vacstmt);
|
||||
|
||||
/*
|
||||
* Process each selected relation. We are careful to process
|
||||
* each relation in a separate transaction in order to avoid holding
|
||||
* too many locks at one time. Also, if we are doing VACUUM ANALYZE,
|
||||
* the ANALYZE part runs as a separate transaction from the VACUUM
|
||||
* to further reduce locking.
|
||||
* Process each selected relation. We are careful to process each
|
||||
* relation in a separate transaction in order to avoid holding too
|
||||
* many locks at one time. Also, if we are doing VACUUM ANALYZE, the
|
||||
* ANALYZE part runs as a separate transaction from the VACUUM to
|
||||
* further reduce locking.
|
||||
*/
|
||||
for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
|
||||
{
|
||||
@@ -271,21 +271,21 @@ vacuum_init(VacuumStmt *vacstmt)
|
||||
if (vacstmt->vacuum && vacstmt->vacrel == NULL)
|
||||
{
|
||||
/*
|
||||
* Compute the initially applicable OldestXmin and FreezeLimit XIDs,
|
||||
* so that we can record these values at the end of the VACUUM.
|
||||
* Note that individual tables may well be processed with newer values,
|
||||
* but we can guarantee that no (non-shared) relations are processed
|
||||
* with older ones.
|
||||
* Compute the initially applicable OldestXmin and FreezeLimit
|
||||
* XIDs, so that we can record these values at the end of the
|
||||
* VACUUM. Note that individual tables may well be processed with
|
||||
* newer values, but we can guarantee that no (non-shared)
|
||||
* relations are processed with older ones.
|
||||
*
|
||||
* It is okay to record non-shared values in pg_database, even though
|
||||
* we may vacuum shared relations with older cutoffs, because only
|
||||
* the minimum of the values present in pg_database matters. We
|
||||
* can be sure that shared relations have at some time been vacuumed
|
||||
* with cutoffs no worse than the global minimum; for, if there is
|
||||
* a backend in some other DB with xmin = OLDXMIN that's determining
|
||||
* the cutoff with which we vacuum shared relations, it is not possible
|
||||
* for that database to have a cutoff newer than OLDXMIN recorded in
|
||||
* pg_database.
|
||||
* can be sure that shared relations have at some time been
|
||||
* vacuumed with cutoffs no worse than the global minimum; for, if
|
||||
* there is a backend in some other DB with xmin = OLDXMIN that's
|
||||
* determining the cutoff with which we vacuum shared relations,
|
||||
* it is not possible for that database to have a cutoff newer
|
||||
* than OLDXMIN recorded in pg_database.
|
||||
*/
|
||||
vacuum_set_xid_limits(vacstmt, false,
|
||||
&initialOldestXmin, &initialFreezeLimit);
|
||||
@@ -316,11 +316,12 @@ vacuum_shutdown(VacuumStmt *vacstmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we did a complete vacuum or analyze, then flush the init file that
|
||||
* relcache.c uses to save startup time. The next backend startup will
|
||||
* rebuild the init file with up-to-date information from pg_class.
|
||||
* This lets the optimizer see the stats that we've collected for certain
|
||||
* critical system indexes. See relcache.c for more details.
|
||||
* If we did a complete vacuum or analyze, then flush the init file
|
||||
* that relcache.c uses to save startup time. The next backend startup
|
||||
* will rebuild the init file with up-to-date information from
|
||||
* pg_class. This lets the optimizer see the stats that we've
|
||||
* collected for certain critical system indexes. See relcache.c for
|
||||
* more details.
|
||||
*
|
||||
* Ignore any failure to unlink the file, since it might not be there if
|
||||
* no backend has been started since the last vacuum.
|
||||
@@ -526,9 +527,10 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples,
|
||||
pgcform->relpages = (int32) num_pages;
|
||||
pgcform->reltuples = num_tuples;
|
||||
pgcform->relhasindex = hasindex;
|
||||
|
||||
/*
|
||||
* If we have discovered that there are no indexes, then there's
|
||||
* no primary key either. This could be done more thoroughly...
|
||||
* If we have discovered that there are no indexes, then there's no
|
||||
* primary key either. This could be done more thoroughly...
|
||||
*/
|
||||
if (!hasindex)
|
||||
pgcform->relhaspkey = false;
|
||||
@@ -606,7 +608,7 @@ vac_update_dbstats(Oid dbid,
|
||||
* seems to be in danger of wrapping around.
|
||||
*
|
||||
* The passed XIDs are simply the ones I just wrote into my pg_database
|
||||
* entry. They're used to initialize the "min" calculations.
|
||||
* entry. They're used to initialize the "min" calculations.
|
||||
*
|
||||
* This routine is shared by full and lazy VACUUM. Note that it is only
|
||||
* applied after a database-wide VACUUM operation.
|
||||
@@ -708,26 +710,27 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
/*
|
||||
* Determine the type of lock we want --- hard exclusive lock for a
|
||||
* FULL vacuum, but just ShareUpdateExclusiveLock for concurrent
|
||||
* vacuum. Either way, we can be sure that no other backend is vacuuming
|
||||
* the same table.
|
||||
* vacuum. Either way, we can be sure that no other backend is
|
||||
* vacuuming the same table.
|
||||
*/
|
||||
lmode = vacstmt->full ? AccessExclusiveLock : ShareUpdateExclusiveLock;
|
||||
|
||||
/*
|
||||
* Open the class, get an appropriate lock on it, and check permissions.
|
||||
* Open the class, get an appropriate lock on it, and check
|
||||
* permissions.
|
||||
*
|
||||
* We allow the user to vacuum a table if he is superuser, the table
|
||||
* owner, or the database owner (but in the latter case, only if it's
|
||||
* not a shared relation). pg_ownercheck includes the superuser case.
|
||||
* not a shared relation). pg_ownercheck includes the superuser case.
|
||||
*
|
||||
* Note we choose to treat permissions failure as a NOTICE and keep
|
||||
* trying to vacuum the rest of the DB --- is this appropriate?
|
||||
*/
|
||||
onerel = heap_open(relid, lmode);
|
||||
|
||||
if (! (pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
|
||||
RELNAME) ||
|
||||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
|
||||
if (!(pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
|
||||
RELNAME) ||
|
||||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
|
||||
{
|
||||
elog(NOTICE, "Skipping \"%s\" --- only table or database owner can VACUUM it",
|
||||
RelationGetRelationName(onerel));
|
||||
@@ -773,9 +776,9 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
|
||||
/*
|
||||
* If the relation has a secondary toast rel, vacuum that too while we
|
||||
* still hold the session lock on the master table. Note however that
|
||||
* "analyze" will not get done on the toast table. This is good,
|
||||
* because the toaster always uses hardcoded index access and statistics
|
||||
* are totally unimportant for toast relations.
|
||||
* "analyze" will not get done on the toast table. This is good,
|
||||
* because the toaster always uses hardcoded index access and
|
||||
* statistics are totally unimportant for toast relations.
|
||||
*/
|
||||
if (toast_relid != InvalidOid)
|
||||
vacuum_rel(toast_relid, vacstmt);
|
||||
@@ -846,6 +849,7 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
||||
vacrelstats->hasindex = true;
|
||||
|
||||
#ifdef NOT_USED
|
||||
|
||||
/*
|
||||
* reindex in VACUUM is dangerous under WAL. ifdef out until it
|
||||
* becomes safe.
|
||||
@@ -945,7 +949,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
char *relname;
|
||||
VacPage vacpage,
|
||||
vacpagecopy;
|
||||
BlockNumber empty_pages,
|
||||
BlockNumber empty_pages,
|
||||
new_pages,
|
||||
changed_pages,
|
||||
empty_end_pages;
|
||||
@@ -1057,12 +1061,13 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
break;
|
||||
case HEAPTUPLE_LIVE:
|
||||
|
||||
/*
|
||||
* Tuple is good. Consider whether to replace its xmin
|
||||
* value with FrozenTransactionId.
|
||||
* Tuple is good. Consider whether to replace its
|
||||
* xmin value with FrozenTransactionId.
|
||||
*/
|
||||
if (TransactionIdIsNormal(tuple.t_data->t_xmin) &&
|
||||
TransactionIdPrecedes(tuple.t_data->t_xmin,
|
||||
@@ -1075,11 +1080,13 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
}
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
|
||||
/*
|
||||
* If tuple is recently deleted then we must not remove
|
||||
* it from relation.
|
||||
* If tuple is recently deleted then we must not
|
||||
* remove it from relation.
|
||||
*/
|
||||
nkeep += 1;
|
||||
|
||||
/*
|
||||
* If we do shrinking and this tuple is updated one
|
||||
* then remember it to construct updated tuple
|
||||
@@ -1103,18 +1110,20 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
}
|
||||
break;
|
||||
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
||||
|
||||
/*
|
||||
* This should not happen, since we hold exclusive lock
|
||||
* on the relation; shouldn't we raise an error?
|
||||
* This should not happen, since we hold exclusive
|
||||
* lock on the relation; shouldn't we raise an error?
|
||||
*/
|
||||
elog(NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
|
||||
relname, blkno, offnum, tuple.t_data->t_xmin);
|
||||
do_shrinking = false;
|
||||
break;
|
||||
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
||||
|
||||
/*
|
||||
* This should not happen, since we hold exclusive lock
|
||||
* on the relation; shouldn't we raise an error?
|
||||
* This should not happen, since we hold exclusive
|
||||
* lock on the relation; shouldn't we raise an error?
|
||||
*/
|
||||
elog(NOTICE, "Rel %s: TID %u/%u: DeleteTransactionInProgress %u - can't shrink relation",
|
||||
relname, blkno, offnum, tuple.t_data->t_xmax);
|
||||
@@ -1174,7 +1183,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
if (tuple.t_len > max_tlen)
|
||||
max_tlen = tuple.t_len;
|
||||
}
|
||||
} /* scan along page */
|
||||
} /* scan along page */
|
||||
|
||||
if (tempPage != (Page) NULL)
|
||||
{
|
||||
@@ -1193,13 +1202,14 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
}
|
||||
|
||||
free_size += vacpage->free;
|
||||
|
||||
/*
|
||||
* Add the page to fraged_pages if it has a useful amount of free
|
||||
* space. "Useful" means enough for a minimal-sized tuple.
|
||||
* But we don't know that accurately near the start of the relation,
|
||||
* so add pages unconditionally if they have >= BLCKSZ/10 free space.
|
||||
* space. "Useful" means enough for a minimal-sized tuple. But we
|
||||
* don't know that accurately near the start of the relation, so
|
||||
* add pages unconditionally if they have >= BLCKSZ/10 free space.
|
||||
*/
|
||||
do_frag = (vacpage->free >= min_tlen || vacpage->free >= BLCKSZ/10);
|
||||
do_frag = (vacpage->free >= min_tlen || vacpage->free >= BLCKSZ / 10);
|
||||
|
||||
if (do_reap || do_frag)
|
||||
{
|
||||
@@ -1238,9 +1248,9 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
fraged_pages->empty_end_pages = empty_end_pages;
|
||||
|
||||
/*
|
||||
* Clear the fraged_pages list if we found we couldn't shrink.
|
||||
* Else, remove any "empty" end-pages from the list, and compute
|
||||
* usable free space = free space in remaining pages.
|
||||
* Clear the fraged_pages list if we found we couldn't shrink. Else,
|
||||
* remove any "empty" end-pages from the list, and compute usable free
|
||||
* space = free space in remaining pages.
|
||||
*/
|
||||
if (do_shrinking)
|
||||
{
|
||||
@@ -1303,9 +1313,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
CommandId myCID;
|
||||
Buffer buf,
|
||||
cur_buffer;
|
||||
BlockNumber nblocks,
|
||||
BlockNumber nblocks,
|
||||
blkno;
|
||||
BlockNumber last_move_dest_block = 0,
|
||||
BlockNumber last_move_dest_block = 0,
|
||||
last_vacuum_block;
|
||||
Page page,
|
||||
ToPage = NULL;
|
||||
@@ -1355,7 +1365,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
resultRelInfo = makeNode(ResultRelInfo);
|
||||
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
|
||||
resultRelInfo->ri_RelationDesc = onerel;
|
||||
resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
|
||||
resultRelInfo->ri_TrigDesc = NULL; /* we don't fire triggers */
|
||||
|
||||
ExecOpenIndices(resultRelInfo);
|
||||
|
||||
@@ -1393,9 +1403,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
/*
|
||||
* Scan pages backwards from the last nonempty page, trying to move
|
||||
* tuples down to lower pages. Quit when we reach a page that we have
|
||||
* moved any tuples onto, or the first page if we haven't moved anything,
|
||||
* or when we find a page we cannot completely empty (this last condition
|
||||
* is handled by "break" statements within the loop).
|
||||
* moved any tuples onto, or the first page if we haven't moved
|
||||
* anything, or when we find a page we cannot completely empty (this
|
||||
* last condition is handled by "break" statements within the loop).
|
||||
*
|
||||
* NB: this code depends on the vacuum_pages and fraged_pages lists being
|
||||
* in order by blkno.
|
||||
@@ -1406,19 +1416,20 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
blkno--)
|
||||
{
|
||||
/*
|
||||
* Forget fraged_pages pages at or after this one; they're no longer
|
||||
* useful as move targets, since we only want to move down. Note
|
||||
* that since we stop the outer loop at last_move_dest_block, pages
|
||||
* removed here cannot have had anything moved onto them already.
|
||||
* Forget fraged_pages pages at or after this one; they're no
|
||||
* longer useful as move targets, since we only want to move down.
|
||||
* Note that since we stop the outer loop at last_move_dest_block,
|
||||
* pages removed here cannot have had anything moved onto them
|
||||
* already.
|
||||
*
|
||||
* Also note that we don't change the stored fraged_pages list,
|
||||
* only our local variable num_fraged_pages; so the forgotten pages
|
||||
* are still available to be loaded into the free space map later.
|
||||
* Also note that we don't change the stored fraged_pages list, only
|
||||
* our local variable num_fraged_pages; so the forgotten pages are
|
||||
* still available to be loaded into the free space map later.
|
||||
*/
|
||||
while (num_fraged_pages > 0 &&
|
||||
fraged_pages->pagedesc[num_fraged_pages-1]->blkno >= blkno)
|
||||
fraged_pages->pagedesc[num_fraged_pages - 1]->blkno >= blkno)
|
||||
{
|
||||
Assert(fraged_pages->pagedesc[num_fraged_pages-1]->offsets_used == 0);
|
||||
Assert(fraged_pages->pagedesc[num_fraged_pages - 1]->offsets_used == 0);
|
||||
--num_fraged_pages;
|
||||
}
|
||||
|
||||
@@ -1534,7 +1545,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
* tuples to another places.
|
||||
*/
|
||||
if ((tuple.t_data->t_infomask & HEAP_UPDATED &&
|
||||
!TransactionIdPrecedes(tuple.t_data->t_xmin, OldestXmin)) ||
|
||||
!TransactionIdPrecedes(tuple.t_data->t_xmin, OldestXmin)) ||
|
||||
(!(tuple.t_data->t_infomask & HEAP_XMAX_INVALID) &&
|
||||
!(ItemPointerEquals(&(tuple.t_self),
|
||||
&(tuple.t_data->t_ctid)))))
|
||||
@@ -1581,7 +1592,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
ItemPointerGetOffsetNumber(&Ctid));
|
||||
if (!ItemIdIsUsed(Citemid))
|
||||
{
|
||||
|
||||
/*
|
||||
* This means that in the middle of chain there
|
||||
* was tuple updated by older (than OldestXmin)
|
||||
@@ -1652,7 +1662,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
/* All done ? */
|
||||
if (!(tp.t_data->t_infomask & HEAP_UPDATED) ||
|
||||
TransactionIdPrecedes(tp.t_data->t_xmin, OldestXmin))
|
||||
TransactionIdPrecedes(tp.t_data->t_xmin, OldestXmin))
|
||||
break;
|
||||
|
||||
/* Well, try to find tuple with old row version */
|
||||
@@ -2109,9 +2119,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
/*
|
||||
* We are not going to move any more tuples across pages, but we still
|
||||
* need to apply vacuum_page to compact free space in the remaining
|
||||
* pages in vacuum_pages list. Note that some of these pages may also
|
||||
* be in the fraged_pages list, and may have had tuples moved onto them;
|
||||
* if so, we already did vacuum_page and needn't do it again.
|
||||
* pages in vacuum_pages list. Note that some of these pages may also
|
||||
* be in the fraged_pages list, and may have had tuples moved onto
|
||||
* them; if so, we already did vacuum_page and needn't do it again.
|
||||
*/
|
||||
for (i = 0, curpage = vacuum_pages->pagedesc;
|
||||
i < vacuumed_pages;
|
||||
@@ -2132,15 +2142,15 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
}
|
||||
|
||||
/*
|
||||
* Now scan all the pages that we moved tuples onto and update
|
||||
* tuple status bits. This is not really necessary, but will save time
|
||||
* for future transactions examining these tuples.
|
||||
* Now scan all the pages that we moved tuples onto and update tuple
|
||||
* status bits. This is not really necessary, but will save time for
|
||||
* future transactions examining these tuples.
|
||||
*
|
||||
* XXX Notice that this code fails to clear HEAP_MOVED_OFF tuples from
|
||||
* pages that were move source pages but not move dest pages. One also
|
||||
* wonders whether it wouldn't be better to skip this step and let the
|
||||
* tuple status updates happen someplace that's not holding an exclusive
|
||||
* lock on the relation.
|
||||
* pages that were move source pages but not move dest pages. One
|
||||
* also wonders whether it wouldn't be better to skip this step and
|
||||
* let the tuple status updates happen someplace that's not holding an
|
||||
* exclusive lock on the relation.
|
||||
*/
|
||||
checked_moved = 0;
|
||||
for (i = 0, curpage = fraged_pages->pagedesc;
|
||||
@@ -2226,7 +2236,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
if (vacpage->blkno == (blkno - 1) &&
|
||||
vacpage->offsets_free > 0)
|
||||
{
|
||||
OffsetNumber unbuf[BLCKSZ/sizeof(OffsetNumber)];
|
||||
OffsetNumber unbuf[BLCKSZ / sizeof(OffsetNumber)];
|
||||
OffsetNumber *unused = unbuf;
|
||||
int uncnt;
|
||||
|
||||
@@ -2297,7 +2307,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
if (blkno < nblocks)
|
||||
{
|
||||
blkno = smgrtruncate(DEFAULT_SMGR, onerel, blkno);
|
||||
onerel->rd_nblocks = blkno; /* update relcache immediately */
|
||||
onerel->rd_nblocks = blkno; /* update relcache immediately */
|
||||
onerel->rd_targblock = InvalidBlockNumber;
|
||||
vacrelstats->rel_pages = blkno; /* set new number of blocks */
|
||||
}
|
||||
@@ -2323,7 +2333,7 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
{
|
||||
Buffer buf;
|
||||
VacPage *vacpage;
|
||||
BlockNumber relblocks;
|
||||
BlockNumber relblocks;
|
||||
int nblocks;
|
||||
int i;
|
||||
|
||||
@@ -2363,7 +2373,7 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
RelationGetRelationName(onerel),
|
||||
vacrelstats->rel_pages, relblocks);
|
||||
relblocks = smgrtruncate(DEFAULT_SMGR, onerel, relblocks);
|
||||
onerel->rd_nblocks = relblocks; /* update relcache immediately */
|
||||
onerel->rd_nblocks = relblocks; /* update relcache immediately */
|
||||
onerel->rd_targblock = InvalidBlockNumber;
|
||||
vacrelstats->rel_pages = relblocks; /* set new number of
|
||||
* blocks */
|
||||
@@ -2377,7 +2387,7 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
static void
|
||||
vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
|
||||
{
|
||||
OffsetNumber unbuf[BLCKSZ/sizeof(OffsetNumber)];
|
||||
OffsetNumber unbuf[BLCKSZ / sizeof(OffsetNumber)];
|
||||
OffsetNumber *unused = unbuf;
|
||||
int uncnt;
|
||||
Page page = BufferGetPage(buffer);
|
||||
@@ -2420,8 +2430,8 @@ scan_index(Relation indrel, double num_tuples)
|
||||
|
||||
/*
|
||||
* Even though we're not planning to delete anything, use the
|
||||
* ambulkdelete call, so that the scan happens within the index AM
|
||||
* for more speed.
|
||||
* ambulkdelete call, so that the scan happens within the index AM for
|
||||
* more speed.
|
||||
*/
|
||||
stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
|
||||
|
||||
@@ -2439,13 +2449,13 @@ scan_index(Relation indrel, double num_tuples)
|
||||
vac_show_rusage(&ru0));
|
||||
|
||||
/*
|
||||
* Check for tuple count mismatch. If the index is partial, then
|
||||
* it's OK for it to have fewer tuples than the heap; else we got trouble.
|
||||
* Check for tuple count mismatch. If the index is partial, then it's
|
||||
* OK for it to have fewer tuples than the heap; else we got trouble.
|
||||
*/
|
||||
if (stats->num_index_tuples != num_tuples)
|
||||
{
|
||||
if (stats->num_index_tuples > num_tuples ||
|
||||
! vac_is_partial_index(indrel))
|
||||
!vac_is_partial_index(indrel))
|
||||
elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
|
||||
\n\tRecreate the index.",
|
||||
RelationGetRelationName(indrel),
|
||||
@@ -2493,13 +2503,13 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
|
||||
vac_show_rusage(&ru0));
|
||||
|
||||
/*
|
||||
* Check for tuple count mismatch. If the index is partial, then
|
||||
* it's OK for it to have fewer tuples than the heap; else we got trouble.
|
||||
* Check for tuple count mismatch. If the index is partial, then it's
|
||||
* OK for it to have fewer tuples than the heap; else we got trouble.
|
||||
*/
|
||||
if (stats->num_index_tuples != num_tuples + keep_tuples)
|
||||
{
|
||||
if (stats->num_index_tuples > num_tuples + keep_tuples ||
|
||||
! vac_is_partial_index(indrel))
|
||||
!vac_is_partial_index(indrel))
|
||||
elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\
|
||||
\n\tRecreate the index.",
|
||||
RelationGetRelationName(indrel),
|
||||
@@ -2519,7 +2529,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel,
|
||||
static bool
|
||||
tid_reaped(ItemPointer itemptr, void *state)
|
||||
{
|
||||
VacPageList vacpagelist = (VacPageList) state;
|
||||
VacPageList vacpagelist = (VacPageList) state;
|
||||
OffsetNumber ioffno;
|
||||
OffsetNumber *voff;
|
||||
VacPage vp,
|
||||
@@ -2591,9 +2601,11 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages,
|
||||
{
|
||||
pages[i] = fraged_pages->pagedesc[i]->blkno;
|
||||
spaceAvail[i] = fraged_pages->pagedesc[i]->free;
|
||||
|
||||
/*
|
||||
* fraged_pages may contain entries for pages that we later decided
|
||||
* to truncate from the relation; don't enter them into the map!
|
||||
* fraged_pages may contain entries for pages that we later
|
||||
* decided to truncate from the relation; don't enter them into
|
||||
* the map!
|
||||
*/
|
||||
if (pages[i] >= rel_pages)
|
||||
{
|
||||
@@ -2617,7 +2629,7 @@ copy_vac_page(VacPage vacpage)
|
||||
|
||||
/* allocate a VacPageData entry */
|
||||
newvacpage = (VacPage) palloc(sizeof(VacPageData) +
|
||||
vacpage->offsets_free * sizeof(OffsetNumber));
|
||||
vacpage->offsets_free * sizeof(OffsetNumber));
|
||||
|
||||
/* fill it in */
|
||||
if (vacpage->offsets_free > 0)
|
||||
@@ -2661,7 +2673,7 @@ vpage_insert(VacPageList vacpagelist, VacPage vpnew)
|
||||
/*
|
||||
* vac_bsearch: just like standard C library routine bsearch(),
|
||||
* except that we first test to see whether the target key is outside
|
||||
* the range of the table entries. This case is handled relatively slowly
|
||||
* the range of the table entries. This case is handled relatively slowly
|
||||
* by the normal binary search algorithm (ie, no faster than any other key)
|
||||
* but it occurs often enough in VACUUM to be worth optimizing.
|
||||
*/
|
||||
@@ -2802,14 +2814,15 @@ vac_is_partial_index(Relation indrel)
|
||||
Form_pg_index indexStruct;
|
||||
|
||||
/*
|
||||
* If the index's AM doesn't support nulls, it's partial for our purposes
|
||||
* If the index's AM doesn't support nulls, it's partial for our
|
||||
* purposes
|
||||
*/
|
||||
if (! indrel->rd_am->amindexnulls)
|
||||
if (!indrel->rd_am->amindexnulls)
|
||||
return true;
|
||||
|
||||
/* Otherwise, look to see if there's a partial-index predicate */
|
||||
cachetuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(RelationGetRelid(indrel)),
|
||||
ObjectIdGetDatum(RelationGetRelid(indrel)),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(cachetuple))
|
||||
elog(ERROR, "vac_is_partial_index: index %u not found",
|
||||
@@ -2888,9 +2901,9 @@ vac_show_rusage(VacRUsage *ru0)
|
||||
snprintf(result, sizeof(result),
|
||||
"CPU %d.%02ds/%d.%02du sec elapsed %d.%02d sec.",
|
||||
(int) (ru1.ru.ru_stime.tv_sec - ru0->ru.ru_stime.tv_sec),
|
||||
(int) (ru1.ru.ru_stime.tv_usec - ru0->ru.ru_stime.tv_usec) / 10000,
|
||||
(int) (ru1.ru.ru_stime.tv_usec - ru0->ru.ru_stime.tv_usec) / 10000,
|
||||
(int) (ru1.ru.ru_utime.tv_sec - ru0->ru.ru_utime.tv_sec),
|
||||
(int) (ru1.ru.ru_utime.tv_usec - ru0->ru.ru_utime.tv_usec) / 10000,
|
||||
(int) (ru1.ru.ru_utime.tv_usec - ru0->ru.ru_utime.tv_usec) / 10000,
|
||||
(int) (ru1.tv.tv_sec - ru0->tv.tv_sec),
|
||||
(int) (ru1.tv.tv_usec - ru0->tv.tv_usec) / 10000);
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
*
|
||||
* We can limit the storage for page free space to MaxFSMPages entries,
|
||||
* since that's the most the free space map will be willing to remember
|
||||
* anyway. If the relation has fewer than that many pages with free space,
|
||||
* life is easy: just build an array of per-page info. If it has more,
|
||||
* anyway. If the relation has fewer than that many pages with free space,
|
||||
* life is easy: just build an array of per-page info. If it has more,
|
||||
* we store the free space info as a heap ordered by amount of free space,
|
||||
* so that we can discard the pages with least free space to ensure we never
|
||||
* have more than MaxFSMPages entries in all. The surviving page entries
|
||||
@@ -31,7 +31,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.8 2001/09/29 04:02:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.9 2001/10/25 05:49:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -51,7 +51,7 @@
|
||||
* Space/time tradeoff parameters: do these need to be user-tunable?
|
||||
*
|
||||
* A page with less than PAGE_SPACE_THRESHOLD free space will be forgotten
|
||||
* immediately, and not even passed to the free space map. Removing the
|
||||
* immediately, and not even passed to the free space map. Removing the
|
||||
* uselessly small entries early saves cycles, and in particular reduces
|
||||
* the amount of time we spend holding the FSM lock when we finally call
|
||||
* MultiRecordFreeSpace. Since the FSM will ignore pages below its own
|
||||
@@ -74,21 +74,21 @@
|
||||
typedef struct LVRelStats
|
||||
{
|
||||
/* Overall statistics about rel */
|
||||
BlockNumber rel_pages;
|
||||
BlockNumber rel_pages;
|
||||
double rel_tuples;
|
||||
BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
|
||||
BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
|
||||
/* List of TIDs of tuples we intend to delete */
|
||||
/* NB: this list is ordered by TID address */
|
||||
int num_dead_tuples; /* current # of entries */
|
||||
int max_dead_tuples; /* # slots allocated in array */
|
||||
ItemPointer dead_tuples; /* array of ItemPointerData */
|
||||
int num_dead_tuples; /* current # of entries */
|
||||
int max_dead_tuples; /* # slots allocated in array */
|
||||
ItemPointer dead_tuples; /* array of ItemPointerData */
|
||||
/* Array or heap of per-page info about free space */
|
||||
/* We use a simple array until it fills up, then convert to heap */
|
||||
bool fs_is_heap; /* are we using heap organization? */
|
||||
int num_free_pages; /* current # of entries */
|
||||
int max_free_pages; /* # slots allocated in arrays */
|
||||
BlockNumber *free_pages; /* array or heap of block numbers */
|
||||
Size *free_spaceavail; /* array or heap of available space */
|
||||
bool fs_is_heap; /* are we using heap organization? */
|
||||
int num_free_pages; /* current # of entries */
|
||||
int max_free_pages; /* # slots allocated in arrays */
|
||||
BlockNumber *free_pages; /* array or heap of block numbers */
|
||||
Size *free_spaceavail; /* array or heap of available space */
|
||||
} LVRelStats;
|
||||
|
||||
|
||||
@@ -100,20 +100,20 @@ static TransactionId FreezeLimit;
|
||||
|
||||
/* non-export function prototypes */
|
||||
static void lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
Relation *Irel, int nindexes);
|
||||
Relation *Irel, int nindexes);
|
||||
static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
|
||||
static void lazy_scan_index(Relation indrel, LVRelStats *vacrelstats);
|
||||
static void lazy_vacuum_index(Relation indrel, LVRelStats *vacrelstats);
|
||||
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
|
||||
int tupindex, LVRelStats *vacrelstats);
|
||||
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
|
||||
int tupindex, LVRelStats *vacrelstats);
|
||||
static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats);
|
||||
static BlockNumber count_nondeletable_pages(Relation onerel,
|
||||
LVRelStats *vacrelstats);
|
||||
LVRelStats *vacrelstats);
|
||||
static void lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks);
|
||||
static void lazy_record_dead_tuple(LVRelStats *vacrelstats,
|
||||
ItemPointer itemptr);
|
||||
ItemPointer itemptr);
|
||||
static void lazy_record_free_space(LVRelStats *vacrelstats,
|
||||
BlockNumber page, Size avail);
|
||||
BlockNumber page, Size avail);
|
||||
static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
|
||||
static bool dummy_tid_reaped(ItemPointer itemptr, void *state);
|
||||
static void lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats);
|
||||
@@ -136,7 +136,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
||||
Relation *Irel;
|
||||
int nindexes;
|
||||
bool hasindex;
|
||||
BlockNumber possibly_freeable;
|
||||
BlockNumber possibly_freeable;
|
||||
|
||||
/* initialize */
|
||||
if (vacstmt->verbose)
|
||||
@@ -163,8 +163,8 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
||||
/*
|
||||
* Optionally truncate the relation.
|
||||
*
|
||||
* Don't even think about it unless we have a shot at releasing a
|
||||
* goodly number of pages. Otherwise, the time taken isn't worth it.
|
||||
* Don't even think about it unless we have a shot at releasing a goodly
|
||||
* number of pages. Otherwise, the time taken isn't worth it.
|
||||
*/
|
||||
possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages;
|
||||
if (possibly_freeable > vacrelstats->rel_pages / REL_TRUNCATE_FRACTION)
|
||||
@@ -195,7 +195,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
blkno;
|
||||
HeapTupleData tuple;
|
||||
char *relname;
|
||||
BlockNumber empty_pages,
|
||||
BlockNumber empty_pages,
|
||||
changed_pages;
|
||||
double num_tuples,
|
||||
tups_vacuumed,
|
||||
@@ -231,8 +231,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
int prev_dead_count;
|
||||
|
||||
/*
|
||||
* If we are close to overrunning the available space for dead-tuple
|
||||
* TIDs, pause and do a cycle of vacuuming before we tackle this page.
|
||||
* If we are close to overrunning the available space for
|
||||
* dead-tuple TIDs, pause and do a cycle of vacuuming before we
|
||||
* tackle this page.
|
||||
*/
|
||||
if ((vacrelstats->max_dead_tuples - vacrelstats->num_dead_tuples) < MAX_TUPLES_PER_PAGE &&
|
||||
vacrelstats->num_dead_tuples > 0)
|
||||
@@ -312,17 +313,18 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
break;
|
||||
case HEAPTUPLE_LIVE:
|
||||
|
||||
/*
|
||||
* Tuple is good. Consider whether to replace its xmin
|
||||
* value with FrozenTransactionId.
|
||||
* Tuple is good. Consider whether to replace its
|
||||
* xmin value with FrozenTransactionId.
|
||||
*
|
||||
* NB: Since we hold only a shared buffer lock here,
|
||||
* we are assuming that TransactionId read/write
|
||||
* is atomic. This is not the only place that makes
|
||||
* such an assumption. It'd be possible to avoid the
|
||||
* NB: Since we hold only a shared buffer lock here, we
|
||||
* are assuming that TransactionId read/write is
|
||||
* atomic. This is not the only place that makes such
|
||||
* an assumption. It'd be possible to avoid the
|
||||
* assumption by momentarily acquiring exclusive lock,
|
||||
* but for the moment I see no need to.
|
||||
*/
|
||||
@@ -337,9 +339,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
}
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
|
||||
/*
|
||||
* If tuple is recently deleted then we must not remove
|
||||
* it from relation.
|
||||
* If tuple is recently deleted then we must not
|
||||
* remove it from relation.
|
||||
*/
|
||||
nkeep += 1;
|
||||
break;
|
||||
@@ -376,11 +379,11 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
num_tuples += 1;
|
||||
hastup = true;
|
||||
}
|
||||
} /* scan along page */
|
||||
} /* scan along page */
|
||||
|
||||
/*
|
||||
* If we remembered any tuples for deletion, then the page will
|
||||
* be visited again by lazy_vacuum_heap, which will compute and
|
||||
* If we remembered any tuples for deletion, then the page will be
|
||||
* visited again by lazy_vacuum_heap, which will compute and
|
||||
* record its post-compaction free space. If not, then we're done
|
||||
* with this page, so remember its free space as-is.
|
||||
*/
|
||||
@@ -418,7 +421,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
|
||||
/* Remove tuples from heap */
|
||||
lazy_vacuum_heap(onerel, vacrelstats);
|
||||
}
|
||||
else if (! did_vacuum_index)
|
||||
else if (!did_vacuum_index)
|
||||
{
|
||||
/* Scan indexes just to update pg_class statistics about them */
|
||||
for (i = 0; i < nindexes; i++)
|
||||
@@ -457,7 +460,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
|
||||
tupindex = 0;
|
||||
while (tupindex < vacrelstats->num_dead_tuples)
|
||||
{
|
||||
BlockNumber tblk;
|
||||
BlockNumber tblk;
|
||||
Buffer buf;
|
||||
Page page;
|
||||
|
||||
@@ -493,7 +496,7 @@ static int
|
||||
lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
|
||||
int tupindex, LVRelStats *vacrelstats)
|
||||
{
|
||||
OffsetNumber unbuf[BLCKSZ/sizeof(OffsetNumber)];
|
||||
OffsetNumber unbuf[BLCKSZ / sizeof(OffsetNumber)];
|
||||
OffsetNumber *unused = unbuf;
|
||||
int uncnt;
|
||||
Page page = BufferGetPage(buffer);
|
||||
@@ -502,8 +505,8 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
|
||||
START_CRIT_SECTION();
|
||||
for (; tupindex < vacrelstats->num_dead_tuples; tupindex++)
|
||||
{
|
||||
BlockNumber tblk;
|
||||
OffsetNumber toff;
|
||||
BlockNumber tblk;
|
||||
OffsetNumber toff;
|
||||
|
||||
tblk = ItemPointerGetBlockNumber(&vacrelstats->dead_tuples[tupindex]);
|
||||
if (tblk != blkno)
|
||||
@@ -542,10 +545,10 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
|
||||
vac_init_rusage(&ru0);
|
||||
|
||||
/*
|
||||
* If the index is not partial, skip the scan, and just assume it
|
||||
* has the same number of tuples as the heap.
|
||||
* If the index is not partial, skip the scan, and just assume it has
|
||||
* the same number of tuples as the heap.
|
||||
*/
|
||||
if (! vac_is_partial_index(indrel))
|
||||
if (!vac_is_partial_index(indrel))
|
||||
{
|
||||
vac_update_relstats(RelationGetRelid(indrel),
|
||||
RelationGetNumberOfBlocks(indrel),
|
||||
@@ -555,23 +558,23 @@ lazy_scan_index(Relation indrel, LVRelStats *vacrelstats)
|
||||
}
|
||||
|
||||
/*
|
||||
* If index is unsafe for concurrent access, must lock it;
|
||||
* but a shared lock should be sufficient.
|
||||
* If index is unsafe for concurrent access, must lock it; but a
|
||||
* shared lock should be sufficient.
|
||||
*/
|
||||
if (! indrel->rd_am->amconcurrent)
|
||||
if (!indrel->rd_am->amconcurrent)
|
||||
LockRelation(indrel, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Even though we're not planning to delete anything, use the
|
||||
* ambulkdelete call, so that the scan happens within the index AM
|
||||
* for more speed.
|
||||
* ambulkdelete call, so that the scan happens within the index AM for
|
||||
* more speed.
|
||||
*/
|
||||
stats = index_bulk_delete(indrel, dummy_tid_reaped, NULL);
|
||||
|
||||
/*
|
||||
* Release lock acquired above.
|
||||
*/
|
||||
if (! indrel->rd_am->amconcurrent)
|
||||
if (!indrel->rd_am->amconcurrent)
|
||||
UnlockRelation(indrel, AccessShareLock);
|
||||
|
||||
if (!stats)
|
||||
@@ -610,7 +613,7 @@ lazy_vacuum_index(Relation indrel, LVRelStats *vacrelstats)
|
||||
/*
|
||||
* If index is unsafe for concurrent access, must lock it.
|
||||
*/
|
||||
if (! indrel->rd_am->amconcurrent)
|
||||
if (!indrel->rd_am->amconcurrent)
|
||||
LockRelation(indrel, AccessExclusiveLock);
|
||||
|
||||
/* Do bulk deletion */
|
||||
@@ -619,7 +622,7 @@ lazy_vacuum_index(Relation indrel, LVRelStats *vacrelstats)
|
||||
/*
|
||||
* Release lock acquired above.
|
||||
*/
|
||||
if (! indrel->rd_am->amconcurrent)
|
||||
if (!indrel->rd_am->amconcurrent)
|
||||
UnlockRelation(indrel, AccessExclusiveLock);
|
||||
|
||||
/* now update statistics in pg_class */
|
||||
@@ -644,8 +647,8 @@ lazy_vacuum_index(Relation indrel, LVRelStats *vacrelstats)
|
||||
static void
|
||||
lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
|
||||
{
|
||||
BlockNumber old_rel_pages = vacrelstats->rel_pages;
|
||||
BlockNumber new_rel_pages;
|
||||
BlockNumber old_rel_pages = vacrelstats->rel_pages;
|
||||
BlockNumber new_rel_pages;
|
||||
BlockNumber *pages;
|
||||
Size *spaceavail;
|
||||
int n;
|
||||
@@ -656,12 +659,13 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
|
||||
vac_init_rusage(&ru0);
|
||||
|
||||
/*
|
||||
* We need full exclusive lock on the relation in order to do truncation.
|
||||
* If we can't get it, give up rather than waiting --- we don't want
|
||||
* to block other backends, and we don't want to deadlock (which is
|
||||
* quite possible considering we already hold a lower-grade lock).
|
||||
* We need full exclusive lock on the relation in order to do
|
||||
* truncation. If we can't get it, give up rather than waiting --- we
|
||||
* don't want to block other backends, and we don't want to deadlock
|
||||
* (which is quite possible considering we already hold a lower-grade
|
||||
* lock).
|
||||
*/
|
||||
if (! ConditionalLockRelation(onerel, AccessExclusiveLock))
|
||||
if (!ConditionalLockRelation(onerel, AccessExclusiveLock))
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -680,9 +684,9 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
|
||||
|
||||
/*
|
||||
* Scan backwards from the end to verify that the end pages actually
|
||||
* contain nothing we need to keep. This is *necessary*, not optional,
|
||||
* because other backends could have added tuples to these pages whilst
|
||||
* we were vacuuming.
|
||||
* contain nothing we need to keep. This is *necessary*, not
|
||||
* optional, because other backends could have added tuples to these
|
||||
* pages whilst we were vacuuming.
|
||||
*/
|
||||
new_rel_pages = count_nondeletable_pages(onerel, vacrelstats);
|
||||
|
||||
@@ -710,9 +714,10 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
|
||||
* Do the physical truncation.
|
||||
*/
|
||||
new_rel_pages = smgrtruncate(DEFAULT_SMGR, onerel, new_rel_pages);
|
||||
onerel->rd_nblocks = new_rel_pages; /* update relcache immediately */
|
||||
onerel->rd_nblocks = new_rel_pages; /* update relcache immediately */
|
||||
onerel->rd_targblock = InvalidBlockNumber;
|
||||
vacrelstats->rel_pages = new_rel_pages; /* save new number of blocks */
|
||||
vacrelstats->rel_pages = new_rel_pages; /* save new number of
|
||||
* blocks */
|
||||
|
||||
/*
|
||||
* Drop free-space info for removed blocks; these must not get entered
|
||||
@@ -808,15 +813,16 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
|
||||
switch (HeapTupleSatisfiesVacuum(tuple.t_data, OldestXmin))
|
||||
{
|
||||
case HEAPTUPLE_DEAD:
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
tupgone = true; /* we can delete the tuple */
|
||||
break;
|
||||
case HEAPTUPLE_LIVE:
|
||||
/* Shouldn't be necessary to re-freeze anything */
|
||||
break;
|
||||
case HEAPTUPLE_RECENTLY_DEAD:
|
||||
|
||||
/*
|
||||
* If tuple is recently deleted then we must not remove
|
||||
* it from relation.
|
||||
* If tuple is recently deleted then we must not
|
||||
* remove it from relation.
|
||||
*/
|
||||
break;
|
||||
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
||||
@@ -839,7 +845,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
|
||||
hastup = true;
|
||||
break; /* can stop scanning */
|
||||
}
|
||||
} /* scan along page */
|
||||
} /* scan along page */
|
||||
|
||||
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
||||
|
||||
@@ -855,8 +861,8 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
|
||||
|
||||
/*
|
||||
* If we fall out of the loop, all the previously-thought-to-be-empty
|
||||
* pages really are; we need not bother to look at the last known-nonempty
|
||||
* page.
|
||||
* pages really are; we need not bother to look at the last
|
||||
* known-nonempty page.
|
||||
*/
|
||||
return vacrelstats->nonempty_pages;
|
||||
}
|
||||
@@ -907,9 +913,9 @@ lazy_record_dead_tuple(LVRelStats *vacrelstats,
|
||||
ItemPointer itemptr)
|
||||
{
|
||||
/*
|
||||
* The array shouldn't overflow under normal behavior,
|
||||
* but perhaps it could if we are given a really small VacuumMem.
|
||||
* In that case, just forget the last few tuples.
|
||||
* The array shouldn't overflow under normal behavior, but perhaps it
|
||||
* could if we are given a really small VacuumMem. In that case, just
|
||||
* forget the last few tuples.
|
||||
*/
|
||||
if (vacrelstats->num_dead_tuples < vacrelstats->max_dead_tuples)
|
||||
{
|
||||
@@ -960,29 +966,29 @@ lazy_record_free_space(LVRelStats *vacrelstats,
|
||||
*/
|
||||
|
||||
/* If we haven't yet converted the array to heap organization, do it */
|
||||
if (! vacrelstats->fs_is_heap)
|
||||
if (!vacrelstats->fs_is_heap)
|
||||
{
|
||||
/*
|
||||
* Scan backwards through the array, "sift-up" each value into its
|
||||
* correct position. We can start the scan at n/2-1 since each entry
|
||||
* above that position has no children to worry about.
|
||||
* correct position. We can start the scan at n/2-1 since each
|
||||
* entry above that position has no children to worry about.
|
||||
*/
|
||||
int l = n / 2;
|
||||
int l = n / 2;
|
||||
|
||||
while (--l >= 0)
|
||||
{
|
||||
BlockNumber R = pages[l];
|
||||
BlockNumber R = pages[l];
|
||||
Size K = spaceavail[l];
|
||||
int i; /* i is where the "hole" is */
|
||||
|
||||
i = l;
|
||||
for (;;)
|
||||
{
|
||||
int j = 2*i + 1;
|
||||
int j = 2 * i + 1;
|
||||
|
||||
if (j >= n)
|
||||
break;
|
||||
if (j+1 < n && spaceavail[j] > spaceavail[j+1])
|
||||
if (j + 1 < n && spaceavail[j] > spaceavail[j + 1])
|
||||
j++;
|
||||
if (K <= spaceavail[j])
|
||||
break;
|
||||
@@ -1001,20 +1007,20 @@ lazy_record_free_space(LVRelStats *vacrelstats,
|
||||
if (avail > spaceavail[0])
|
||||
{
|
||||
/*
|
||||
* Notionally, we replace the zero'th entry with the new data,
|
||||
* and then sift-up to maintain the heap property. Physically,
|
||||
* the new data doesn't get stored into the arrays until we find
|
||||
* the right location for it.
|
||||
* Notionally, we replace the zero'th entry with the new data, and
|
||||
* then sift-up to maintain the heap property. Physically, the
|
||||
* new data doesn't get stored into the arrays until we find the
|
||||
* right location for it.
|
||||
*/
|
||||
int i = 0; /* i is where the "hole" is */
|
||||
int i = 0; /* i is where the "hole" is */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int j = 2*i + 1;
|
||||
int j = 2 * i + 1;
|
||||
|
||||
if (j >= n)
|
||||
break;
|
||||
if (j+1 < n && spaceavail[j] > spaceavail[j+1])
|
||||
if (j + 1 < n && spaceavail[j] > spaceavail[j + 1])
|
||||
j++;
|
||||
if (avail <= spaceavail[j])
|
||||
break;
|
||||
@@ -1038,7 +1044,7 @@ static bool
|
||||
lazy_tid_reaped(ItemPointer itemptr, void *state)
|
||||
{
|
||||
LVRelStats *vacrelstats = (LVRelStats *) state;
|
||||
ItemPointer res;
|
||||
ItemPointer res;
|
||||
|
||||
res = (ItemPointer) bsearch((void *) itemptr,
|
||||
(void *) vacrelstats->dead_tuples,
|
||||
@@ -1066,9 +1072,9 @@ static void
|
||||
lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats)
|
||||
{
|
||||
/*
|
||||
* Since MultiRecordFreeSpace doesn't currently impose any restrictions
|
||||
* on the ordering of the input, we can just pass it the arrays as-is,
|
||||
* whether they are in heap or linear order.
|
||||
* Since MultiRecordFreeSpace doesn't currently impose any
|
||||
* restrictions on the ordering of the input, we can just pass it the
|
||||
* arrays as-is, whether they are in heap or linear order.
|
||||
*/
|
||||
MultiRecordFreeSpace(&onerel->rd_node,
|
||||
0, MaxBlockNumber,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.54 2001/10/18 17:30:14 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.55 2001/10/25 05:49:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -334,9 +334,10 @@ set_default_datestyle(void)
|
||||
*/
|
||||
DBDate = strdup(DBDate);
|
||||
|
||||
/* Parse desired setting into DateStyle/EuroDates
|
||||
* Use parse_datestyle_internal() to avoid any palloc() issues per above
|
||||
* - thomas 2001-10-15
|
||||
/*
|
||||
* Parse desired setting into DateStyle/EuroDates Use
|
||||
* parse_datestyle_internal() to avoid any palloc() issues per above -
|
||||
* thomas 2001-10-15
|
||||
*/
|
||||
parse_datestyle_internal(DBDate);
|
||||
|
||||
@@ -380,7 +381,7 @@ parse_timezone(List *args)
|
||||
|
||||
foreach(arg, args)
|
||||
{
|
||||
A_Const *p;
|
||||
A_Const *p;
|
||||
|
||||
Assert(IsA(arg, List));
|
||||
p = lfirst(arg);
|
||||
@@ -394,24 +395,28 @@ parse_timezone(List *args)
|
||||
Interval *interval;
|
||||
|
||||
interval = DatumGetIntervalP(DirectFunctionCall3(interval_in,
|
||||
CStringGetDatum(p->val.val.str),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
Int32GetDatum(-1)));
|
||||
CStringGetDatum(p->val.val.str),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
Int32GetDatum(-1)));
|
||||
if (interval->month != 0)
|
||||
elog(ERROR, "SET TIME ZONE illegal INTERVAL; month not allowed");
|
||||
CTimeZone = interval->time;
|
||||
}
|
||||
else if (strcmp(type->name, "float8") == 0)
|
||||
{
|
||||
float8 time;
|
||||
float8 time;
|
||||
|
||||
time = DatumGetFloat8(DirectFunctionCall1(float8in, CStringGetDatum(p->val.val.str)));
|
||||
CTimeZone = time * 3600;
|
||||
}
|
||||
/* We do not actually generate an integer constant in gram.y so this is not used... */
|
||||
|
||||
/*
|
||||
* We do not actually generate an integer constant in gram.y
|
||||
* so this is not used...
|
||||
*/
|
||||
else if (strcmp(type->name, "int4") == 0)
|
||||
{
|
||||
int32 time;
|
||||
int32 time;
|
||||
|
||||
time = p->val.val.ival;
|
||||
CTimeZone = time * 3600;
|
||||
@@ -462,11 +467,11 @@ parse_timezone(List *args)
|
||||
static bool
|
||||
show_timezone(void)
|
||||
{
|
||||
char *tzn;
|
||||
char *tzn;
|
||||
|
||||
if (HasCTZSet)
|
||||
{
|
||||
Interval interval;
|
||||
Interval interval;
|
||||
|
||||
interval.month = 0;
|
||||
interval.time = CTimeZone;
|
||||
@@ -474,9 +479,7 @@ show_timezone(void)
|
||||
tzn = DatumGetCString(DirectFunctionCall1(interval_out, IntervalPGetDatum(&interval)));
|
||||
}
|
||||
else
|
||||
{
|
||||
tzn = getenv("TZ");
|
||||
}
|
||||
|
||||
if (tzn != NULL)
|
||||
elog(NOTICE, "Time zone is '%s'", tzn);
|
||||
@@ -500,9 +503,7 @@ static bool
|
||||
reset_timezone(void)
|
||||
{
|
||||
if (HasCTZSet)
|
||||
{
|
||||
HasCTZSet = false;
|
||||
}
|
||||
|
||||
/* no time zone has been set in this session? */
|
||||
else if (defaultTZ == NULL)
|
||||
@@ -545,7 +546,7 @@ reset_timezone(void)
|
||||
static bool
|
||||
parse_XactIsoLevel(List *args)
|
||||
{
|
||||
char *value;
|
||||
char *value;
|
||||
|
||||
if (args == NULL)
|
||||
return reset_XactIsoLevel();
|
||||
@@ -603,8 +604,8 @@ reset_XactIsoLevel(void)
|
||||
static bool
|
||||
parse_random_seed(List *args)
|
||||
{
|
||||
char *value;
|
||||
double seed = 0;
|
||||
char *value;
|
||||
double seed = 0;
|
||||
|
||||
if (args == NULL)
|
||||
return reset_random_seed();
|
||||
@@ -648,9 +649,10 @@ reset_random_seed(void)
|
||||
static bool
|
||||
parse_client_encoding(List *args)
|
||||
{
|
||||
char *value;
|
||||
char *value;
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
int encoding;
|
||||
int encoding;
|
||||
#endif
|
||||
|
||||
if (args == NULL)
|
||||
@@ -679,7 +681,7 @@ parse_client_encoding(List *args)
|
||||
}
|
||||
#else
|
||||
if (value &&
|
||||
strcasecmp(value, pg_get_client_encoding_name()) != 0)
|
||||
strcasecmp(value, pg_get_client_encoding_name()) != 0)
|
||||
elog(ERROR, "Client encoding %s is not supported", value);
|
||||
#endif
|
||||
return TRUE;
|
||||
@@ -766,14 +768,14 @@ SetPGVariable(const char *name, List *args)
|
||||
parse_random_seed(args);
|
||||
else
|
||||
{
|
||||
/* For routines defined somewhere else,
|
||||
* go ahead and extract the string argument
|
||||
* to match the original interface definition.
|
||||
/*
|
||||
* For routines defined somewhere else, go ahead and extract the
|
||||
* string argument to match the original interface definition.
|
||||
* Later, we can change this code too...
|
||||
*/
|
||||
char *value;
|
||||
char *value;
|
||||
|
||||
value = ((args != NULL)? ((A_Const *) lfirst(args))->val.val.str: NULL);
|
||||
value = ((args != NULL) ? ((A_Const *) lfirst(args))->val.val.str : NULL);
|
||||
|
||||
if (strcasecmp(name, "session_authorization") == 0)
|
||||
SetSessionAuthorization(value);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: view.c,v 1.57 2001/08/16 20:38:53 tgl Exp $
|
||||
* $Id: view.c,v 1.58 2001/10/25 05:49:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -131,7 +131,6 @@ DefineViewRules(char *viewName, Query *viewParse)
|
||||
RuleStmt *replace_rule;
|
||||
RuleStmt *append_rule;
|
||||
RuleStmt *delete_rule;
|
||||
|
||||
#endif
|
||||
|
||||
retrieve_rule = FormViewRetrieveRule(viewName, viewParse);
|
||||
@@ -141,7 +140,6 @@ DefineViewRules(char *viewName, Query *viewParse)
|
||||
replace_rule = FormViewReplaceRule(viewName, viewParse);
|
||||
append_rule = FormViewAppendRule(viewName, viewParse);
|
||||
delete_rule = FormViewDeleteRule(viewName, viewParse);
|
||||
|
||||
#endif
|
||||
|
||||
DefineQueryRewrite(retrieve_rule);
|
||||
@@ -229,7 +227,6 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
|
||||
void
|
||||
DefineView(char *viewName, Query *viewParse)
|
||||
{
|
||||
|
||||
/*
|
||||
* Create the "view" relation NOTE: if it already exists, the xact
|
||||
* will be aborted.
|
||||
@@ -264,7 +261,6 @@ DefineView(char *viewName, Query *viewParse)
|
||||
void
|
||||
RemoveView(char *viewName)
|
||||
{
|
||||
|
||||
/*
|
||||
* We just have to drop the relation; the associated rules will be
|
||||
* cleaned up automatically.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* ExecInitTee
|
||||
* ExecEndTee
|
||||
*
|
||||
* $Id: nodeTee.c,v 1.10 2001/03/22 06:16:13 momjian Exp $
|
||||
* $Id: nodeTee.c,v 1.11 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -336,7 +336,6 @@ ExecTee(Tee * node, Plan *parent)
|
||||
slot = ExecProcNode(childNode, (Plan *) node);
|
||||
if (!TupIsNull(slot))
|
||||
{
|
||||
|
||||
/*
|
||||
* heap_insert changes something...
|
||||
*/
|
||||
@@ -361,7 +360,6 @@ ExecTee(Tee * node, Plan *parent)
|
||||
teeState->tee_leftScanDesc : teeState->tee_rightScanDesc;
|
||||
|
||||
{
|
||||
|
||||
/*
|
||||
* move the scandesc forward so we don't re-read this
|
||||
* tuple later
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execAmi.c,v 1.59 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Id: execAmi.c,v 1.60 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -224,7 +224,6 @@ ExecCloseR(Plan *node)
|
||||
|
||||
for (i = 0; i < numIndices; i++)
|
||||
{
|
||||
|
||||
/*
|
||||
* shut down each of the index scans and close each of the
|
||||
* index relations
|
||||
@@ -410,7 +409,7 @@ ExecMarkPos(Plan *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
case T_SeqScan:
|
||||
ExecSeqMarkPos((SeqScan *) node);
|
||||
break;
|
||||
|
||||
@@ -452,7 +451,7 @@ ExecRestrPos(Plan *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
case T_SeqScan:
|
||||
ExecSeqRestrPos((SeqScan *) node);
|
||||
break;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/Attic/execFlatten.c,v 1.14 2001/01/24 19:42:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/Attic/execFlatten.c,v 1.15 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -33,7 +33,6 @@
|
||||
#ifdef SETS_FIXED
|
||||
static bool FjoinBumpOuterNodes(TargetEntry *tlist, ExprContext *econtext,
|
||||
DatumPtr results, char *nulls);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -81,7 +80,6 @@ ExecEvalFjoin(TargetEntry *tlist,
|
||||
*/
|
||||
if (!fjNode->fj_initialized)
|
||||
{
|
||||
|
||||
/*
|
||||
* Initialize all of the Outer nodes
|
||||
*/
|
||||
@@ -127,7 +125,6 @@ ExecEvalFjoin(TargetEntry *tlist,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* If we're already initialized, all we need to do is get the next
|
||||
* inner result and pair it up with the existing outer node result
|
||||
@@ -242,5 +239,4 @@ FjoinBumpOuterNodes(TargetEntry *tlist,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.28 2001/05/27 20:48:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.29 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -111,7 +111,6 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType,
|
||||
resjunk = resdom->resjunk;
|
||||
if (!resjunk)
|
||||
{
|
||||
|
||||
/*
|
||||
* make a copy of the resdom node, changing its resno.
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.148 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.149 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -287,7 +287,6 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
|
||||
static void
|
||||
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
|
||||
{
|
||||
|
||||
/*
|
||||
* Check RTEs in the query's primary rangetable.
|
||||
*/
|
||||
@@ -428,7 +427,6 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
||||
|
||||
if (rte->checkForWrite)
|
||||
{
|
||||
|
||||
/*
|
||||
* Note: write access in a SELECT context means SELECT FOR UPDATE.
|
||||
* Right now we don't distinguish that from true update as far as
|
||||
@@ -521,7 +519,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
if (resultRelations != NIL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Multiple result relations (due to inheritance)
|
||||
* parseTree->resultRelations identifies them all
|
||||
@@ -544,7 +541,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Single result relation identified by
|
||||
* parseTree->resultRelation
|
||||
@@ -564,7 +560,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* if no result relation, then set state appropriately
|
||||
*/
|
||||
@@ -599,9 +594,9 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
/*
|
||||
* initialize the executor "tuple" table. We need slots for all the
|
||||
* plan nodes, plus possibly output slots for the junkfilter(s).
|
||||
* At this point we aren't sure if we need junkfilters, so just add
|
||||
* slots for them unconditionally.
|
||||
* plan nodes, plus possibly output slots for the junkfilter(s). At
|
||||
* this point we aren't sure if we need junkfilters, so just add slots
|
||||
* for them unconditionally.
|
||||
*/
|
||||
{
|
||||
int nSlots = ExecCountSlotsNode(plan);
|
||||
@@ -669,7 +664,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
if (junk_filter_needed)
|
||||
{
|
||||
|
||||
/*
|
||||
* If there are multiple result relations, each one needs its
|
||||
* own junk filter. Note this is only possible for
|
||||
@@ -694,7 +688,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
j = ExecInitJunkFilter(subplan->targetlist,
|
||||
ExecGetTupType(subplan),
|
||||
ExecAllocTableSlot(estate->es_tupleTable));
|
||||
ExecAllocTableSlot(estate->es_tupleTable));
|
||||
resultRelInfo->ri_junkFilter = j;
|
||||
resultRelInfo++;
|
||||
subplans = lnext(subplans);
|
||||
@@ -714,7 +708,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
j = ExecInitJunkFilter(plan->targetlist,
|
||||
tupType,
|
||||
ExecAllocTableSlot(estate->es_tupleTable));
|
||||
ExecAllocTableSlot(estate->es_tupleTable));
|
||||
estate->es_junkFilter = j;
|
||||
if (estate->es_result_relation_info)
|
||||
estate->es_result_relation_info->ri_junkFilter = j;
|
||||
@@ -741,13 +735,11 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
if (!parseTree->isPortal)
|
||||
{
|
||||
|
||||
/*
|
||||
* a select into table
|
||||
*/
|
||||
if (parseTree->into != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* create the "into" relation
|
||||
*/
|
||||
@@ -1101,7 +1093,7 @@ lnext: ;
|
||||
newTuple = ExecRemoveJunk(junkfilter, slot);
|
||||
|
||||
slot = ExecStoreTuple(newTuple, /* tuple to store */
|
||||
junkfilter->jf_resultSlot, /* dest slot */
|
||||
junkfilter->jf_resultSlot, /* dest slot */
|
||||
InvalidBuffer, /* this tuple has no
|
||||
* buffer */
|
||||
true); /* tuple should be pfreed */
|
||||
@@ -1234,7 +1226,7 @@ ExecAppend(TupleTableSlot *slot,
|
||||
|
||||
/* BEFORE ROW INSERT Triggers */
|
||||
if (resultRelInfo->ri_TrigDesc &&
|
||||
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
||||
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
||||
{
|
||||
HeapTuple newtuple;
|
||||
|
||||
@@ -1245,7 +1237,6 @@ ExecAppend(TupleTableSlot *slot,
|
||||
|
||||
if (newtuple != tuple) /* modified by Trigger(s) */
|
||||
{
|
||||
|
||||
/*
|
||||
* Insert modified tuple into tuple table slot, replacing the
|
||||
* original. We assume that it was allocated in per-tuple
|
||||
@@ -1314,7 +1305,7 @@ ExecDelete(TupleTableSlot *slot,
|
||||
|
||||
/* BEFORE ROW DELETE Triggers */
|
||||
if (resultRelInfo->ri_TrigDesc &&
|
||||
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
|
||||
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
|
||||
{
|
||||
bool dodelete;
|
||||
|
||||
@@ -1421,7 +1412,7 @@ ExecReplace(TupleTableSlot *slot,
|
||||
|
||||
/* BEFORE ROW UPDATE Triggers */
|
||||
if (resultRelInfo->ri_TrigDesc &&
|
||||
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
||||
resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
||||
{
|
||||
HeapTuple newtuple;
|
||||
|
||||
@@ -1433,7 +1424,6 @@ ExecReplace(TupleTableSlot *slot,
|
||||
|
||||
if (newtuple != tuple) /* modified by Trigger(s) */
|
||||
{
|
||||
|
||||
/*
|
||||
* Insert modified tuple into tuple table slot, replacing the
|
||||
* original. We assume that it was allocated in per-tuple
|
||||
@@ -1448,11 +1438,11 @@ ExecReplace(TupleTableSlot *slot,
|
||||
/*
|
||||
* Check the constraints of the tuple
|
||||
*
|
||||
* If we generate a new candidate tuple after EvalPlanQual testing,
|
||||
* we must loop back here and recheck constraints. (We don't need to
|
||||
* redo triggers, however. If there are any BEFORE triggers then
|
||||
* trigger.c will have done mark4update to lock the correct tuple,
|
||||
* so there's no need to do them again.)
|
||||
* If we generate a new candidate tuple after EvalPlanQual testing, we
|
||||
* must loop back here and recheck constraints. (We don't need to
|
||||
* redo triggers, however. If there are any BEFORE triggers then
|
||||
* trigger.c will have done mark4update to lock the correct tuple, so
|
||||
* there's no need to do them again.)
|
||||
*/
|
||||
lreplace:;
|
||||
if (resultRelationDesc->rd_att->constr)
|
||||
@@ -1483,7 +1473,7 @@ lreplace:;
|
||||
*tupleid = ctid;
|
||||
tuple = ExecRemoveJunk(estate->es_junkFilter, epqslot);
|
||||
slot = ExecStoreTuple(tuple,
|
||||
estate->es_junkFilter->jf_resultSlot,
|
||||
estate->es_junkFilter->jf_resultSlot,
|
||||
InvalidBuffer, true);
|
||||
goto lreplace;
|
||||
}
|
||||
@@ -1641,9 +1631,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
*/
|
||||
if (estate->es_result_relation_info != NULL &&
|
||||
estate->es_result_relation_info->ri_RangeTableIndex == rti)
|
||||
{
|
||||
relation = estate->es_result_relation_info->ri_RelationDesc;
|
||||
}
|
||||
else
|
||||
{
|
||||
List *l;
|
||||
@@ -1724,7 +1712,7 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
*tid = tuple.t_self;
|
||||
|
||||
/*
|
||||
* Need to run a recheck subquery. Find or create a PQ stack entry.
|
||||
* Need to run a recheck subquery. Find or create a PQ stack entry.
|
||||
*/
|
||||
epq = (evalPlanQual *) estate->es_evalPlanQual;
|
||||
rtsize = length(estate->es_range_table);
|
||||
@@ -1782,18 +1770,20 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
{
|
||||
newepq = (evalPlanQual *) palloc(sizeof(evalPlanQual));
|
||||
newepq->free = NULL;
|
||||
|
||||
/*
|
||||
* Each stack level has its own copy of the plan tree. This
|
||||
* Each stack level has its own copy of the plan tree. This
|
||||
* is wasteful, but necessary as long as plan nodes point to
|
||||
* exec state nodes rather than vice versa. Note that copyfuncs.c
|
||||
* doesn't attempt to copy the exec state nodes, which is a good
|
||||
* thing in this situation.
|
||||
* exec state nodes rather than vice versa. Note that
|
||||
* copyfuncs.c doesn't attempt to copy the exec state nodes,
|
||||
* which is a good thing in this situation.
|
||||
*/
|
||||
newepq->plan = copyObject(estate->es_origPlan);
|
||||
|
||||
/*
|
||||
* Init stack level's EState. We share top level's copy of
|
||||
* es_result_relations array and other non-changing status.
|
||||
* We need our own tupletable, es_param_exec_vals, and other
|
||||
* es_result_relations array and other non-changing status. We
|
||||
* need our own tupletable, es_param_exec_vals, and other
|
||||
* changeable state.
|
||||
*/
|
||||
epqstate = &(newepq->estate);
|
||||
@@ -1805,11 +1795,12 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
sizeof(ParamExecData));
|
||||
epqstate->es_tupleTable = NULL;
|
||||
epqstate->es_per_tuple_exprcontext = NULL;
|
||||
|
||||
/*
|
||||
* Each epqstate must have its own es_evTupleNull state,
|
||||
* but all the stack entries share es_evTuple state. This
|
||||
* allows sub-rechecks to inherit the value being examined by
|
||||
* an outer recheck.
|
||||
* Each epqstate must have its own es_evTupleNull state, but
|
||||
* all the stack entries share es_evTuple state. This allows
|
||||
* sub-rechecks to inherit the value being examined by an
|
||||
* outer recheck.
|
||||
*/
|
||||
epqstate->es_evTupleNull = (bool *) palloc(rtsize * sizeof(bool));
|
||||
if (epq == NULL)
|
||||
@@ -1842,12 +1833,12 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
epqstate = &(epq->estate);
|
||||
|
||||
/*
|
||||
* Ok - we're requested for the same RTE. Unfortunately we still
|
||||
* have to end and restart execution of the plan, because ExecReScan
|
||||
* Ok - we're requested for the same RTE. Unfortunately we still have
|
||||
* to end and restart execution of the plan, because ExecReScan
|
||||
* wouldn't ensure that upper plan nodes would reset themselves. We
|
||||
* could make that work if insertion of the target tuple were integrated
|
||||
* with the Param mechanism somehow, so that the upper plan nodes know
|
||||
* that their children's outputs have changed.
|
||||
* could make that work if insertion of the target tuple were
|
||||
* integrated with the Param mechanism somehow, so that the upper plan
|
||||
* nodes know that their children's outputs have changed.
|
||||
*/
|
||||
if (endNode)
|
||||
{
|
||||
@@ -1858,8 +1849,8 @@ EvalPlanQual(EState *estate, Index rti, ItemPointer tid)
|
||||
}
|
||||
|
||||
/*
|
||||
* free old RTE' tuple, if any, and store target tuple where relation's
|
||||
* scan node will see it
|
||||
* free old RTE' tuple, if any, and store target tuple where
|
||||
* relation's scan node will see it
|
||||
*/
|
||||
if (epqstate->es_evTuple[rti - 1] != NULL)
|
||||
heap_freetuple(epqstate->es_evTuple[rti - 1]);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.27 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.28 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -267,9 +267,9 @@ ExecProcNode(Plan *node, Plan *parent)
|
||||
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
/*
|
||||
* control nodes
|
||||
*/
|
||||
/*
|
||||
* control nodes
|
||||
*/
|
||||
case T_Result:
|
||||
result = ExecResult((Result *) node);
|
||||
break;
|
||||
@@ -473,9 +473,9 @@ ExecEndNode(Plan *node, Plan *parent)
|
||||
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
/*
|
||||
* control nodes
|
||||
*/
|
||||
/*
|
||||
* control nodes
|
||||
*/
|
||||
case T_Result:
|
||||
ExecEndResult((Result *) node);
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.88 2001/09/21 00:11:30 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.89 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -62,9 +62,9 @@ static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalNullTest(NullTest *ntest, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
|
||||
|
||||
/*----------
|
||||
@@ -126,7 +126,6 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Empty refexpr indicates we are doing an INSERT into an array
|
||||
* column. For now, we just take the refassgnexpr (which the
|
||||
@@ -339,9 +338,9 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull)
|
||||
* the entire tuple; we give back a whole slot so that callers know
|
||||
* what the tuple looks like.
|
||||
*
|
||||
* XXX this is a horrid crock: since the pointer to the slot might
|
||||
* live longer than the current evaluation context, we are forced to
|
||||
* copy the tuple and slot into a long-lived context --- we use
|
||||
* XXX this is a horrid crock: since the pointer to the slot might live
|
||||
* longer than the current evaluation context, we are forced to copy
|
||||
* the tuple and slot into a long-lived context --- we use
|
||||
* TransactionCommandContext which should be safe enough. This
|
||||
* represents a serious memory leak if many such tuples are processed
|
||||
* in one command, however. We ought to redesign the representation
|
||||
@@ -434,7 +433,6 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
|
||||
matchFound = 0;
|
||||
if (paramList != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* search for an entry in 'paramList' that matches the
|
||||
* `expression'.
|
||||
@@ -485,7 +483,6 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
|
||||
|
||||
if (!matchFound)
|
||||
{
|
||||
|
||||
/*
|
||||
* ooops! we couldn't find this parameter in the parameter list.
|
||||
* Signal an error
|
||||
@@ -1128,28 +1125,28 @@ ExecEvalNullTest(NullTest *ntest,
|
||||
|
||||
result = ExecEvalExpr(ntest->arg, econtext, isNull, isDone);
|
||||
switch (ntest->nulltesttype)
|
||||
{
|
||||
case IS_NULL:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else
|
||||
return BoolGetDatum(false);
|
||||
case IS_NOT_NULL:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else
|
||||
return BoolGetDatum(true);
|
||||
default:
|
||||
elog(ERROR, "ExecEvalNullTest: unexpected nulltesttype %d",
|
||||
(int) ntest->nulltesttype);
|
||||
return (Datum) 0; /* keep compiler quiet */
|
||||
}
|
||||
{
|
||||
case IS_NULL:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else
|
||||
return BoolGetDatum(false);
|
||||
case IS_NOT_NULL:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else
|
||||
return BoolGetDatum(true);
|
||||
default:
|
||||
elog(ERROR, "ExecEvalNullTest: unexpected nulltesttype %d",
|
||||
(int) ntest->nulltesttype);
|
||||
return (Datum) 0; /* keep compiler quiet */
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -1168,68 +1165,68 @@ ExecEvalBooleanTest(BooleanTest *btest,
|
||||
|
||||
result = ExecEvalExpr(btest->arg, econtext, isNull, isDone);
|
||||
switch (btest->booltesttype)
|
||||
{
|
||||
case IS_TRUE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(true);
|
||||
{
|
||||
case IS_TRUE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(true);
|
||||
else
|
||||
return BoolGetDatum(false);
|
||||
case IS_NOT_TRUE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(false);
|
||||
return BoolGetDatum(false);
|
||||
case IS_NOT_TRUE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(false);
|
||||
else
|
||||
return BoolGetDatum(true);
|
||||
case IS_FALSE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(false);
|
||||
return BoolGetDatum(true);
|
||||
case IS_FALSE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(false);
|
||||
else
|
||||
return BoolGetDatum(true);
|
||||
case IS_NOT_FALSE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(true);
|
||||
return BoolGetDatum(true);
|
||||
case IS_NOT_FALSE:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else if (DatumGetBool(result))
|
||||
return BoolGetDatum(true);
|
||||
else
|
||||
return BoolGetDatum(false);
|
||||
case IS_UNKNOWN:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
return BoolGetDatum(false);
|
||||
case IS_UNKNOWN:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(true);
|
||||
}
|
||||
else
|
||||
return BoolGetDatum(false);
|
||||
case IS_NOT_UNKNOWN:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
return BoolGetDatum(false);
|
||||
case IS_NOT_UNKNOWN:
|
||||
if (*isNull)
|
||||
{
|
||||
*isNull = false;
|
||||
return BoolGetDatum(false);
|
||||
}
|
||||
else
|
||||
return BoolGetDatum(true);
|
||||
default:
|
||||
elog(ERROR, "ExecEvalBooleanTest: unexpected booltesttype %d",
|
||||
(int) btest->booltesttype);
|
||||
return (Datum) 0; /* keep compiler quiet */
|
||||
}
|
||||
return BoolGetDatum(true);
|
||||
default:
|
||||
elog(ERROR, "ExecEvalBooleanTest: unexpected booltesttype %d",
|
||||
(int) btest->booltesttype);
|
||||
return (Datum) 0; /* keep compiler quiet */
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -1409,15 +1406,15 @@ ExecEvalExpr(Node *expression,
|
||||
break;
|
||||
case T_NullTest:
|
||||
retDatum = ExecEvalNullTest((NullTest *) expression,
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
case T_BooleanTest:
|
||||
retDatum = ExecEvalBooleanTest((BooleanTest *) expression,
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
econtext,
|
||||
isNull,
|
||||
isDone);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1665,7 +1662,7 @@ ExecTargetList(List *targetlist,
|
||||
* generating multiple tuples, when one or more tlist items return
|
||||
* sets. (We expect the caller to call us again if we return:
|
||||
*
|
||||
* isDone = ExprMultipleResult.)
|
||||
* isDone = ExprMultipleResult.)
|
||||
*/
|
||||
if (nodomains > NPREALLOCDOMAINS)
|
||||
{
|
||||
@@ -1774,13 +1771,11 @@ ExecTargetList(List *targetlist,
|
||||
|
||||
if (haveDoneSets)
|
||||
{
|
||||
|
||||
/*
|
||||
* note: can't get here unless we verified isDone != NULL
|
||||
*/
|
||||
if (*isDone == ExprSingleResult)
|
||||
{
|
||||
|
||||
/*
|
||||
* all sets are done, so report that tlist expansion is
|
||||
* complete.
|
||||
@@ -1792,7 +1787,6 @@ ExecTargetList(List *targetlist,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* We have some done and some undone sets. Restart the done
|
||||
* ones so that we can deliver a tuple (if possible).
|
||||
@@ -1815,7 +1809,6 @@ ExecTargetList(List *targetlist,
|
||||
|
||||
if (itemIsDone[resind] == ExprEndResult)
|
||||
{
|
||||
|
||||
/*
|
||||
* Oh dear, this item is returning an empty
|
||||
* set. Guess we can't make a tuple after all.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.17 2001/03/22 06:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.18 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -122,7 +122,6 @@ ExecScan(Scan *node,
|
||||
*/
|
||||
if (!qual || ExecQual(qual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* Found a satisfactory scan tuple.
|
||||
*
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.48 2001/03/22 06:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.49 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -241,10 +241,10 @@ ExecAllocTableSlot(TupleTable table)
|
||||
Assert(table != NULL);
|
||||
|
||||
/*
|
||||
* if our table is full we have to allocate a larger size table.
|
||||
* Since ExecAllocTableSlot() is only called before the table is ever
|
||||
* used to store tuples, we don't have to worry about the contents of
|
||||
* the old table. If this changes, then we will have to preserve the
|
||||
* if our table is full we have to allocate a larger size table. Since
|
||||
* ExecAllocTableSlot() is only called before the table is ever used
|
||||
* to store tuples, we don't have to worry about the contents of the
|
||||
* old table. If this changes, then we will have to preserve the
|
||||
* contents. -cim 6/23/90
|
||||
*
|
||||
* Unfortunately, we *cannot* do this. All of the nodes in the plan that
|
||||
@@ -347,7 +347,6 @@ ExecStoreTuple(HeapTuple tuple,
|
||||
Buffer buffer,
|
||||
bool shouldFree)
|
||||
{
|
||||
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
@@ -407,7 +406,7 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
||||
|
||||
slot->val = (HeapTuple) NULL;
|
||||
|
||||
slot->ttc_shouldFree = true;/* probably useless code... */
|
||||
slot->ttc_shouldFree = true; /* probably useless code... */
|
||||
|
||||
/*
|
||||
* Drop the pin on the referenced buffer, if there is one.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.77 2001/07/16 05:06:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.78 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -78,7 +78,6 @@ ResetTupleCount(void)
|
||||
NTupleReplaced = 0;
|
||||
NIndexTupleProcessed = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -117,7 +116,6 @@ DisplayTupleCount(FILE *statfp)
|
||||
(NTupleReplaced == 1) ? "" : "s");
|
||||
fprintf(statfp, "\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -504,26 +502,26 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
||||
/*
|
||||
* Open (and lock, if necessary) the index relation
|
||||
*
|
||||
* If the index AM is not safe for concurrent updates, obtain
|
||||
* an exclusive lock on the index to lock out other updaters as
|
||||
* well as readers (index_beginscan places AccessShareLock).
|
||||
* We will release this lock in ExecCloseIndices.
|
||||
* If the index AM is not safe for concurrent updates, obtain an
|
||||
* exclusive lock on the index to lock out other updaters as well
|
||||
* as readers (index_beginscan places AccessShareLock). We will
|
||||
* release this lock in ExecCloseIndices.
|
||||
*
|
||||
* If the index AM supports concurrent updates, we obtain no lock
|
||||
* here at all, which is a tad weird, but safe since any critical
|
||||
* operation on the index (like deleting it) will acquire exclusive
|
||||
* lock on the parent table. Perhaps someday we should acquire
|
||||
* RowExclusiveLock on the index here?
|
||||
* operation on the index (like deleting it) will acquire
|
||||
* exclusive lock on the parent table. Perhaps someday we should
|
||||
* acquire RowExclusiveLock on the index here?
|
||||
*
|
||||
* If there are multiple not-concurrent-safe indexes, all backends
|
||||
* must lock the indexes in the same order or we will get deadlocks
|
||||
* here during concurrent updates. This is guaranteed by
|
||||
* RelationGetIndexList(), which promises to return the index list
|
||||
* in OID order.
|
||||
* must lock the indexes in the same order or we will get
|
||||
* deadlocks here during concurrent updates. This is guaranteed
|
||||
* by RelationGetIndexList(), which promises to return the index
|
||||
* list in OID order.
|
||||
*/
|
||||
indexDesc = index_open(indexOid);
|
||||
|
||||
if (! indexDesc->rd_am->amconcurrent)
|
||||
if (!indexDesc->rd_am->amconcurrent)
|
||||
LockRelation(indexDesc, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
@@ -572,7 +570,7 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
|
||||
continue;
|
||||
|
||||
/* Drop lock, if one was acquired by ExecOpenIndices */
|
||||
if (! indexDescs[i]->rd_am->amconcurrent)
|
||||
if (!indexDescs[i]->rd_am->amconcurrent)
|
||||
UnlockRelation(indexDescs[i], AccessExclusiveLock);
|
||||
|
||||
index_close(indexDescs[i]);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.45 2001/03/22 06:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.46 2001/10/25 05:49:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -32,7 +32,7 @@
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
|
||||
F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
|
||||
} ExecStatus;
|
||||
|
||||
typedef struct local_es
|
||||
@@ -201,7 +201,6 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* This is a hack. We assume here that any function returning a
|
||||
* tuple returns it by reference. This needs to be fixed, since
|
||||
@@ -257,7 +256,6 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||
static void
|
||||
postquel_start(execution_state *es)
|
||||
{
|
||||
|
||||
/*
|
||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
@@ -274,7 +272,6 @@ postquel_getnext(execution_state *es)
|
||||
|
||||
if (es->qd->operation == CMD_UTILITY)
|
||||
{
|
||||
|
||||
/*
|
||||
* Process a utility command. (create, destroy...) DZ - 30-8-1996
|
||||
*/
|
||||
@@ -292,7 +289,6 @@ postquel_getnext(execution_state *es)
|
||||
static void
|
||||
postquel_end(execution_state *es)
|
||||
{
|
||||
|
||||
/*
|
||||
* Do nothing for utility commands. (create, destroy...) DZ -
|
||||
* 30-8-1996
|
||||
@@ -417,7 +413,6 @@ postquel_execute(execution_state *es,
|
||||
*/
|
||||
if (fcache->returnsTuple)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX do we need to remove junk attrs from the result tuple?
|
||||
* Probably OK to leave them, as long as they are at the end.
|
||||
@@ -528,7 +523,6 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
||||
*/
|
||||
if (es == (execution_state *) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Reset the execution states to start over again
|
||||
*/
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* instrument.c
|
||||
* functions for instrumentation of plan execution
|
||||
* functions for instrumentation of plan execution
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2001, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/instrument.c,v 1.1 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/instrument.c,v 1.2 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -22,9 +22,9 @@
|
||||
Instrumentation *
|
||||
InstrAlloc(void)
|
||||
{
|
||||
Instrumentation *instr = palloc( sizeof(Instrumentation) );
|
||||
Instrumentation *instr = palloc(sizeof(Instrumentation));
|
||||
|
||||
memset( instr, 0, sizeof(Instrumentation) );
|
||||
memset(instr, 0, sizeof(Instrumentation));
|
||||
|
||||
return instr;
|
||||
}
|
||||
@@ -47,7 +47,7 @@ void
|
||||
InstrStopNode(Instrumentation *instr, bool returnedTuple)
|
||||
{
|
||||
struct timeval endtime;
|
||||
|
||||
|
||||
if (!instr)
|
||||
return;
|
||||
|
||||
@@ -56,10 +56,10 @@ InstrStopNode(Instrumentation *instr, bool returnedTuple)
|
||||
elog(DEBUG, "InstrStopNode without start");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gettimeofday(&endtime, NULL);
|
||||
|
||||
instr->counter.tv_sec += endtime.tv_sec - instr->starttime.tv_sec;
|
||||
|
||||
instr->counter.tv_sec += endtime.tv_sec - instr->starttime.tv_sec;
|
||||
instr->counter.tv_usec += endtime.tv_usec - instr->starttime.tv_usec;
|
||||
|
||||
/* Normalize after each add to avoid overflow/underflow of tv_usec */
|
||||
@@ -90,10 +90,10 @@ InstrStopNode(Instrumentation *instr, bool returnedTuple)
|
||||
}
|
||||
|
||||
/* Finish a run cycle for a plan node */
|
||||
void
|
||||
void
|
||||
InstrEndLoop(Instrumentation *instr)
|
||||
{
|
||||
double totaltime;
|
||||
double totaltime;
|
||||
|
||||
if (!instr)
|
||||
return;
|
||||
@@ -104,10 +104,10 @@ InstrEndLoop(Instrumentation *instr)
|
||||
|
||||
/* Accumulate statistics */
|
||||
totaltime = (double) instr->counter.tv_sec +
|
||||
(double) instr->counter.tv_usec / 1000000.0;
|
||||
(double) instr->counter.tv_usec / 1000000.0;
|
||||
|
||||
instr->startup += instr->firsttuple;
|
||||
instr->total += totaltime;
|
||||
instr->total += totaltime;
|
||||
instr->ntuples += instr->tuplecount;
|
||||
instr->nloops += 1;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.77 2001/03/22 06:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.78 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -73,7 +73,6 @@
|
||||
*/
|
||||
typedef struct AggStatePerAggData
|
||||
{
|
||||
|
||||
/*
|
||||
* These values are set up during ExecInitAgg() and do not change
|
||||
* thereafter:
|
||||
@@ -178,7 +177,6 @@ initialize_aggregate(AggStatePerAgg peraggstate)
|
||||
*/
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
|
||||
/*
|
||||
* In case of rescan, maybe there could be an uncompleted sort
|
||||
* operation? Clean it up if so.
|
||||
@@ -228,7 +226,6 @@ advance_transition_function(AggStatePerAgg peraggstate,
|
||||
{
|
||||
if (isNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* For a strict transfn, nothing happens at a NULL input
|
||||
* tuple; we just keep the prior transValue. However, if the
|
||||
@@ -243,7 +240,6 @@ advance_transition_function(AggStatePerAgg peraggstate,
|
||||
}
|
||||
if (peraggstate->noTransValue)
|
||||
{
|
||||
|
||||
/*
|
||||
* transValue has not been initialized. This is the first
|
||||
* non-NULL input value. We use it as the initial value for
|
||||
@@ -264,7 +260,6 @@ advance_transition_function(AggStatePerAgg peraggstate,
|
||||
}
|
||||
if (peraggstate->transValueIsNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* Don't call a strict function with NULL inputs. Note it is
|
||||
* possible to get here despite the above tests, if the
|
||||
@@ -333,7 +328,6 @@ process_sorted_aggregate(AggState *aggstate,
|
||||
while (tuplesort_getdatum(peraggstate->sortstate, true,
|
||||
&newVal, &isNull))
|
||||
{
|
||||
|
||||
/*
|
||||
* DISTINCT always suppresses nulls, per SQL spec, regardless of
|
||||
* the transition function's strictness.
|
||||
@@ -398,7 +392,6 @@ static void
|
||||
finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* Apply the agg's finalfn if one is provided, else return transValue.
|
||||
*/
|
||||
@@ -757,7 +750,6 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
aggstate->numaggs = numaggs = length(aggstate->aggs);
|
||||
if (numaggs <= 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* This used to be treated as an error, but we can't do that
|
||||
* anymore because constant-expression simplification could
|
||||
@@ -897,7 +889,6 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
*/
|
||||
if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* Note: use the type from the input expression here, not
|
||||
* aggform->aggbasetype, because the latter might be 0.
|
||||
@@ -913,7 +904,6 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
|
||||
/*
|
||||
* Note: use the type from the input expression here, not
|
||||
* aggform->aggbasetype, because the latter might be 0.
|
||||
@@ -947,8 +937,8 @@ int
|
||||
ExecCountSlotsAgg(Agg *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
AGG_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
AGG_NSLOTS;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.42 2001/05/15 00:33:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAppend.c,v 1.43 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -90,7 +90,6 @@ exec_append_initialize_next(Append *node)
|
||||
|
||||
if (whichplan < appendstate->as_firstplan)
|
||||
{
|
||||
|
||||
/*
|
||||
* if scanning in reverse, we start at the last scan in the list
|
||||
* and then proceed back to the first.. in any case we inform
|
||||
@@ -102,7 +101,6 @@ exec_append_initialize_next(Append *node)
|
||||
}
|
||||
else if (whichplan > appendstate->as_lastplan)
|
||||
{
|
||||
|
||||
/*
|
||||
* as above, end the scan if we go beyond the last scan in our
|
||||
* list..
|
||||
@@ -112,7 +110,6 @@ exec_append_initialize_next(Append *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* initialize the scan
|
||||
*
|
||||
@@ -182,12 +179,13 @@ ExecInitAppend(Append *node, EState *estate, Plan *parent)
|
||||
node->appendstate = appendstate;
|
||||
|
||||
/*
|
||||
* Do we want to scan just one subplan? (Special case for EvalPlanQual)
|
||||
* XXX pretty dirty way of determining that this case applies ...
|
||||
* Do we want to scan just one subplan? (Special case for
|
||||
* EvalPlanQual) XXX pretty dirty way of determining that this case
|
||||
* applies ...
|
||||
*/
|
||||
if (node->isTarget && estate->es_evTuple != NULL)
|
||||
{
|
||||
int tplan;
|
||||
int tplan;
|
||||
|
||||
tplan = estate->es_result_relation_info - estate->es_result_relations;
|
||||
Assert(tplan >= 0 && tplan < nplans);
|
||||
@@ -301,7 +299,6 @@ ExecProcAppend(Append *node)
|
||||
|
||||
if (!TupIsNull(result))
|
||||
{
|
||||
|
||||
/*
|
||||
* if the subplan gave us something then place a copy of whatever
|
||||
* we get into our result slot and return it.
|
||||
@@ -313,7 +310,6 @@ ExecProcAppend(Append *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* .. go on to the "next" subplan in the appropriate direction and
|
||||
* try processing again (recursively)
|
||||
@@ -385,15 +381,17 @@ ExecReScanAppend(Append *node, ExprContext *exprCtxt, Plan *parent)
|
||||
Plan *subnode;
|
||||
|
||||
subnode = (Plan *) nth(i, node->appendplans);
|
||||
|
||||
/*
|
||||
* ExecReScan doesn't know about my subplans, so I have to do
|
||||
* changed-parameter signaling myself.
|
||||
*/
|
||||
if (node->plan.chgParam != NULL)
|
||||
SetChangedParamList(subnode, node->plan.chgParam);
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
* if chgParam of subnode is not null then plan will be re-scanned
|
||||
* by first ExecProcNode.
|
||||
*/
|
||||
if (subnode->chgParam == NULL)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* locate group boundaries.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.43 2001/03/22 06:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.44 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -122,7 +122,6 @@ ExecGroupEveryTuple(Group *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Compare with first tuple and see if this tuple is of the
|
||||
* same group.
|
||||
@@ -133,7 +132,6 @@ ExecGroupEveryTuple(Group *node)
|
||||
grpstate->eqfunctions,
|
||||
econtext->ecxt_per_tuple_memory))
|
||||
{
|
||||
|
||||
/*
|
||||
* No; save the tuple to return it next time, and return
|
||||
* NULL
|
||||
@@ -478,7 +476,7 @@ execTuplesMatch(HeapTuple tuple1,
|
||||
* Look up the equality functions needed for execTuplesMatch.
|
||||
* The result is a palloc'd array.
|
||||
*/
|
||||
FmgrInfo *
|
||||
FmgrInfo *
|
||||
execTuplesMatchPrepare(TupleDesc tupdesc,
|
||||
int numCols,
|
||||
AttrNumber *matchColIdx)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $Id: nodeHash.c,v 1.59 2001/08/13 19:50:11 tgl Exp $
|
||||
* $Id: nodeHash.c,v 1.60 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -69,7 +69,6 @@ ExecHash(Hash *node)
|
||||
|
||||
if (nbatch > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Open temp files for inner batches, if needed. Note that file
|
||||
* buffers are palloc'd in regular executor context.
|
||||
@@ -165,8 +164,8 @@ int
|
||||
ExecCountSlotsHash(Hash *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
HASH_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
HASH_NSLOTS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
@@ -279,7 +278,6 @@ ExecHashTableCreate(Hash *node)
|
||||
|
||||
if (nbatch > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* allocate and initialize the file arrays in hashCxt
|
||||
*/
|
||||
@@ -480,7 +478,6 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
||||
*/
|
||||
if (bucketno < hashtable->nbuckets)
|
||||
{
|
||||
|
||||
/*
|
||||
* put the tuple in hash table
|
||||
*/
|
||||
@@ -506,7 +503,6 @@ ExecHashTableInsert(HashJoinTable hashtable,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* put the tuple into a tmp file for other batches
|
||||
*/
|
||||
@@ -536,8 +532,8 @@ ExecHashGetBucket(HashJoinTable hashtable,
|
||||
MemoryContext oldContext;
|
||||
|
||||
/*
|
||||
* We reset the eval context each time to reclaim any memory leaked
|
||||
* in the hashkey expression or hashFunc itself.
|
||||
* We reset the eval context each time to reclaim any memory leaked in
|
||||
* the hashkey expression or hashFunc itself.
|
||||
*/
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -657,15 +653,15 @@ hashFunc(Datum key, int len, bool byVal)
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If this is a variable length type, then 'key' points to a "struct
|
||||
* varlena" and len == -1. NOTE: VARSIZE returns the "real" data
|
||||
* length plus the sizeof the "vl_len" attribute of varlena (the
|
||||
* length information). 'key' points to the beginning of the varlena
|
||||
* struct, so we have to use "VARDATA" to find the beginning of
|
||||
* the "real" data. Also, we have to be careful to detoast the
|
||||
* datum if it's toasted. (We don't worry about freeing the detoasted
|
||||
* copy; that happens for free when the per-tuple memory context
|
||||
* is reset in ExecHashGetBucket.)
|
||||
* If this is a variable length type, then 'key' points to a
|
||||
* "struct varlena" and len == -1. NOTE: VARSIZE returns the
|
||||
* "real" data length plus the sizeof the "vl_len" attribute of
|
||||
* varlena (the length information). 'key' points to the beginning
|
||||
* of the varlena struct, so we have to use "VARDATA" to find the
|
||||
* beginning of the "real" data. Also, we have to be careful to
|
||||
* detoast the datum if it's toasted. (We don't worry about
|
||||
* freeing the detoasted copy; that happens for free when the
|
||||
* per-tuple memory context is reset in ExecHashGetBucket.)
|
||||
*/
|
||||
unsigned char *k;
|
||||
|
||||
@@ -737,7 +733,6 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
|
||||
void
|
||||
ExecReScanHash(Hash *node, ExprContext *exprCtxt, Plan *parent)
|
||||
{
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.38 2001/03/22 06:16:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.39 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -148,7 +148,6 @@ ExecHashJoin(HashJoin *node)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we don't have an outer tuple, get the next one
|
||||
*/
|
||||
@@ -159,7 +158,6 @@ ExecHashJoin(HashJoin *node)
|
||||
hjstate);
|
||||
if (TupIsNull(outerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* when the last batch runs out, clean up and exit
|
||||
*/
|
||||
@@ -193,7 +191,6 @@ ExecHashJoin(HashJoin *node)
|
||||
|
||||
if (batch > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to postpone this outer tuple to a later batch.
|
||||
* Save it in the corresponding outer-batch file.
|
||||
@@ -270,7 +267,6 @@ ExecHashJoin(HashJoin *node)
|
||||
if (!hjstate->hj_MatchedOuter &&
|
||||
node->join.jointype == JOIN_LEFT)
|
||||
{
|
||||
|
||||
/*
|
||||
* We are doing an outer join and there were no join matches
|
||||
* for this outer tuple. Generate a fake join tuple with
|
||||
@@ -281,7 +277,6 @@ ExecHashJoin(HashJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification was satisfied so we project and return
|
||||
* the slot containing the result tuple using
|
||||
@@ -411,8 +406,8 @@ int
|
||||
ExecCountSlotsHashJoin(HashJoin *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
HASHJOIN_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
HASHJOIN_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -565,7 +560,6 @@ ExecHashJoinNewBatch(HashJoinState *hjstate)
|
||||
|
||||
if (newbatch > 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* We no longer need the previous outer batch file; close it right
|
||||
* away to free disk space.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.62 2001/07/15 22:48:17 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.63 2001/10/25 05:49:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -222,7 +222,7 @@ IndexNext(IndexScan *node)
|
||||
qual = lnext(qual);
|
||||
}
|
||||
if (!prev_matches)
|
||||
return slot;/* OK to return tuple */
|
||||
return slot; /* OK to return tuple */
|
||||
/* Duplicate tuple, so drop it and loop back for another */
|
||||
ExecClearTuple(slot);
|
||||
}
|
||||
@@ -337,7 +337,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
|
||||
if (econtext)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we are being passed an outer tuple, save it for runtime key
|
||||
* calc
|
||||
@@ -377,7 +376,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
run_keys = runtimeKeyInfo[i];
|
||||
for (j = 0; j < n_keys; j++)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have a run-time key, then extract the run-time
|
||||
* expression and evaluate it with respect to the current
|
||||
@@ -703,10 +701,10 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
Expr *clause; /* one clause of index qual */
|
||||
Oper *op; /* operator used in clause */
|
||||
Node *leftop; /* expr on lhs of operator */
|
||||
Node *rightop;/* expr on rhs ... */
|
||||
Node *rightop; /* expr on rhs ... */
|
||||
bits16 flags = 0;
|
||||
|
||||
int scanvar;/* which var identifies varattno */
|
||||
int scanvar; /* which var identifies varattno */
|
||||
AttrNumber varattno = 0; /* att number used in scan */
|
||||
Oid opid; /* operator id used in scan */
|
||||
Datum scanvalue = 0; /* value used in scan (if const) */
|
||||
@@ -772,7 +770,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
|
||||
if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
|
||||
{
|
||||
|
||||
/*
|
||||
* if the leftop is a "rel-var", then it means that it is
|
||||
* a var node which tells us which attribute to use for
|
||||
@@ -783,7 +780,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
}
|
||||
else if (IsA(leftop, Const))
|
||||
{
|
||||
|
||||
/*
|
||||
* if the leftop is a const node then it means it
|
||||
* identifies the value to place in our scan key.
|
||||
@@ -820,7 +816,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* otherwise, the leftop contains an expression evaluable
|
||||
* at runtime to figure out the value to place in our scan
|
||||
@@ -842,7 +837,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
|
||||
if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
|
||||
{
|
||||
|
||||
/*
|
||||
* here we make sure only one op identifies the
|
||||
* scan-attribute...
|
||||
@@ -861,7 +855,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
}
|
||||
else if (IsA(rightop, Const))
|
||||
{
|
||||
|
||||
/*
|
||||
* if the rightop is a const node then it means it
|
||||
* identifies the value to place in our scan key.
|
||||
@@ -898,7 +891,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* otherwise, the rightop contains an expression evaluable
|
||||
* at runtime to figure out the value to place in our scan
|
||||
@@ -1023,7 +1015,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
ExecOpenScanR(indexOid, /* relation */
|
||||
numScanKeys[i], /* nkeys */
|
||||
scanKeys[i], /* scan key */
|
||||
true, /* is index */
|
||||
true, /* is index */
|
||||
direction, /* scan direction */
|
||||
estate->es_snapshot,
|
||||
&(relationDescs[i]), /* return: rel desc */
|
||||
@@ -1045,5 +1037,5 @@ int
|
||||
ExecCountSlotsIndexScan(IndexScan *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.7 2001/08/06 18:05:07 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.8 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -66,7 +66,6 @@ ExecLimit(Limit *node)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have reached the subplan EOF or the limit, just quit.
|
||||
*
|
||||
@@ -76,11 +75,11 @@ ExecLimit(Limit *node)
|
||||
* here is for position > netlimit not position >= netlimit.
|
||||
*
|
||||
* Similarly, when scanning backwards, we must re-fetch the last
|
||||
* tuple in the offset region before we can return NULL.
|
||||
* Otherwise we won't be correctly aligned to start going forward
|
||||
* again. So, although you might think we can quit when position
|
||||
* equals offset + 1, we have to fetch a subplan tuple first, and
|
||||
* then exit when position = offset.
|
||||
* tuple in the offset region before we can return NULL. Otherwise
|
||||
* we won't be correctly aligned to start going forward again.
|
||||
* So, although you might think we can quit when position equals
|
||||
* offset + 1, we have to fetch a subplan tuple first, and then
|
||||
* exit when position = offset.
|
||||
*/
|
||||
if (ScanDirectionIsForward(direction))
|
||||
{
|
||||
@@ -101,7 +100,6 @@ ExecLimit(Limit *node)
|
||||
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||
if (TupIsNull(slot))
|
||||
{
|
||||
|
||||
/*
|
||||
* We are at start or end of the subplan. Update local state
|
||||
* appropriately, but always return NULL.
|
||||
@@ -269,8 +267,8 @@ int
|
||||
ExecCountSlotsLimit(Limit *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
LIMIT_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
LIMIT_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.36 2001/05/27 20:42:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.37 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -185,8 +185,8 @@ int
|
||||
ExecCountSlotsMaterial(Material *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
||||
MATERIAL_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
||||
MATERIAL_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.45 2001/03/23 04:49:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.46 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -124,7 +124,6 @@ MJFormSkipQual(List *qualList, char *replaceopname)
|
||||
|
||||
foreach(qualcdr, qualCopy)
|
||||
{
|
||||
|
||||
/*
|
||||
* first get the current (op .. ..) list
|
||||
*/
|
||||
@@ -321,7 +320,6 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
|
||||
|
||||
printf("******** \n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -431,7 +429,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
default:
|
||||
elog(ERROR, "ExecMergeJoin: unsupported join type %d",
|
||||
(int) node->join.jointype);
|
||||
doFillOuter = false;/* keep compiler quiet */
|
||||
doFillOuter = false; /* keep compiler quiet */
|
||||
doFillInner = false;
|
||||
break;
|
||||
}
|
||||
@@ -476,7 +474,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* get the current state of the join and do things accordingly.
|
||||
* Note: The join states are highlighted with 32-* comments for
|
||||
@@ -486,7 +483,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
switch (mergestate->mj_JoinState)
|
||||
{
|
||||
|
||||
/*
|
||||
* EXEC_MJ_INITIALIZE means that this is the first time
|
||||
* ExecMergeJoin() has been called and so we have to fetch
|
||||
@@ -505,7 +501,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
MJ_printf("ExecMergeJoin: outer subplan is empty\n");
|
||||
if (doFillInner)
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples. We set MatchedInner = true to
|
||||
@@ -526,7 +521,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
MJ_printf("ExecMergeJoin: inner subplan is empty\n");
|
||||
if (doFillOuter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit left-join tuples for all outer
|
||||
* tuples, including the one we just fetched. We
|
||||
@@ -632,7 +626,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (qualResult)
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -669,7 +662,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (doFillInner && !mergestate->mj_MatchedInner)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the outer
|
||||
* tuple, and return it if it passes the non-join
|
||||
@@ -686,7 +678,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -747,7 +738,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (doFillOuter && !mergestate->mj_MatchedOuter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the inner
|
||||
* tuple, and return it if it passes the non-join
|
||||
@@ -764,7 +754,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -805,7 +794,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples.
|
||||
@@ -873,7 +861,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (qualResult)
|
||||
{
|
||||
|
||||
/*
|
||||
* the merge clause matched so now we restore the
|
||||
* inner scan position to the first mark, and loop
|
||||
@@ -915,7 +902,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
{
|
||||
if (doFillOuter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit left-join tuples for remaining
|
||||
* outer tuples.
|
||||
@@ -1036,7 +1022,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (doFillOuter && !mergestate->mj_MatchedOuter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the inner
|
||||
* tuple, and return it if it passes the non-join
|
||||
@@ -1053,7 +1038,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -1094,7 +1078,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples.
|
||||
@@ -1216,7 +1199,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (doFillInner && !mergestate->mj_MatchedInner)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the outer
|
||||
* tuple, and return it if it passes the non-join
|
||||
@@ -1233,7 +1215,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -1274,7 +1255,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
if (doFillOuter && !TupIsNull(outerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit left-join tuples for remaining
|
||||
* outer tuples.
|
||||
@@ -1304,7 +1284,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (!mergestate->mj_MatchedInner)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the outer
|
||||
* tuple, and return it if it passes the non-join
|
||||
@@ -1321,7 +1300,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -1373,7 +1351,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (!mergestate->mj_MatchedOuter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate a fake join tuple with nulls for the inner
|
||||
* tuple, and return it if it passes the non-join
|
||||
@@ -1390,7 +1367,6 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification succeeded. now form the desired
|
||||
* projection tuple and return the slot containing
|
||||
@@ -1579,8 +1555,8 @@ int
|
||||
ExecCountSlotsMergeJoin(MergeJoin *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
||||
MERGEJOIN_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
||||
MERGEJOIN_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.24 2001/03/22 06:16:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.25 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -118,7 +118,6 @@ ExecNestLoop(NestLoop *node)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we don't have an outer tuple, get the next one and reset the
|
||||
* inner scan.
|
||||
@@ -174,7 +173,6 @@ ExecNestLoop(NestLoop *node)
|
||||
if (!nlstate->nl_MatchedOuter &&
|
||||
node->join.jointype == JOIN_LEFT)
|
||||
{
|
||||
|
||||
/*
|
||||
* We are doing an outer join and there were no join
|
||||
* matches for this outer tuple. Generate a fake join
|
||||
@@ -187,7 +185,6 @@ ExecNestLoop(NestLoop *node)
|
||||
|
||||
if (ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification was satisfied so we project and
|
||||
* return the slot containing the result tuple using
|
||||
@@ -231,7 +228,6 @@ ExecNestLoop(NestLoop *node)
|
||||
|
||||
if (otherqual == NIL || ExecQual(otherqual, econtext, false))
|
||||
{
|
||||
|
||||
/*
|
||||
* qualification was satisfied so we project and return
|
||||
* the slot containing the result tuple using
|
||||
@@ -346,8 +342,8 @@ int
|
||||
ExecCountSlotsNestLoop(NestLoop *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
NESTLOOP_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
NESTLOOP_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.19 2001/03/22 06:16:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.20 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -125,7 +125,6 @@ ExecResult(Result *node)
|
||||
|
||||
if (outerPlan != NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* retrieve tuples from the outer plan until there are no
|
||||
* more.
|
||||
@@ -146,7 +145,6 @@ ExecResult(Result *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* if we don't have an outer plan, then we are just generating
|
||||
* the results from a constant target list. Do it only once.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.31 2001/07/15 22:48:18 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.32 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -127,7 +127,6 @@ SeqNext(SeqScan *node)
|
||||
TupleTableSlot *
|
||||
ExecSeqScan(SeqScan *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* use SeqNext as access method
|
||||
*/
|
||||
@@ -246,8 +245,8 @@ int
|
||||
ExecCountSlotsSeqScan(SeqScan *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
SEQSCAN_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
SEQSCAN_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.4 2001/03/22 06:16:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.5 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -100,7 +100,6 @@ ExecSetOp(SetOp *node)
|
||||
|
||||
if (TupIsNull(resultTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* First of group: save a copy in result slot, and reset
|
||||
* duplicate-counters for new group.
|
||||
@@ -118,7 +117,6 @@ ExecSetOp(SetOp *node)
|
||||
}
|
||||
else if (setopstate->subplan_done)
|
||||
{
|
||||
|
||||
/*
|
||||
* Reached end of input, so finish processing final group
|
||||
*/
|
||||
@@ -126,7 +124,6 @@ ExecSetOp(SetOp *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Else test if the new tuple and the previously saved tuple
|
||||
* match.
|
||||
@@ -144,7 +141,6 @@ ExecSetOp(SetOp *node)
|
||||
|
||||
if (endOfGroup)
|
||||
{
|
||||
|
||||
/*
|
||||
* We've reached the end of the group containing resultTuple.
|
||||
* Decide how many copies (if any) to emit. This logic is
|
||||
@@ -187,7 +183,6 @@ ExecSetOp(SetOp *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Current tuple is member of same group as resultTuple. Count
|
||||
* it in the appropriate counter.
|
||||
@@ -294,8 +289,8 @@ int
|
||||
ExecCountSlotsSetOp(SetOp *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
SETOP_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
SETOP_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.34 2001/05/27 20:42:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.35 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -275,8 +275,8 @@ int
|
||||
ExecCountSlotsSort(Sort *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
||||
SORT_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) +
|
||||
SORT_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.31 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.32 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -257,7 +257,6 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
|
||||
if (!found)
|
||||
{
|
||||
|
||||
/*
|
||||
* deal with empty subplan result. result/isNull were previously
|
||||
* initialized correctly for all sublink types except EXPR and
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.10 2001/09/18 01:59:06 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.11 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -63,8 +63,8 @@ SubqueryNext(SubqueryScan *node)
|
||||
direction = estate->es_direction;
|
||||
|
||||
/*
|
||||
* We need not support EvalPlanQual here, since we are not scanning
|
||||
* a real relation.
|
||||
* We need not support EvalPlanQual here, since we are not scanning a
|
||||
* real relation.
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -92,7 +92,6 @@ SubqueryNext(SubqueryScan *node)
|
||||
TupleTableSlot *
|
||||
ExecSubqueryScan(SubqueryScan *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* use SubqueryNext as access method
|
||||
*/
|
||||
@@ -181,8 +180,8 @@ ExecCountSlotsSubqueryScan(SubqueryScan *node)
|
||||
* The subplan has its own tuple table and must not be counted here!
|
||||
*/
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
SUBQUERYSCAN_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
SUBQUERYSCAN_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -251,6 +250,7 @@ ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
*/
|
||||
if (node->scan.plan.chgParam != NULL)
|
||||
SetChangedParamList(node->subplan, node->scan.plan.chgParam);
|
||||
|
||||
/*
|
||||
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||
* first ExecProcNode.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.19 2001/09/29 07:57:06 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.20 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "access/heapam.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
static int TidListCreate(List *, ExprContext *, ItemPointerData []);
|
||||
static int TidListCreate(List *, ExprContext *, ItemPointerData[]);
|
||||
static TupleTableSlot *TidNext(TidScan *node);
|
||||
|
||||
static int
|
||||
@@ -80,7 +80,7 @@ TidNext(TidScan *node)
|
||||
|
||||
bool bBackward;
|
||||
int tidNumber;
|
||||
ItemPointerData* tidList;
|
||||
ItemPointerData *tidList;
|
||||
|
||||
/*
|
||||
* extract necessary information from tid scan node
|
||||
@@ -233,7 +233,6 @@ TidNext(TidScan *node)
|
||||
TupleTableSlot *
|
||||
ExecTidScan(TidScan *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* use TidNext as access method
|
||||
*/
|
||||
@@ -249,7 +248,7 @@ ExecTidReScan(TidScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
{
|
||||
EState *estate;
|
||||
TidScanState *tidstate;
|
||||
ItemPointerData* tidList;
|
||||
ItemPointerData *tidList;
|
||||
|
||||
tidstate = node->tidstate;
|
||||
estate = node->scan.plan.state;
|
||||
@@ -357,7 +356,6 @@ ExecTidRestrPos(TidScan *node)
|
||||
tidstate = node->tidstate;
|
||||
tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -376,7 +374,7 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent)
|
||||
{
|
||||
TidScanState *tidstate;
|
||||
CommonScanState *scanstate;
|
||||
ItemPointerData* tidList;
|
||||
ItemPointerData *tidList;
|
||||
int numTids;
|
||||
int tidPtr;
|
||||
List *rangeTable;
|
||||
@@ -482,5 +480,5 @@ int
|
||||
ExecCountSlotsTidScan(TidScan *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan((Plan *) node)) +
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan((Plan *) node)) + TIDSCAN_NSLOTS;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.32 2001/03/22 06:16:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeUnique.c,v 1.33 2001/10/25 05:49:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -61,7 +61,6 @@ ExecUnique(Unique *node)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* fetch a tuple from the outer subplan
|
||||
*/
|
||||
@@ -186,8 +185,8 @@ int
|
||||
ExecCountSlotsUnique(Unique *node)
|
||||
{
|
||||
return ExecCountSlotsNode(outerPlan(node)) +
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
UNIQUE_NSLOTS;
|
||||
ExecCountSlotsNode(innerPlan(node)) +
|
||||
UNIQUE_NSLOTS;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user