mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
pgindent run. Make it all clean.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.69 2001/01/24 19:42:46 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.70 2001/03/22 03:59:11 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The old interface functions have been converted to macros
|
||||
@@ -306,8 +306,8 @@ nocachegetattr(HeapTuple tuple,
|
||||
int j;
|
||||
|
||||
/*
|
||||
* In for(), we test <= and not < because we want to see
|
||||
* if we can go past it in initializing offsets.
|
||||
* In for(), we test <= and not < because we want to see if we
|
||||
* can go past it in initializing offsets.
|
||||
*/
|
||||
for (j = 0; j <= attnum; j++)
|
||||
{
|
||||
@@ -321,9 +321,9 @@ nocachegetattr(HeapTuple tuple,
|
||||
}
|
||||
|
||||
/*
|
||||
* If slow is false, and we got here, we know that we have a tuple with
|
||||
* no nulls or varlenas before the target attribute. If possible, we
|
||||
* also want to initialize the remainder of the attribute cached
|
||||
* If slow is false, and we got here, we know that we have a tuple
|
||||
* with no nulls or varlenas before the target attribute. If possible,
|
||||
* we also want to initialize the remainder of the attribute cached
|
||||
* offset values.
|
||||
*/
|
||||
if (!slow)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.52 2001/02/22 21:48:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.53 2001/03/22 03:59:11 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,9 +45,11 @@ index_formtuple(TupleDesc tupleDescriptor,
|
||||
bool hasnull = false;
|
||||
uint16 tupmask = 0;
|
||||
int numberOfAttributes = tupleDescriptor->natts;
|
||||
|
||||
#ifdef TOAST_INDEX_HACK
|
||||
Datum untoasted_value[INDEX_MAX_KEYS];
|
||||
bool untoasted_free[INDEX_MAX_KEYS];
|
||||
|
||||
#endif
|
||||
|
||||
if (numberOfAttributes > INDEX_MAX_KEYS)
|
||||
@@ -57,7 +59,7 @@ index_formtuple(TupleDesc tupleDescriptor,
|
||||
#ifdef TOAST_INDEX_HACK
|
||||
for (i = 0; i < numberOfAttributes; i++)
|
||||
{
|
||||
Form_pg_attribute att = tupleDescriptor->attrs[i];
|
||||
Form_pg_attribute att = tupleDescriptor->attrs[i];
|
||||
|
||||
untoasted_value[i] = value[i];
|
||||
untoasted_free[i] = false;
|
||||
@@ -73,20 +75,20 @@ index_formtuple(TupleDesc tupleDescriptor,
|
||||
if (VARATT_IS_EXTERNAL(value[i]))
|
||||
{
|
||||
untoasted_value[i] = PointerGetDatum(
|
||||
heap_tuple_fetch_attr(
|
||||
(varattrib *) DatumGetPointer(value[i])));
|
||||
heap_tuple_fetch_attr(
|
||||
(varattrib *) DatumGetPointer(value[i])));
|
||||
untoasted_free[i] = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If value is above size target, and is of a compressible datatype,
|
||||
* try to compress it in-line.
|
||||
* If value is above size target, and is of a compressible
|
||||
* datatype, try to compress it in-line.
|
||||
*/
|
||||
if (VARATT_SIZE(untoasted_value[i]) > TOAST_INDEX_TARGET &&
|
||||
!VARATT_IS_EXTENDED(untoasted_value[i]) &&
|
||||
(att->attstorage == 'x' || att->attstorage == 'm'))
|
||||
{
|
||||
Datum cvalue = toast_compress_datum(untoasted_value[i]);
|
||||
Datum cvalue = toast_compress_datum(untoasted_value[i]);
|
||||
|
||||
if (DatumGetPointer(cvalue) != NULL)
|
||||
{
|
||||
@@ -146,8 +148,8 @@ index_formtuple(TupleDesc tupleDescriptor,
|
||||
/*
|
||||
* We do this because DataFill wants to initialize a "tupmask" which
|
||||
* is used for HeapTuples, but we want an indextuple infomask. The
|
||||
* only relevant info is the "has variable attributes" field.
|
||||
* We have already set the hasnull bit above.
|
||||
* only relevant info is the "has variable attributes" field. We have
|
||||
* already set the hasnull bit above.
|
||||
*/
|
||||
|
||||
if (tupmask & HEAP_HASVARLENA)
|
||||
@@ -315,9 +317,9 @@ nocache_index_getattr(IndexTuple tup,
|
||||
}
|
||||
|
||||
/*
|
||||
* If slow is false, and we got here, we know that we have a tuple with
|
||||
* no nulls or varlenas before the target attribute. If possible, we
|
||||
* also want to initialize the remainder of the attribute cached
|
||||
* If slow is false, and we got here, we know that we have a tuple
|
||||
* with no nulls or varlenas before the target attribute. If possible,
|
||||
* we also want to initialize the remainder of the attribute cached
|
||||
* offset values.
|
||||
*/
|
||||
if (!slow)
|
||||
@@ -391,9 +393,7 @@ nocache_index_getattr(IndexTuple tup,
|
||||
usecache = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
off += att[i]->attlen;
|
||||
}
|
||||
}
|
||||
|
||||
off = att_align(off, att[attnum]->attlen, att[attnum]->attalign);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.57 2001/01/24 19:42:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.58 2001/03/22 03:59:11 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -51,7 +51,7 @@ getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
|
||||
|
||||
*typOutput = pt->typoutput;
|
||||
*typElem = pt->typelem;
|
||||
*typIsVarlena = (! pt->typbyval) && (pt->typlen == -1);
|
||||
*typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
|
||||
ReleaseSysCache(typeTuple);
|
||||
return OidIsValid(*typOutput);
|
||||
}
|
||||
@@ -200,9 +200,10 @@ 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.
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (thisState->typisvarlena)
|
||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||
@@ -210,9 +211,9 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
||||
attr = origattr;
|
||||
|
||||
outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
|
||||
attr,
|
||||
ObjectIdGetDatum(thisState->typelem),
|
||||
Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
|
||||
attr,
|
||||
ObjectIdGetDatum(thisState->typelem),
|
||||
Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
|
||||
|
||||
pq_sendcountedtext(&buf, outputstr, strlen(outputstr));
|
||||
|
||||
@@ -308,9 +309,10 @@ 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.
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (typisvarlena)
|
||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||
@@ -318,9 +320,9 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
||||
attr = origattr;
|
||||
|
||||
value = DatumGetCString(OidFunctionCall3(typoutput,
|
||||
attr,
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
|
||||
attr,
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
|
||||
|
||||
printatt((unsigned) i + 1, typeinfo->attrs[i], value);
|
||||
|
||||
@@ -405,6 +407,7 @@ 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.71 2001/01/24 19:42:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.72 2001/03/22 03:59:11 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||
@@ -242,9 +242,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||
/*
|
||||
* We do not need to check every single field here, and in fact
|
||||
* some fields such as attdispersion probably shouldn't be
|
||||
* compared. We can also disregard attnum (it was used to
|
||||
* place the row in the attrs array) and everything derived
|
||||
* from the column datatype.
|
||||
* compared. We can also disregard 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;
|
||||
@@ -276,8 +276,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||
|
||||
/*
|
||||
* We can't assume that the items are always read from the
|
||||
* system catalogs in the same order; so use the adnum field to
|
||||
* identify the matching item to compare.
|
||||
* system catalogs in the same order; so use the adnum field
|
||||
* to identify the matching item to compare.
|
||||
*/
|
||||
for (j = 0; j < n; defval2++, j++)
|
||||
{
|
||||
@@ -298,9 +298,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||
ConstrCheck *check2 = constr2->check;
|
||||
|
||||
/*
|
||||
* Similarly, don't assume that the checks are always read
|
||||
* in the same order; match them up by name and contents.
|
||||
* (The name *should* be unique, but...)
|
||||
* Similarly, don't assume that the checks are always read in
|
||||
* the same order; match them up by name and contents. (The
|
||||
* name *should* be unique, but...)
|
||||
*/
|
||||
for (j = 0; j < n; check2++, j++)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,8 +32,8 @@ static bool gistindex_keytest(IndexTuple tuple, TupleDesc tupdesc,
|
||||
Datum
|
||||
gistgettuple(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
RetrieveIndexResult res;
|
||||
|
||||
/* if we have it cached in the scan desc, just return the value */
|
||||
|
||||
@@ -72,9 +72,9 @@ gistbeginscan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
gistrescan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
|
||||
GISTScanOpaque p;
|
||||
int i;
|
||||
|
||||
@@ -160,7 +160,7 @@ gistrescan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
gistmarkpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GISTScanOpaque p;
|
||||
GISTSTACK *o,
|
||||
*n,
|
||||
@@ -196,7 +196,7 @@ gistmarkpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
gistrestrpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GISTScanOpaque p;
|
||||
GISTSTACK *o,
|
||||
*n,
|
||||
@@ -232,8 +232,8 @@ gistrestrpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
gistendscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GISTScanOpaque p;
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GISTScanOpaque p;
|
||||
|
||||
p = (GISTScanOpaque) s->opaque;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.49 2001/02/22 21:48:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.50 2001/03/22 03:59:12 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains only the public interface routines.
|
||||
@@ -41,12 +41,14 @@ bool BuildingHash = false;
|
||||
Datum
|
||||
hashbuild(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
Node *oldPred = (Node *) PG_GETARG_POINTER(3);
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
Node *oldPred = (Node *) PG_GETARG_POINTER(3);
|
||||
|
||||
#ifdef NOT_USED
|
||||
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
|
||||
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
|
||||
|
||||
#endif
|
||||
HeapScanDesc hscan;
|
||||
HeapTuple htup;
|
||||
@@ -59,9 +61,11 @@ hashbuild(PG_FUNCTION_ARGS)
|
||||
nitups;
|
||||
HashItem hitem;
|
||||
Node *pred = indexInfo->ii_Predicate;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
TupleTable tupleTable;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
#endif
|
||||
ExprContext *econtext;
|
||||
InsertIndexResult res = NULL;
|
||||
@@ -117,6 +121,7 @@ hashbuild(PG_FUNCTION_ARGS)
|
||||
nhtups++;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
|
||||
/*
|
||||
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
|
||||
* this tuple if it was already in the existing partial index
|
||||
@@ -191,9 +196,7 @@ hashbuild(PG_FUNCTION_ARGS)
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
if (pred != NULL || oldPred != NULL)
|
||||
{
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
}
|
||||
#endif /* OMIT_PARTIAL_INDEX */
|
||||
FreeExprContext(econtext);
|
||||
|
||||
@@ -241,12 +244,14 @@ hashbuild(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashinsert(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
|
||||
char *nulls = (char *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
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);
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
|
||||
#endif
|
||||
InsertIndexResult res;
|
||||
HashItem hitem;
|
||||
@@ -276,8 +281,8 @@ hashinsert(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashgettuple(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
RetrieveIndexResult res;
|
||||
|
||||
/*
|
||||
@@ -326,11 +331,13 @@ hashbeginscan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashrescan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
|
||||
#ifdef NOT_USED /* XXX surely it's wrong to ignore this? */
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
|
||||
#endif
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
ItemPointer iptr;
|
||||
HashScanOpaque so;
|
||||
|
||||
@@ -367,7 +374,7 @@ hashrescan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashendscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer iptr;
|
||||
HashScanOpaque so;
|
||||
|
||||
@@ -405,7 +412,7 @@ hashendscan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashmarkpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer iptr;
|
||||
HashScanOpaque so;
|
||||
|
||||
@@ -437,7 +444,7 @@ hashmarkpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashrestrpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer iptr;
|
||||
HashScanOpaque so;
|
||||
|
||||
@@ -468,8 +475,8 @@ hashrestrpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashdelete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
|
||||
/* adjust any active scans that will be affected by this deletion */
|
||||
_hash_adjscans(rel, tid);
|
||||
@@ -491,8 +498,8 @@ hash_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
elog(STOP, "hash_undo: unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hash_desc(char *buf, uint8 xl_info, char* rec)
|
||||
hash_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.29 2001/01/24 19:42:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.30 2001/03/22 03:59:13 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These functions are stored in pg_amproc. For each operator class
|
||||
@@ -25,32 +25,32 @@
|
||||
Datum
|
||||
hashchar(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_UINT32(~ ((uint32) PG_GETARG_CHAR(0)));
|
||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_CHAR(0)));
|
||||
}
|
||||
|
||||
Datum
|
||||
hashint2(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_UINT32(~ ((uint32) PG_GETARG_INT16(0)));
|
||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_INT16(0)));
|
||||
}
|
||||
|
||||
Datum
|
||||
hashint4(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_UINT32(~ PG_GETARG_UINT32(0));
|
||||
PG_RETURN_UINT32(~PG_GETARG_UINT32(0));
|
||||
}
|
||||
|
||||
Datum
|
||||
hashint8(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* we just use the low 32 bits... */
|
||||
PG_RETURN_UINT32(~ ((uint32) PG_GETARG_INT64(0)));
|
||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_INT64(0)));
|
||||
}
|
||||
|
||||
Datum
|
||||
hashoid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_UINT32(~ ((uint32) PG_GETARG_OID(0)));
|
||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
|
||||
}
|
||||
|
||||
Datum
|
||||
@@ -93,7 +93,7 @@ hashint2vector(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
hashname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *key = NameStr(* PG_GETARG_NAME(0));
|
||||
char *key = NameStr(*PG_GETARG_NAME(0));
|
||||
|
||||
return hash_any((char *) key, NAMEDATALEN);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.110 2001/01/24 19:42:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.111 2001/03/22 03:59:13 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
* heapgettup - fetch next heap tuple from a scan
|
||||
* heap_open - open a heap relation by relationId
|
||||
* heap_openr - open a heap relation by name
|
||||
* heap_open[r]_nofail - same, but return NULL on failure instead of elog
|
||||
* heap_open[r]_nofail - same, but return NULL on failure instead of elog
|
||||
* heap_close - close a heap relation
|
||||
* heap_beginscan - begin relation scan
|
||||
* heap_rescan - restart a relation scan
|
||||
@@ -88,16 +88,16 @@
|
||||
|
||||
#include "access/xlogutils.h"
|
||||
|
||||
XLogRecPtr log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup);
|
||||
XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
|
||||
char *unused, int unlen);
|
||||
XLogRecPtr log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup);
|
||||
XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
|
||||
char *unused, int unlen);
|
||||
|
||||
/* comments are in heap_update */
|
||||
static xl_heaptid _locked_tuple_;
|
||||
static xl_heaptid _locked_tuple_;
|
||||
static void _heap_unlock_tuple(void *data);
|
||||
static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
|
||||
ItemPointerData from, Buffer newbuf, HeapTuple newtup, bool move);
|
||||
static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
|
||||
ItemPointerData from, Buffer newbuf, HeapTuple newtup, bool move);
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -249,7 +249,7 @@ heapgettup(Relation relation,
|
||||
OffsetNumber lineoff;
|
||||
int linesleft;
|
||||
ItemPointer tid = (tuple->t_data == NULL) ?
|
||||
(ItemPointer) NULL : &(tuple->t_self);
|
||||
(ItemPointer) NULL : &(tuple->t_self);
|
||||
|
||||
/* ----------------
|
||||
* increment access statistics
|
||||
@@ -286,7 +286,7 @@ heapgettup(Relation relation,
|
||||
|
||||
if (!ItemPointerIsValid(tid))
|
||||
Assert(!PointerIsValid(tid));
|
||||
|
||||
|
||||
tuple->t_tableOid = relation->rd_id;
|
||||
|
||||
/* ----------------
|
||||
@@ -538,9 +538,9 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
|
||||
(
|
||||
(tupleDesc)->attrs[(attnum) - 1]->attcacheoff >= 0 ?
|
||||
(
|
||||
fetchatt((tupleDesc)->attrs[(attnum) - 1],
|
||||
(char *) (tup)->t_data + (tup)->t_data->t_hoff +
|
||||
(tupleDesc)->attrs[(attnum) - 1]->attcacheoff)
|
||||
fetchatt((tupleDesc)->attrs[(attnum) - 1],
|
||||
(char *) (tup)->t_data + (tup)->t_data->t_hoff +
|
||||
(tupleDesc)->attrs[(attnum) - 1]->attcacheoff)
|
||||
)
|
||||
:
|
||||
nocachegetattr((tup), (attnum), (tupleDesc), (isnull))
|
||||
@@ -564,7 +564,8 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
|
||||
)
|
||||
);
|
||||
}
|
||||
#endif /* defined(DISABLE_COMPLEX_MACRO)*/
|
||||
|
||||
#endif /* defined(DISABLE_COMPLEX_MACRO) */
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -791,8 +792,8 @@ heap_beginscan(Relation relation,
|
||||
scan->rs_nkeys = (short) nkeys;
|
||||
|
||||
/*
|
||||
* we do this here instead of in initscan() because heap_rescan
|
||||
* also calls initscan() and we don't want to allocate memory again
|
||||
* we do this here instead of in initscan() because heap_rescan also
|
||||
* calls initscan() and we don't want to allocate memory again
|
||||
*/
|
||||
if (nkeys)
|
||||
scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
|
||||
@@ -1316,7 +1317,7 @@ heap_get_latest_tid(Relation relation,
|
||||
Oid
|
||||
heap_insert(Relation relation, HeapTuple tup)
|
||||
{
|
||||
Buffer buffer;
|
||||
Buffer buffer;
|
||||
|
||||
/* increment access statistics */
|
||||
IncrHeapAccessStat(local_insert);
|
||||
@@ -1350,7 +1351,7 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||
* toasted attributes from some other relation, invoke the toaster.
|
||||
* ----------
|
||||
*/
|
||||
if (HeapTupleHasExtended(tup) ||
|
||||
if (HeapTupleHasExtended(tup) ||
|
||||
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
|
||||
heap_tuple_toast_attrs(relation, tup, NULL);
|
||||
#endif
|
||||
@@ -1364,17 +1365,17 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||
|
||||
/* XLOG stuff */
|
||||
{
|
||||
xl_heap_insert xlrec;
|
||||
xl_heap_header xlhdr;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[3];
|
||||
Page page = BufferGetPage(buffer);
|
||||
uint8 info = XLOG_HEAP_INSERT;
|
||||
xl_heap_insert xlrec;
|
||||
xl_heap_header xlhdr;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[3];
|
||||
Page page = BufferGetPage(buffer);
|
||||
uint8 info = XLOG_HEAP_INSERT;
|
||||
|
||||
xlrec.target.node = relation->rd_node;
|
||||
xlrec.target.tid = tup->t_self;
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = SizeOfHeapInsert;
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
@@ -1383,12 +1384,12 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||
xlhdr.t_hoff = tup->t_data->t_hoff;
|
||||
xlhdr.mask = tup->t_data->t_infomask;
|
||||
rdata[1].buffer = buffer;
|
||||
rdata[1].data = (char*)&xlhdr;
|
||||
rdata[1].data = (char *) &xlhdr;
|
||||
rdata[1].len = SizeOfHeapHeader;
|
||||
rdata[1].next = &(rdata[2]);
|
||||
|
||||
rdata[2].buffer = buffer;
|
||||
rdata[2].data = (char*) tup->t_data + offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[2].data = (char *) tup->t_data + offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[2].len = tup->t_len - offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[2].next = NULL;
|
||||
|
||||
@@ -1411,10 +1412,10 @@ heap_insert(Relation relation, HeapTuple tup)
|
||||
WriteBuffer(buffer);
|
||||
|
||||
/*
|
||||
* If tuple is cachable, mark it for rollback from the caches
|
||||
* in case we abort. Note it is OK to do this after WriteBuffer
|
||||
* releases the buffer, because the "tup" data structure is all
|
||||
* in local memory, not in the shared buffer.
|
||||
* If tuple is cachable, mark it for rollback from the caches in case
|
||||
* we abort. Note it is OK to do this after WriteBuffer releases the
|
||||
* buffer, because the "tup" data structure is all in local memory,
|
||||
* not in the shared buffer.
|
||||
*/
|
||||
RelationMark4RollbackHeapTuple(relation, tup);
|
||||
|
||||
@@ -1513,14 +1514,14 @@ l1:
|
||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||
/* XLOG stuff */
|
||||
{
|
||||
xl_heap_delete xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
xl_heap_delete xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
|
||||
xlrec.target.node = relation->rd_node;
|
||||
xlrec.target.tid = tp.t_self;
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = SizeOfHeapDelete;
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
@@ -1551,9 +1552,10 @@ l1:
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Mark tuple for invalidation from system caches at next command boundary.
|
||||
* We have to do this before WriteBuffer because we need to look at the
|
||||
* contents of the tuple, so we need to hold our refcount on the buffer.
|
||||
* Mark tuple for invalidation from system caches at next command
|
||||
* boundary. We have to do this before WriteBuffer because we need to
|
||||
* look at the contents of the tuple, so we need to hold our refcount
|
||||
* on the buffer.
|
||||
*/
|
||||
RelationInvalidateHeapTuple(relation, &tp);
|
||||
|
||||
@@ -1567,7 +1569,7 @@ l1:
|
||||
*
|
||||
* This routine may be used to delete a tuple when concurrent updates of
|
||||
* the target tuple are not expected (for example, because we have a lock
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* via elog().
|
||||
*/
|
||||
void
|
||||
@@ -1636,6 +1638,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||
oldtup.t_data = (HeapTupleHeader) PageGetItem(dp, lp);
|
||||
oldtup.t_len = ItemIdGetLength(lp);
|
||||
oldtup.t_self = *otid;
|
||||
|
||||
/*
|
||||
* Note: beyond this point, use oldtup not otid to refer to old tuple.
|
||||
* otid may very well point at newtup->t_self, which we will overwrite
|
||||
@@ -1701,23 +1704,24 @@ l2:
|
||||
|
||||
/*
|
||||
* If the toaster needs to be activated, OR if the new tuple will not
|
||||
* fit on the same page as the old, then we need to release the context
|
||||
* lock (but not the pin!) on the old tuple's buffer while we are off
|
||||
* doing TOAST and/or table-file-extension work. We must mark the old
|
||||
* tuple to show that it's already being updated, else other processes
|
||||
* may try to update it themselves. To avoid second XLOG log record,
|
||||
* we use xact mgr hook to unlock old tuple without reading log if xact
|
||||
* will abort before update is logged. In the event of crash prio logging,
|
||||
* TQUAL routines will see HEAP_XMAX_UNLOGGED flag...
|
||||
* fit on the same page as the old, then we need to release the
|
||||
* context lock (but not the pin!) on the old tuple's buffer while we
|
||||
* are off doing TOAST and/or table-file-extension work. We must mark
|
||||
* the old tuple to show that it's already being updated, else other
|
||||
* processes may try to update it themselves. To avoid second XLOG log
|
||||
* record, we use xact mgr hook to unlock old tuple without reading
|
||||
* log if xact will abort before update is logged. In the event of
|
||||
* crash prio logging, TQUAL routines will see HEAP_XMAX_UNLOGGED
|
||||
* flag...
|
||||
*
|
||||
* NOTE: this trick is useless currently but saved for future
|
||||
* when we'll implement UNDO and will re-use transaction IDs
|
||||
* after postmaster startup.
|
||||
* NOTE: this trick is useless currently but saved for future when we'll
|
||||
* implement UNDO and will re-use transaction IDs after postmaster
|
||||
* startup.
|
||||
*
|
||||
* We need to invoke the toaster if there are already any toasted values
|
||||
* present, or if the new tuple is over-threshold.
|
||||
*/
|
||||
need_toast = (HeapTupleHasExtended(&oldtup) ||
|
||||
need_toast = (HeapTupleHasExtended(&oldtup) ||
|
||||
HeapTupleHasExtended(newtup) ||
|
||||
(MAXALIGN(newtup->t_len) > TOAST_TUPLE_THRESHOLD));
|
||||
|
||||
@@ -1726,7 +1730,7 @@ l2:
|
||||
{
|
||||
_locked_tuple_.node = relation->rd_node;
|
||||
_locked_tuple_.tid = oldtup.t_self;
|
||||
XactPushRollback(_heap_unlock_tuple, (void*) &_locked_tuple_);
|
||||
XactPushRollback(_heap_unlock_tuple, (void *) &_locked_tuple_);
|
||||
|
||||
TransactionIdStore(GetCurrentTransactionId(),
|
||||
&(oldtup.t_data->t_xmax));
|
||||
@@ -1762,7 +1766,7 @@ l2:
|
||||
/* NO ELOG(ERROR) from here till changes are logged */
|
||||
START_CRIT_SECTION();
|
||||
|
||||
RelationPutHeapTuple(relation, newbuf, newtup); /* insert new tuple */
|
||||
RelationPutHeapTuple(relation, newbuf, newtup); /* insert new tuple */
|
||||
|
||||
if (already_marked)
|
||||
{
|
||||
@@ -1784,7 +1788,7 @@ l2:
|
||||
|
||||
/* XLOG stuff */
|
||||
{
|
||||
XLogRecPtr recptr = log_heap_update(relation, buffer, oldtup.t_self,
|
||||
XLogRecPtr recptr = log_heap_update(relation, buffer, oldtup.t_self,
|
||||
newbuf, newtup, false);
|
||||
|
||||
if (newbuf != buffer)
|
||||
@@ -1814,10 +1818,10 @@ l2:
|
||||
WriteBuffer(buffer);
|
||||
|
||||
/*
|
||||
* If new tuple is cachable, mark it for rollback from the caches
|
||||
* in case we abort. Note it is OK to do this after WriteBuffer
|
||||
* releases the buffer, because the "newtup" data structure is all
|
||||
* in local memory, not in the shared buffer.
|
||||
* If new tuple is cachable, mark it for rollback from the caches in
|
||||
* case we abort. Note it is OK to do this after WriteBuffer releases
|
||||
* the buffer, because the "newtup" data structure is all in local
|
||||
* memory, not in the shared buffer.
|
||||
*/
|
||||
RelationMark4RollbackHeapTuple(relation, newtup);
|
||||
|
||||
@@ -1829,7 +1833,7 @@ l2:
|
||||
*
|
||||
* This routine may be used to update a tuple when concurrent updates of
|
||||
* the target tuple are not expected (for example, because we have a lock
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* via elog().
|
||||
*/
|
||||
void
|
||||
@@ -2129,14 +2133,14 @@ heap_restrpos(HeapScanDesc scan)
|
||||
XLogRecPtr
|
||||
log_heap_clean(Relation reln, Buffer buffer, char *unused, int unlen)
|
||||
{
|
||||
xl_heap_clean xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[3];
|
||||
xl_heap_clean xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[3];
|
||||
|
||||
xlrec.node = reln->rd_node;
|
||||
xlrec.block = BufferGetBlockNumber(buffer);
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = SizeOfHeapClean;
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
@@ -2157,27 +2161,27 @@ log_heap_clean(Relation reln, Buffer buffer, char *unused, int unlen)
|
||||
|
||||
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CLEAN, rdata);
|
||||
|
||||
return(recptr);
|
||||
return (recptr);
|
||||
}
|
||||
|
||||
static XLogRecPtr
|
||||
log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup, bool move)
|
||||
{
|
||||
char tbuf[MAXALIGN(sizeof(xl_heap_header)) + 2 * sizeof(TransactionId)];
|
||||
xl_heap_update xlrec;
|
||||
xl_heap_header *xlhdr = (xl_heap_header*) tbuf;
|
||||
int hsize = SizeOfHeapHeader;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[4];
|
||||
Page page = BufferGetPage(newbuf);
|
||||
uint8 info = (move) ? XLOG_HEAP_MOVE : XLOG_HEAP_UPDATE;
|
||||
char tbuf[MAXALIGN(sizeof(xl_heap_header)) + 2 * sizeof(TransactionId)];
|
||||
xl_heap_update xlrec;
|
||||
xl_heap_header *xlhdr = (xl_heap_header *) tbuf;
|
||||
int hsize = SizeOfHeapHeader;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[4];
|
||||
Page page = BufferGetPage(newbuf);
|
||||
uint8 info = (move) ? XLOG_HEAP_MOVE : XLOG_HEAP_UPDATE;
|
||||
|
||||
xlrec.target.node = reln->rd_node;
|
||||
xlrec.target.tid = from;
|
||||
xlrec.newtid = newtup->t_self;
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = SizeOfHeapUpdate;
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
@@ -2190,9 +2194,9 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
xlhdr->t_natts = newtup->t_data->t_natts;
|
||||
xlhdr->t_hoff = newtup->t_data->t_hoff;
|
||||
xlhdr->mask = newtup->t_data->t_infomask;
|
||||
if (move) /* remember xmin & xmax */
|
||||
if (move) /* remember xmin & xmax */
|
||||
{
|
||||
TransactionId xmax;
|
||||
TransactionId xmax;
|
||||
|
||||
if (newtup->t_data->t_infomask & HEAP_XMAX_INVALID ||
|
||||
newtup->t_data->t_infomask & HEAP_MARKED_FOR_UPDATE)
|
||||
@@ -2200,17 +2204,17 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
else
|
||||
xmax = newtup->t_data->t_xmax;
|
||||
memcpy(tbuf + hsize, &xmax, sizeof(TransactionId));
|
||||
memcpy(tbuf + hsize + sizeof(TransactionId),
|
||||
&(newtup->t_data->t_xmin), sizeof(TransactionId));
|
||||
memcpy(tbuf + hsize + sizeof(TransactionId),
|
||||
&(newtup->t_data->t_xmin), sizeof(TransactionId));
|
||||
hsize += (2 * sizeof(TransactionId));
|
||||
}
|
||||
rdata[2].buffer = newbuf;
|
||||
rdata[2].data = (char*)xlhdr;
|
||||
rdata[2].data = (char *) xlhdr;
|
||||
rdata[2].len = hsize;
|
||||
rdata[2].next = &(rdata[3]);
|
||||
|
||||
rdata[3].buffer = newbuf;
|
||||
rdata[3].data = (char*) newtup->t_data + offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[3].data = (char *) newtup->t_data + offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[3].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[3].next = NULL;
|
||||
|
||||
@@ -2224,23 +2228,23 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
|
||||
recptr = XLogInsert(RM_HEAP_ID, info, rdata);
|
||||
|
||||
return(recptr);
|
||||
return (recptr);
|
||||
}
|
||||
|
||||
XLogRecPtr
|
||||
log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup)
|
||||
log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup)
|
||||
{
|
||||
return(log_heap_update(reln, oldbuf, from, newbuf, newtup, true));
|
||||
return (log_heap_update(reln, oldbuf, from, newbuf, newtup, true));
|
||||
}
|
||||
|
||||
static void
|
||||
heap_xlog_clean(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_heap_clean *xlrec = (xl_heap_clean*) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
xl_heap_clean *xlrec = (xl_heap_clean *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
if (!redo || (record->xl_info & XLR_BKP_BLOCK_1))
|
||||
return;
|
||||
@@ -2266,15 +2270,15 @@ heap_xlog_clean(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
if (record->xl_len > SizeOfHeapClean)
|
||||
{
|
||||
char unbuf[BLCKSZ];
|
||||
OffsetNumber *unused = (OffsetNumber*)unbuf;
|
||||
char *unend;
|
||||
ItemId lp;
|
||||
char unbuf[BLCKSZ];
|
||||
OffsetNumber *unused = (OffsetNumber *) unbuf;
|
||||
char *unend;
|
||||
ItemId lp;
|
||||
|
||||
memcpy(unbuf, (char*)xlrec + SizeOfHeapClean, record->xl_len - SizeOfHeapClean);
|
||||
memcpy(unbuf, (char *) xlrec + SizeOfHeapClean, record->xl_len - SizeOfHeapClean);
|
||||
unend = unbuf + (record->xl_len - SizeOfHeapClean);
|
||||
|
||||
while((char*)unused < unend)
|
||||
while ((char *) unused < unend)
|
||||
{
|
||||
lp = ((PageHeader) page)->pd_linp + *unused;
|
||||
lp->lp_flags &= ~LP_USED;
|
||||
@@ -2289,13 +2293,13 @@ heap_xlog_clean(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
static void
|
||||
heap_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_heap_delete *xlrec = (xl_heap_delete*) XLogRecGetData(record);
|
||||
Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node);
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
ItemId lp = NULL;
|
||||
HeapTupleHeader htup;
|
||||
xl_heap_delete *xlrec = (xl_heap_delete *) XLogRecGetData(record);
|
||||
Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node);
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
ItemId lp = NULL;
|
||||
HeapTupleHeader htup;
|
||||
|
||||
if (redo && (record->xl_info & XLR_BKP_BLOCK_1))
|
||||
return;
|
||||
@@ -2303,7 +2307,7 @@ heap_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
if (!RelationIsValid(reln))
|
||||
return;
|
||||
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "heap_delete_%sdo: no block", (redo) ? "re" : "un");
|
||||
@@ -2320,7 +2324,8 @@ heap_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied ?! */
|
||||
else if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied
|
||||
* ?! */
|
||||
elog(STOP, "heap_delete_undo: bad page LSN");
|
||||
|
||||
offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
|
||||
@@ -2337,7 +2342,7 @@ heap_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
htup->t_xmax = record->xl_xid;
|
||||
htup->t_cmax = FirstCommandId;
|
||||
htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
UnlockAndWriteBuffer(buffer);
|
||||
@@ -2350,12 +2355,12 @@ heap_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
static void
|
||||
heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_heap_insert *xlrec = (xl_heap_insert*) XLogRecGetData(record);
|
||||
Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node);
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
HeapTupleHeader htup;
|
||||
xl_heap_insert *xlrec = (xl_heap_insert *) XLogRecGetData(record);
|
||||
Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node);
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
HeapTupleHeader htup;
|
||||
|
||||
if (redo && (record->xl_info & XLR_BKP_BLOCK_1))
|
||||
return;
|
||||
@@ -2363,7 +2368,7 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
if (!RelationIsValid(reln))
|
||||
return;
|
||||
|
||||
buffer = XLogReadBuffer((redo) ? true : false, reln,
|
||||
buffer = XLogReadBuffer((redo) ? true : false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
return;
|
||||
@@ -2375,9 +2380,9 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
if (redo)
|
||||
{
|
||||
char tbuf[MaxTupleSize];
|
||||
xl_heap_header xlhdr;
|
||||
uint32 newlen;
|
||||
char tbuf[MaxTupleSize];
|
||||
xl_heap_header xlhdr;
|
||||
uint32 newlen;
|
||||
|
||||
if (record->xl_info & XLOG_HEAP_INIT_PAGE)
|
||||
{
|
||||
@@ -2396,9 +2401,9 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
elog(STOP, "heap_insert_redo: invalid max offset number");
|
||||
|
||||
newlen = record->xl_len - SizeOfHeapInsert - SizeOfHeapHeader;
|
||||
memcpy((char*)&xlhdr, (char*)xlrec + SizeOfHeapInsert, SizeOfHeapHeader);
|
||||
memcpy(tbuf + offsetof(HeapTupleHeaderData, t_bits),
|
||||
(char*)xlrec + SizeOfHeapInsert + SizeOfHeapHeader, newlen);
|
||||
memcpy((char *) &xlhdr, (char *) xlrec + SizeOfHeapInsert, SizeOfHeapHeader);
|
||||
memcpy(tbuf + offsetof(HeapTupleHeaderData, t_bits),
|
||||
(char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader, newlen);
|
||||
newlen += offsetof(HeapTupleHeaderData, t_bits);
|
||||
htup = (HeapTupleHeader) tbuf;
|
||||
htup->t_oid = xlhdr.t_oid;
|
||||
@@ -2408,19 +2413,20 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
htup->t_cmin = FirstCommandId;
|
||||
htup->t_xmax = htup->t_cmax = 0;
|
||||
htup->t_infomask = HEAP_XMAX_INVALID | xlhdr.mask;
|
||||
|
||||
offnum = PageAddItem(page, (Item)htup, newlen, offnum,
|
||||
LP_USED | OverwritePageMode);
|
||||
|
||||
offnum = PageAddItem(page, (Item) htup, newlen, offnum,
|
||||
LP_USED | OverwritePageMode);
|
||||
if (offnum == InvalidOffsetNumber)
|
||||
elog(STOP, "heap_insert_redo: failed to add tuple");
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID); /* prev sui */
|
||||
PageSetSUI(page, ThisStartUpID); /* prev sui */
|
||||
UnlockAndWriteBuffer(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* undo insert */
|
||||
if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied ?! */
|
||||
if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied
|
||||
* ?! */
|
||||
elog(STOP, "heap_insert_undo: bad page LSN");
|
||||
|
||||
elog(STOP, "heap_insert_undo: unimplemented");
|
||||
@@ -2432,16 +2438,16 @@ heap_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
static void
|
||||
heap_xlog_update(bool redo, XLogRecPtr lsn, XLogRecord *record, bool move)
|
||||
{
|
||||
xl_heap_update *xlrec = (xl_heap_update*) XLogRecGetData(record);
|
||||
Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node);
|
||||
Buffer buffer;
|
||||
bool samepage =
|
||||
(ItemPointerGetBlockNumber(&(xlrec->newtid)) ==
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
ItemId lp = NULL;
|
||||
HeapTupleHeader htup;
|
||||
xl_heap_update *xlrec = (xl_heap_update *) XLogRecGetData(record);
|
||||
Relation reln = XLogOpenRelation(redo, RM_HEAP_ID, xlrec->target.node);
|
||||
Buffer buffer;
|
||||
bool samepage =
|
||||
(ItemPointerGetBlockNumber(&(xlrec->newtid)) ==
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
ItemId lp = NULL;
|
||||
HeapTupleHeader htup;
|
||||
|
||||
if (!RelationIsValid(reln))
|
||||
return;
|
||||
@@ -2451,7 +2457,7 @@ heap_xlog_update(bool redo, XLogRecPtr lsn, XLogRecord *record, bool move)
|
||||
|
||||
/* Deal with old tuple version */
|
||||
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "heap_update_%sdo: no block", (redo) ? "re" : "un");
|
||||
@@ -2470,7 +2476,8 @@ heap_xlog_update(bool redo, XLogRecPtr lsn, XLogRecord *record, bool move)
|
||||
goto newt;
|
||||
}
|
||||
}
|
||||
else if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied ?! */
|
||||
else if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied
|
||||
* ?! */
|
||||
elog(STOP, "heap_update_undo: bad old tuple page LSN");
|
||||
|
||||
offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
|
||||
@@ -2487,7 +2494,7 @@ heap_xlog_update(bool redo, XLogRecPtr lsn, XLogRecord *record, bool move)
|
||||
if (move)
|
||||
{
|
||||
TransactionIdStore(record->xl_xid, (TransactionId *) &(htup->t_cmin));
|
||||
htup->t_infomask &=
|
||||
htup->t_infomask &=
|
||||
~(HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN);
|
||||
htup->t_infomask |= HEAP_MOVED_OFF;
|
||||
}
|
||||
@@ -2496,7 +2503,7 @@ heap_xlog_update(bool redo, XLogRecPtr lsn, XLogRecord *record, bool move)
|
||||
htup->t_xmax = record->xl_xid;
|
||||
htup->t_cmax = FirstCommandId;
|
||||
htup->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
||||
}
|
||||
if (samepage)
|
||||
goto newsame;
|
||||
@@ -2514,11 +2521,11 @@ newt:;
|
||||
|
||||
if (redo &&
|
||||
((record->xl_info & XLR_BKP_BLOCK_2) ||
|
||||
((record->xl_info & XLR_BKP_BLOCK_1) && samepage)))
|
||||
((record->xl_info & XLR_BKP_BLOCK_1) && samepage)))
|
||||
return;
|
||||
|
||||
buffer = XLogReadBuffer((redo) ? true : false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->newtid)));
|
||||
buffer = XLogReadBuffer((redo) ? true : false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->newtid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
return;
|
||||
|
||||
@@ -2531,10 +2538,10 @@ newsame:;
|
||||
|
||||
if (redo)
|
||||
{
|
||||
char tbuf[MaxTupleSize];
|
||||
xl_heap_header xlhdr;
|
||||
int hsize;
|
||||
uint32 newlen;
|
||||
char tbuf[MaxTupleSize];
|
||||
xl_heap_header xlhdr;
|
||||
int hsize;
|
||||
uint32 newlen;
|
||||
|
||||
if (record->xl_info & XLOG_HEAP_INIT_PAGE)
|
||||
{
|
||||
@@ -2557,9 +2564,9 @@ newsame:;
|
||||
hsize += (2 * sizeof(TransactionId));
|
||||
|
||||
newlen = record->xl_len - hsize;
|
||||
memcpy((char*)&xlhdr, (char*)xlrec + SizeOfHeapUpdate, SizeOfHeapHeader);
|
||||
memcpy(tbuf + offsetof(HeapTupleHeaderData, t_bits),
|
||||
(char*)xlrec + hsize, newlen);
|
||||
memcpy((char *) &xlhdr, (char *) xlrec + SizeOfHeapUpdate, SizeOfHeapHeader);
|
||||
memcpy(tbuf + offsetof(HeapTupleHeaderData, t_bits),
|
||||
(char *) xlrec + hsize, newlen);
|
||||
newlen += offsetof(HeapTupleHeaderData, t_bits);
|
||||
htup = (HeapTupleHeader) tbuf;
|
||||
htup->t_oid = xlhdr.t_oid;
|
||||
@@ -2568,13 +2575,13 @@ newsame:;
|
||||
if (move)
|
||||
{
|
||||
hsize = SizeOfHeapUpdate + SizeOfHeapHeader;
|
||||
memcpy(&(htup->t_xmax), (char*)xlrec + hsize, sizeof(TransactionId));
|
||||
memcpy(&(htup->t_xmin),
|
||||
(char*)xlrec + hsize + sizeof(TransactionId), sizeof(TransactionId));
|
||||
memcpy(&(htup->t_xmax), (char *) xlrec + hsize, sizeof(TransactionId));
|
||||
memcpy(&(htup->t_xmin),
|
||||
(char *) xlrec + hsize + sizeof(TransactionId), sizeof(TransactionId));
|
||||
TransactionIdStore(record->xl_xid, (TransactionId *) &(htup->t_cmin));
|
||||
htup->t_infomask = xlhdr.mask;
|
||||
htup->t_infomask &= ~(HEAP_XMIN_COMMITTED |
|
||||
HEAP_XMIN_INVALID | HEAP_MOVED_OFF);
|
||||
htup->t_infomask &= ~(HEAP_XMIN_COMMITTED |
|
||||
HEAP_XMIN_INVALID | HEAP_MOVED_OFF);
|
||||
htup->t_infomask |= HEAP_MOVED_IN;
|
||||
}
|
||||
else
|
||||
@@ -2584,19 +2591,20 @@ newsame:;
|
||||
htup->t_xmax = htup->t_cmax = 0;
|
||||
htup->t_infomask = HEAP_XMAX_INVALID | xlhdr.mask;
|
||||
}
|
||||
|
||||
offnum = PageAddItem(page, (Item)htup, newlen, offnum,
|
||||
LP_USED | OverwritePageMode);
|
||||
|
||||
offnum = PageAddItem(page, (Item) htup, newlen, offnum,
|
||||
LP_USED | OverwritePageMode);
|
||||
if (offnum == InvalidOffsetNumber)
|
||||
elog(STOP, "heap_update_redo: failed to add tuple");
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID); /* prev sui */
|
||||
PageSetSUI(page, ThisStartUpID); /* prev sui */
|
||||
UnlockAndWriteBuffer(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* undo */
|
||||
if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied ?! */
|
||||
if (XLByteLT(PageGetLSN(page), lsn)) /* changes are not applied
|
||||
* ?! */
|
||||
elog(STOP, "heap_update_undo: bad new tuple page LSN");
|
||||
|
||||
elog(STOP, "heap_update_undo: unimplemented");
|
||||
@@ -2606,19 +2614,19 @@ newsame:;
|
||||
static void
|
||||
_heap_unlock_tuple(void *data)
|
||||
{
|
||||
xl_heaptid *xltid = (xl_heaptid*) data;
|
||||
Relation reln = XLogOpenRelation(false, RM_HEAP_ID, xltid->node);
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
ItemId lp;
|
||||
HeapTupleHeader htup;
|
||||
xl_heaptid *xltid = (xl_heaptid *) data;
|
||||
Relation reln = XLogOpenRelation(false, RM_HEAP_ID, xltid->node);
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
OffsetNumber offnum;
|
||||
ItemId lp;
|
||||
HeapTupleHeader htup;
|
||||
|
||||
if (!RelationIsValid(reln))
|
||||
elog(STOP, "_heap_unlock_tuple: can't open relation");
|
||||
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xltid->tid)));
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xltid->tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "_heap_unlock_tuple: can't read buffer");
|
||||
|
||||
@@ -2636,8 +2644,8 @@ _heap_unlock_tuple(void *data)
|
||||
|
||||
htup = (HeapTupleHeader) PageGetItem(page, lp);
|
||||
|
||||
if (htup->t_xmax != GetCurrentTransactionId() ||
|
||||
htup->t_cmax != GetCurrentCommandId())
|
||||
if (htup->t_xmax != GetCurrentTransactionId() ||
|
||||
htup->t_cmax != GetCurrentCommandId())
|
||||
elog(STOP, "_heap_unlock_tuple: invalid xmax/cmax in rollback");
|
||||
htup->t_infomask &= ~HEAP_XMAX_UNLOGGED;
|
||||
htup->t_infomask |= HEAP_XMAX_INVALID;
|
||||
@@ -2645,9 +2653,10 @@ _heap_unlock_tuple(void *data)
|
||||
return;
|
||||
}
|
||||
|
||||
void heap_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
heap_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
info &= XLOG_HEAP_OPMASK;
|
||||
if (info == XLOG_HEAP_INSERT)
|
||||
@@ -2664,9 +2673,10 @@ void heap_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
elog(STOP, "heap_redo: unknown op code %u", info);
|
||||
}
|
||||
|
||||
void heap_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
heap_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
info &= XLOG_HEAP_OPMASK;
|
||||
if (info == XLOG_HEAP_INSERT)
|
||||
@@ -2687,46 +2697,50 @@ static void
|
||||
out_target(char *buf, xl_heaptid *target)
|
||||
{
|
||||
sprintf(buf + strlen(buf), "node %u/%u; tid %u/%u",
|
||||
target->node.tblNode, target->node.relNode,
|
||||
ItemPointerGetBlockNumber(&(target->tid)),
|
||||
ItemPointerGetOffsetNumber(&(target->tid)));
|
||||
target->node.tblNode, target->node.relNode,
|
||||
ItemPointerGetBlockNumber(&(target->tid)),
|
||||
ItemPointerGetOffsetNumber(&(target->tid)));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
heap_desc(char *buf, uint8 xl_info, char* rec)
|
||||
heap_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
info &= XLOG_HEAP_OPMASK;
|
||||
if (info == XLOG_HEAP_INSERT)
|
||||
{
|
||||
xl_heap_insert *xlrec = (xl_heap_insert*) rec;
|
||||
xl_heap_insert *xlrec = (xl_heap_insert *) rec;
|
||||
|
||||
strcat(buf, "insert: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
}
|
||||
else if (info == XLOG_HEAP_DELETE)
|
||||
{
|
||||
xl_heap_delete *xlrec = (xl_heap_delete*) rec;
|
||||
xl_heap_delete *xlrec = (xl_heap_delete *) rec;
|
||||
|
||||
strcat(buf, "delete: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
}
|
||||
else if (info == XLOG_HEAP_UPDATE || info == XLOG_HEAP_MOVE)
|
||||
{
|
||||
xl_heap_update *xlrec = (xl_heap_update*) rec;
|
||||
xl_heap_update *xlrec = (xl_heap_update *) rec;
|
||||
|
||||
if (info == XLOG_HEAP_UPDATE)
|
||||
strcat(buf, "update: ");
|
||||
else
|
||||
strcat(buf, "move: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; new %u/%u",
|
||||
ItemPointerGetBlockNumber(&(xlrec->newtid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
|
||||
ItemPointerGetBlockNumber(&(xlrec->newtid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
|
||||
}
|
||||
else if (info == XLOG_HEAP_CLEAN)
|
||||
{
|
||||
xl_heap_clean *xlrec = (xl_heap_clean*) rec;
|
||||
xl_heap_clean *xlrec = (xl_heap_clean *) rec;
|
||||
|
||||
sprintf(buf + strlen(buf), "clean: node %u/%u; blk %u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
|
||||
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
|
||||
}
|
||||
else
|
||||
strcat(buf, "UNKNOWN");
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Id: hio.c,v 1.35 2001/01/24 19:42:48 momjian Exp $
|
||||
* $Id: hio.c,v 1.36 2001/03/22 03:59:13 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "access/hio.h"
|
||||
|
||||
/*
|
||||
* RelationPutHeapTuple - place tuple at specified page
|
||||
* RelationPutHeapTuple - place tuple at specified page
|
||||
*
|
||||
* !!! ELOG(ERROR) IS DISALLOWED HERE !!!
|
||||
*
|
||||
@@ -69,7 +69,7 @@ RelationPutHeapTuple(Relation relation,
|
||||
*
|
||||
* Returns (locked) buffer with free space >= given len.
|
||||
*
|
||||
* Note that we use LockPage to lock relation for extension. We can
|
||||
* Note that we use LockPage to lock relation for extension. We can
|
||||
* do this as long as in all other places we use page-level locking
|
||||
* for indices only. Alternatively, we could define pseudo-table as
|
||||
* we do for transactions with XactLockTable.
|
||||
@@ -92,7 +92,7 @@ RelationGetBufferForTuple(Relation relation, Size len)
|
||||
*/
|
||||
if (len > MaxTupleSize)
|
||||
elog(ERROR, "Tuple is too big: size %lu, max size %ld",
|
||||
(unsigned long)len, MaxTupleSize);
|
||||
(unsigned long) len, MaxTupleSize);
|
||||
|
||||
if (!relation->rd_myxactonly)
|
||||
LockPage(relation, 0, ExclusiveLock);
|
||||
@@ -140,13 +140,13 @@ RelationGetBufferForTuple(Relation relation, Size len)
|
||||
{
|
||||
/* We should not get here given the test at the top */
|
||||
elog(STOP, "Tuple is too big: size %lu",
|
||||
(unsigned long)len);
|
||||
(unsigned long) len);
|
||||
}
|
||||
}
|
||||
|
||||
if (!relation->rd_myxactonly)
|
||||
UnlockPage(relation, 0, ExclusiveLock);
|
||||
|
||||
return(buffer);
|
||||
return (buffer);
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.17 2001/02/15 20:57:01 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.18 2001/03/22 03:59:13 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -41,12 +41,12 @@
|
||||
|
||||
#undef TOAST_DEBUG
|
||||
|
||||
static void toast_delete(Relation rel, HeapTuple oldtup);
|
||||
static void toast_delete_datum(Relation rel, Datum value);
|
||||
static void toast_insert_or_update(Relation rel, HeapTuple newtup,
|
||||
HeapTuple oldtup);
|
||||
static Datum toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value);
|
||||
static varattrib *toast_fetch_datum(varattrib *attr);
|
||||
static void toast_delete(Relation rel, HeapTuple oldtup);
|
||||
static void toast_delete_datum(Relation rel, Datum value);
|
||||
static void toast_insert_or_update(Relation rel, HeapTuple newtup,
|
||||
HeapTuple oldtup);
|
||||
static Datum toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value);
|
||||
static varattrib *toast_fetch_datum(varattrib *attr);
|
||||
|
||||
|
||||
/* ----------
|
||||
@@ -70,14 +70,14 @@ heap_tuple_toast_attrs(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
/* ----------
|
||||
* heap_tuple_fetch_attr -
|
||||
*
|
||||
* Public entry point to get back a toasted value
|
||||
* Public entry point to get back a toasted value
|
||||
* external storage (possibly still in compressed format).
|
||||
* ----------
|
||||
*/
|
||||
varattrib *
|
||||
varattrib *
|
||||
heap_tuple_fetch_attr(varattrib *attr)
|
||||
{
|
||||
varattrib *result;
|
||||
varattrib *result;
|
||||
|
||||
if (VARATT_IS_EXTERNAL(attr))
|
||||
{
|
||||
@@ -94,7 +94,7 @@ heap_tuple_fetch_attr(varattrib *attr)
|
||||
* ----------
|
||||
*/
|
||||
result = attr;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -107,10 +107,10 @@ heap_tuple_fetch_attr(varattrib *attr)
|
||||
* or external storage.
|
||||
* ----------
|
||||
*/
|
||||
varattrib *
|
||||
varattrib *
|
||||
heap_tuple_untoast_attr(varattrib *attr)
|
||||
{
|
||||
varattrib *result;
|
||||
varattrib *result;
|
||||
|
||||
if (VARATT_IS_EXTERNAL(attr))
|
||||
{
|
||||
@@ -121,14 +121,14 @@ heap_tuple_untoast_attr(varattrib *attr)
|
||||
* Fetch it from the toast heap and decompress.
|
||||
* ----------
|
||||
*/
|
||||
varattrib *tmp;
|
||||
varattrib *tmp;
|
||||
|
||||
tmp = toast_fetch_datum(attr);
|
||||
result = (varattrib *)palloc(attr->va_content.va_external.va_rawsize
|
||||
+ VARHDRSZ);
|
||||
result = (varattrib *) palloc(attr->va_content.va_external.va_rawsize
|
||||
+ VARHDRSZ);
|
||||
VARATT_SIZEP(result) = attr->va_content.va_external.va_rawsize
|
||||
+ VARHDRSZ;
|
||||
pglz_decompress((PGLZ_Header *)tmp, VARATT_DATA(result));
|
||||
+ VARHDRSZ;
|
||||
pglz_decompress((PGLZ_Header *) tmp, VARATT_DATA(result));
|
||||
|
||||
pfree(tmp);
|
||||
}
|
||||
@@ -147,11 +147,11 @@ heap_tuple_untoast_attr(varattrib *attr)
|
||||
* This is a compressed value inside of the main tuple
|
||||
* ----------
|
||||
*/
|
||||
result = (varattrib *)palloc(attr->va_content.va_compressed.va_rawsize
|
||||
+ VARHDRSZ);
|
||||
result = (varattrib *) palloc(attr->va_content.va_compressed.va_rawsize
|
||||
+ VARHDRSZ);
|
||||
VARATT_SIZEP(result) = attr->va_content.va_compressed.va_rawsize
|
||||
+ VARHDRSZ;
|
||||
pglz_decompress((PGLZ_Header *)attr, VARATT_DATA(result));
|
||||
+ VARHDRSZ;
|
||||
pglz_decompress((PGLZ_Header *) attr, VARATT_DATA(result));
|
||||
}
|
||||
else
|
||||
/* ----------
|
||||
@@ -173,21 +173,21 @@ heap_tuple_untoast_attr(varattrib *attr)
|
||||
static void
|
||||
toast_delete(Relation rel, HeapTuple oldtup)
|
||||
{
|
||||
TupleDesc tupleDesc;
|
||||
Form_pg_attribute *att;
|
||||
int numAttrs;
|
||||
int i;
|
||||
Datum value;
|
||||
bool isnull;
|
||||
TupleDesc tupleDesc;
|
||||
Form_pg_attribute *att;
|
||||
int numAttrs;
|
||||
int i;
|
||||
Datum value;
|
||||
bool isnull;
|
||||
|
||||
/* ----------
|
||||
* Get the tuple descriptor, the number of and attribute
|
||||
* descriptors.
|
||||
* ----------
|
||||
*/
|
||||
tupleDesc = rel->rd_att;
|
||||
numAttrs = tupleDesc->natts;
|
||||
att = tupleDesc->attrs;
|
||||
tupleDesc = rel->rd_att;
|
||||
numAttrs = tupleDesc->natts;
|
||||
att = tupleDesc->attrs;
|
||||
|
||||
/* ----------
|
||||
* Check for external stored attributes and delete them
|
||||
@@ -216,35 +216,35 @@ toast_delete(Relation rel, HeapTuple oldtup)
|
||||
static void
|
||||
toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
{
|
||||
TupleDesc tupleDesc;
|
||||
Form_pg_attribute *att;
|
||||
int numAttrs;
|
||||
int i;
|
||||
bool old_isnull;
|
||||
bool new_isnull;
|
||||
TupleDesc tupleDesc;
|
||||
Form_pg_attribute *att;
|
||||
int numAttrs;
|
||||
int i;
|
||||
bool old_isnull;
|
||||
bool new_isnull;
|
||||
|
||||
bool need_change = false;
|
||||
bool need_free = false;
|
||||
bool need_delold = false;
|
||||
bool has_nulls = false;
|
||||
bool need_change = false;
|
||||
bool need_free = false;
|
||||
bool need_delold = false;
|
||||
bool has_nulls = false;
|
||||
|
||||
Size maxDataLen;
|
||||
Size maxDataLen;
|
||||
|
||||
char toast_action[MaxHeapAttributeNumber];
|
||||
char toast_nulls[MaxHeapAttributeNumber];
|
||||
Datum toast_values[MaxHeapAttributeNumber];
|
||||
int32 toast_sizes[MaxHeapAttributeNumber];
|
||||
bool toast_free[MaxHeapAttributeNumber];
|
||||
bool toast_delold[MaxHeapAttributeNumber];
|
||||
char toast_action[MaxHeapAttributeNumber];
|
||||
char toast_nulls[MaxHeapAttributeNumber];
|
||||
Datum toast_values[MaxHeapAttributeNumber];
|
||||
int32 toast_sizes[MaxHeapAttributeNumber];
|
||||
bool toast_free[MaxHeapAttributeNumber];
|
||||
bool toast_delold[MaxHeapAttributeNumber];
|
||||
|
||||
/* ----------
|
||||
* Get the tuple descriptor, the number of and attribute
|
||||
* descriptors and the location of the tuple values.
|
||||
* ----------
|
||||
*/
|
||||
tupleDesc = rel->rd_att;
|
||||
numAttrs = tupleDesc->natts;
|
||||
att = tupleDesc->attrs;
|
||||
tupleDesc = rel->rd_att;
|
||||
numAttrs = tupleDesc->natts;
|
||||
att = tupleDesc->attrs;
|
||||
|
||||
/* ----------
|
||||
* Then collect information about the values given
|
||||
@@ -255,14 +255,14 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* 'x' incompressible, but OK to move off
|
||||
* ----------
|
||||
*/
|
||||
memset(toast_action, ' ', numAttrs * sizeof(char));
|
||||
memset(toast_nulls, ' ', numAttrs * sizeof(char));
|
||||
memset(toast_free, 0, numAttrs * sizeof(bool));
|
||||
memset(toast_delold, 0, numAttrs * sizeof(bool));
|
||||
memset(toast_action, ' ', numAttrs * sizeof(char));
|
||||
memset(toast_nulls, ' ', numAttrs * sizeof(char));
|
||||
memset(toast_free, 0, numAttrs * sizeof(bool));
|
||||
memset(toast_delold, 0, numAttrs * sizeof(bool));
|
||||
for (i = 0; i < numAttrs; i++)
|
||||
{
|
||||
varattrib *old_value;
|
||||
varattrib *new_value;
|
||||
varattrib *old_value;
|
||||
varattrib *new_value;
|
||||
|
||||
if (oldtup != NULL)
|
||||
{
|
||||
@@ -270,25 +270,25 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* For UPDATE get the old and new values of this attribute
|
||||
* ----------
|
||||
*/
|
||||
old_value = (varattrib *)DatumGetPointer(
|
||||
heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));
|
||||
toast_values[i] =
|
||||
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
||||
new_value = (varattrib *)DatumGetPointer(toast_values[i]);
|
||||
old_value = (varattrib *) DatumGetPointer(
|
||||
heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull));
|
||||
toast_values[i] =
|
||||
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
||||
new_value = (varattrib *) DatumGetPointer(toast_values[i]);
|
||||
|
||||
/* ----------
|
||||
* If the old value is an external stored one, check if it
|
||||
* has changed so we have to delete it later.
|
||||
* ----------
|
||||
*/
|
||||
if (!old_isnull && att[i]->attlen == -1 &&
|
||||
VARATT_IS_EXTERNAL(old_value))
|
||||
if (!old_isnull && att[i]->attlen == -1 &&
|
||||
VARATT_IS_EXTERNAL(old_value))
|
||||
{
|
||||
if (new_isnull || !VARATT_IS_EXTERNAL(new_value) ||
|
||||
old_value->va_content.va_external.va_rowid !=
|
||||
new_value->va_content.va_external.va_rowid ||
|
||||
old_value->va_content.va_external.va_attno !=
|
||||
new_value->va_content.va_external.va_attno)
|
||||
old_value->va_content.va_external.va_rowid !=
|
||||
new_value->va_content.va_external.va_rowid ||
|
||||
old_value->va_content.va_external.va_attno !=
|
||||
new_value->va_content.va_external.va_attno)
|
||||
{
|
||||
/* ----------
|
||||
* The old external store value isn't needed any
|
||||
@@ -318,8 +318,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* For INSERT simply get the new value
|
||||
* ----------
|
||||
*/
|
||||
toast_values[i] =
|
||||
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
||||
toast_values[i] =
|
||||
heap_getattr(newtup, i + 1, tupleDesc, &new_isnull);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
@@ -356,7 +356,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
if (VARATT_IS_EXTERNAL(DatumGetPointer(toast_values[i])))
|
||||
{
|
||||
toast_values[i] = PointerGetDatum(heap_tuple_untoast_attr(
|
||||
(varattrib *)DatumGetPointer(toast_values[i])));
|
||||
(varattrib *) DatumGetPointer(toast_values[i])));
|
||||
toast_free[i] = true;
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
@@ -366,7 +366,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* Remember the size of this attribute
|
||||
* ----------
|
||||
*/
|
||||
toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));
|
||||
toast_sizes[i] = VARATT_SIZE(DatumGetPointer(toast_values[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -375,7 +375,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* ----------
|
||||
*/
|
||||
toast_action[i] = 'p';
|
||||
toast_sizes[i] = att[i]->attlen;
|
||||
toast_sizes[i] = att[i]->attlen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +384,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
*
|
||||
* 1: Inline compress attributes with attstorage 'x'
|
||||
* 2: Store attributes with attstorage 'x' or 'e' external
|
||||
* 3: Inline compress attributes with attstorage 'm'
|
||||
* 3: Inline compress attributes with attstorage 'm'
|
||||
* 4: Store attributes with attstorage 'm' external
|
||||
* ----------
|
||||
*/
|
||||
@@ -398,12 +398,12 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* ----------
|
||||
*/
|
||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||
maxDataLen)
|
||||
maxDataLen)
|
||||
{
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
Datum new_value;
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
Datum new_value;
|
||||
|
||||
/* ----------
|
||||
* Search for the biggest yet uncompressed internal attribute
|
||||
@@ -420,7 +420,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
if (toast_sizes[i] > biggest_size)
|
||||
{
|
||||
biggest_attno = i;
|
||||
biggest_size = toast_sizes[i];
|
||||
biggest_size = toast_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,24 +431,28 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* Attempt to compress it inline
|
||||
* ----------
|
||||
*/
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
new_value = toast_compress_datum(old_value);
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
new_value = toast_compress_datum(old_value);
|
||||
|
||||
if (DatumGetPointer(new_value) != NULL)
|
||||
{
|
||||
/* successful compression */
|
||||
if (toast_free[i])
|
||||
pfree(DatumGetPointer(old_value));
|
||||
toast_values[i] = new_value;
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
toast_values[i] = new_value;
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* incompressible data, ignore on subsequent compression passes */
|
||||
|
||||
/*
|
||||
* incompressible data, ignore on subsequent compression
|
||||
* passes
|
||||
*/
|
||||
toast_action[i] = 'x';
|
||||
}
|
||||
}
|
||||
@@ -459,11 +463,11 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* ----------
|
||||
*/
|
||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
||||
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
||||
{
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
|
||||
/* ----------
|
||||
* Search for the biggest yet inlined attribute with
|
||||
@@ -481,7 +485,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
if (toast_sizes[i] > biggest_size)
|
||||
{
|
||||
biggest_attno = i;
|
||||
biggest_size = toast_sizes[i];
|
||||
biggest_size = toast_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,21 +496,21 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* Store this external
|
||||
* ----------
|
||||
*/
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
toast_action[i] = 'p';
|
||||
toast_values[i] = toast_save_datum(rel,
|
||||
newtup->t_data->t_oid,
|
||||
i + 1,
|
||||
toast_values[i]);
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
toast_action[i] = 'p';
|
||||
toast_values[i] = toast_save_datum(rel,
|
||||
newtup->t_data->t_oid,
|
||||
i + 1,
|
||||
toast_values[i]);
|
||||
if (toast_free[i])
|
||||
pfree(DatumGetPointer(old_value));
|
||||
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
need_free = true;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
@@ -515,12 +519,12 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* ----------
|
||||
*/
|
||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||
maxDataLen)
|
||||
maxDataLen)
|
||||
{
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
Datum new_value;
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
Datum new_value;
|
||||
|
||||
/* ----------
|
||||
* Search for the biggest yet uncompressed internal attribute
|
||||
@@ -537,7 +541,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
if (toast_sizes[i] > biggest_size)
|
||||
{
|
||||
biggest_attno = i;
|
||||
biggest_size = toast_sizes[i];
|
||||
biggest_size = toast_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,24 +552,28 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* Attempt to compress it inline
|
||||
* ----------
|
||||
*/
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
new_value = toast_compress_datum(old_value);
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
new_value = toast_compress_datum(old_value);
|
||||
|
||||
if (DatumGetPointer(new_value) != NULL)
|
||||
{
|
||||
/* successful compression */
|
||||
if (toast_free[i])
|
||||
pfree(DatumGetPointer(old_value));
|
||||
toast_values[i] = new_value;
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
toast_values[i] = new_value;
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* incompressible data, ignore on subsequent compression passes */
|
||||
|
||||
/*
|
||||
* incompressible data, ignore on subsequent compression
|
||||
* passes
|
||||
*/
|
||||
toast_action[i] = 'x';
|
||||
}
|
||||
}
|
||||
@@ -575,11 +583,11 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* ----------
|
||||
*/
|
||||
while (MAXALIGN(ComputeDataSize(tupleDesc, toast_values, toast_nulls)) >
|
||||
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
||||
maxDataLen && rel->rd_rel->reltoastrelid != InvalidOid)
|
||||
{
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
int biggest_attno = -1;
|
||||
int32 biggest_size = MAXALIGN(sizeof(varattrib));
|
||||
Datum old_value;
|
||||
|
||||
/* ----------
|
||||
* Search for the biggest yet inlined attribute with
|
||||
@@ -597,7 +605,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
if (toast_sizes[i] > biggest_size)
|
||||
{
|
||||
biggest_attno = i;
|
||||
biggest_size = toast_sizes[i];
|
||||
biggest_size = toast_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,21 +616,21 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* Store this external
|
||||
* ----------
|
||||
*/
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
toast_action[i] = 'p';
|
||||
toast_values[i] = toast_save_datum(rel,
|
||||
newtup->t_data->t_oid,
|
||||
i + 1,
|
||||
toast_values[i]);
|
||||
i = biggest_attno;
|
||||
old_value = toast_values[i];
|
||||
toast_action[i] = 'p';
|
||||
toast_values[i] = toast_save_datum(rel,
|
||||
newtup->t_data->t_oid,
|
||||
i + 1,
|
||||
toast_values[i]);
|
||||
if (toast_free[i])
|
||||
pfree(DatumGetPointer(old_value));
|
||||
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
toast_free[i] = true;
|
||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||
|
||||
need_change = true;
|
||||
need_free = true;
|
||||
need_free = true;
|
||||
}
|
||||
|
||||
/* ----------
|
||||
@@ -632,10 +640,10 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
*/
|
||||
if (need_change)
|
||||
{
|
||||
char *new_data;
|
||||
int32 new_len;
|
||||
MemoryContext oldcxt;
|
||||
HeapTupleHeader olddata;
|
||||
char *new_data;
|
||||
int32 new_len;
|
||||
MemoryContext oldcxt;
|
||||
HeapTupleHeader olddata;
|
||||
|
||||
/* ----------
|
||||
* Calculate the new size of the tuple
|
||||
@@ -662,24 +670,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
* ----------
|
||||
*/
|
||||
memcpy(new_data, newtup->t_data, newtup->t_data->t_hoff);
|
||||
newtup->t_data = (HeapTupleHeader)new_data;
|
||||
newtup->t_data = (HeapTupleHeader) new_data;
|
||||
newtup->t_len = new_len;
|
||||
|
||||
DataFill((char *)(MAXALIGN((long)new_data +
|
||||
offsetof(HeapTupleHeaderData, t_bits) +
|
||||
((has_nulls) ? BITMAPLEN(numAttrs) : 0))),
|
||||
tupleDesc,
|
||||
toast_values,
|
||||
toast_nulls,
|
||||
&(newtup->t_data->t_infomask),
|
||||
has_nulls ? newtup->t_data->t_bits : NULL);
|
||||
DataFill((char *) (MAXALIGN((long) new_data +
|
||||
offsetof(HeapTupleHeaderData, t_bits) +
|
||||
((has_nulls) ? BITMAPLEN(numAttrs) : 0))),
|
||||
tupleDesc,
|
||||
toast_values,
|
||||
toast_nulls,
|
||||
&(newtup->t_data->t_infomask),
|
||||
has_nulls ? newtup->t_data->t_bits : NULL);
|
||||
|
||||
/* ----------
|
||||
* In the case we modified a previously modified tuple again,
|
||||
* free the memory from the previous run
|
||||
* ----------
|
||||
*/
|
||||
if ((char *)olddata != ((char *)newtup + HEAPTUPLESIZE))
|
||||
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
||||
pfree(olddata);
|
||||
|
||||
/* ----------
|
||||
@@ -723,7 +731,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||
Datum
|
||||
toast_compress_datum(Datum value)
|
||||
{
|
||||
varattrib *tmp;
|
||||
varattrib *tmp;
|
||||
|
||||
tmp = (varattrib *) palloc(sizeof(PGLZ_Header) + VARATT_SIZE(value));
|
||||
pglz_compress(VARATT_DATA(value), VARATT_SIZE(value) - VARHDRSZ,
|
||||
@@ -754,45 +762,45 @@ toast_compress_datum(Datum value)
|
||||
static Datum
|
||||
toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
||||
{
|
||||
Relation toastrel;
|
||||
Relation toastidx;
|
||||
HeapTuple toasttup;
|
||||
InsertIndexResult idxres;
|
||||
TupleDesc toasttupDesc;
|
||||
Datum t_values[3];
|
||||
char t_nulls[3];
|
||||
varattrib *result;
|
||||
char chunk_data[VARHDRSZ + TOAST_MAX_CHUNK_SIZE];
|
||||
int32 chunk_size;
|
||||
int32 chunk_seq = 0;
|
||||
char *data_p;
|
||||
int32 data_todo;
|
||||
Relation toastrel;
|
||||
Relation toastidx;
|
||||
HeapTuple toasttup;
|
||||
InsertIndexResult idxres;
|
||||
TupleDesc toasttupDesc;
|
||||
Datum t_values[3];
|
||||
char t_nulls[3];
|
||||
varattrib *result;
|
||||
char chunk_data[VARHDRSZ + TOAST_MAX_CHUNK_SIZE];
|
||||
int32 chunk_size;
|
||||
int32 chunk_seq = 0;
|
||||
char *data_p;
|
||||
int32 data_todo;
|
||||
|
||||
/* ----------
|
||||
* Create the varattrib reference
|
||||
* ----------
|
||||
*/
|
||||
result = (varattrib *)palloc(sizeof(varattrib));
|
||||
result = (varattrib *) palloc(sizeof(varattrib));
|
||||
|
||||
result->va_header = sizeof(varattrib) | VARATT_FLAG_EXTERNAL;
|
||||
result->va_header = sizeof(varattrib) | VARATT_FLAG_EXTERNAL;
|
||||
if (VARATT_IS_COMPRESSED(value))
|
||||
{
|
||||
result->va_header |= VARATT_FLAG_COMPRESSED;
|
||||
result->va_content.va_external.va_rawsize =
|
||||
((varattrib *)value)->va_content.va_compressed.va_rawsize;
|
||||
result->va_content.va_external.va_rawsize =
|
||||
((varattrib *) value)->va_content.va_compressed.va_rawsize;
|
||||
}
|
||||
else
|
||||
result->va_content.va_external.va_rawsize = VARATT_SIZE(value);
|
||||
|
||||
result->va_content.va_external.va_extsize =
|
||||
VARATT_SIZE(value) - VARHDRSZ;
|
||||
result->va_content.va_external.va_valueid = newoid();
|
||||
result->va_content.va_external.va_toastrelid =
|
||||
rel->rd_rel->reltoastrelid;
|
||||
result->va_content.va_external.va_toastidxid =
|
||||
rel->rd_rel->reltoastidxid;
|
||||
result->va_content.va_external.va_rowid = mainoid;
|
||||
result->va_content.va_external.va_attno = attno;
|
||||
|
||||
result->va_content.va_external.va_extsize =
|
||||
VARATT_SIZE(value) - VARHDRSZ;
|
||||
result->va_content.va_external.va_valueid = newoid();
|
||||
result->va_content.va_external.va_toastrelid =
|
||||
rel->rd_rel->reltoastrelid;
|
||||
result->va_content.va_external.va_toastidxid =
|
||||
rel->rd_rel->reltoastidxid;
|
||||
result->va_content.va_external.va_rowid = mainoid;
|
||||
result->va_content.va_external.va_attno = attno;
|
||||
|
||||
/* ----------
|
||||
* Initialize constant parts of the tuple data
|
||||
@@ -808,8 +816,8 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
||||
* Get the data to process
|
||||
* ----------
|
||||
*/
|
||||
data_p = VARATT_DATA(value);
|
||||
data_todo = VARATT_SIZE(value) - VARHDRSZ;
|
||||
data_p = VARATT_DATA(value);
|
||||
data_todo = VARATT_SIZE(value) - VARHDRSZ;
|
||||
|
||||
/* ----------
|
||||
* Open the toast relation
|
||||
@@ -818,9 +826,9 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
||||
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
||||
toasttupDesc = toastrel->rd_att;
|
||||
toastidx = index_open(rel->rd_rel->reltoastidxid);
|
||||
|
||||
|
||||
/* ----------
|
||||
* Split up the item into chunks
|
||||
* Split up the item into chunks
|
||||
* ----------
|
||||
*/
|
||||
while (data_todo > 0)
|
||||
@@ -848,8 +856,8 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
||||
*/
|
||||
heap_insert(toastrel, toasttup);
|
||||
idxres = index_insert(toastidx, t_values, t_nulls,
|
||||
&(toasttup->t_self),
|
||||
toastrel);
|
||||
&(toasttup->t_self),
|
||||
toastrel);
|
||||
if (idxres == NULL)
|
||||
elog(ERROR, "Failed to insert index entry for TOAST tuple");
|
||||
|
||||
@@ -888,14 +896,14 @@ toast_save_datum(Relation rel, Oid mainoid, int16 attno, Datum value)
|
||||
static void
|
||||
toast_delete_datum(Relation rel, Datum value)
|
||||
{
|
||||
register varattrib *attr = (varattrib *)value;
|
||||
Relation toastrel;
|
||||
Relation toastidx;
|
||||
ScanKeyData toastkey;
|
||||
IndexScanDesc toastscan;
|
||||
HeapTupleData toasttup;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
register varattrib *attr = (varattrib *) value;
|
||||
Relation toastrel;
|
||||
Relation toastidx;
|
||||
ScanKeyData toastkey;
|
||||
IndexScanDesc toastscan;
|
||||
HeapTupleData toasttup;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
|
||||
if (!VARATT_IS_EXTERNAL(attr))
|
||||
return;
|
||||
@@ -904,8 +912,8 @@ toast_delete_datum(Relation rel, Datum value)
|
||||
* Open the toast relation and it's index
|
||||
* ----------
|
||||
*/
|
||||
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
||||
RowExclusiveLock);
|
||||
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
||||
RowExclusiveLock);
|
||||
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
|
||||
|
||||
/* ----------
|
||||
@@ -913,10 +921,10 @@ toast_delete_datum(Relation rel, Datum value)
|
||||
* ----------
|
||||
*/
|
||||
ScanKeyEntryInitialize(&toastkey,
|
||||
(bits16) 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
(bits16) 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
|
||||
/* ----------
|
||||
* Read the chunks by index
|
||||
@@ -961,36 +969,36 @@ toast_delete_datum(Relation rel, Datum value)
|
||||
static varattrib *
|
||||
toast_fetch_datum(varattrib *attr)
|
||||
{
|
||||
Relation toastrel;
|
||||
Relation toastidx;
|
||||
ScanKeyData toastkey;
|
||||
IndexScanDesc toastscan;
|
||||
HeapTupleData toasttup;
|
||||
HeapTuple ttup;
|
||||
TupleDesc toasttupDesc;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
Relation toastrel;
|
||||
Relation toastidx;
|
||||
ScanKeyData toastkey;
|
||||
IndexScanDesc toastscan;
|
||||
HeapTupleData toasttup;
|
||||
HeapTuple ttup;
|
||||
TupleDesc toasttupDesc;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
|
||||
varattrib *result;
|
||||
int32 ressize;
|
||||
int32 residx;
|
||||
int numchunks;
|
||||
Pointer chunk;
|
||||
bool isnull;
|
||||
int32 chunksize;
|
||||
varattrib *result;
|
||||
int32 ressize;
|
||||
int32 residx;
|
||||
int numchunks;
|
||||
Pointer chunk;
|
||||
bool isnull;
|
||||
int32 chunksize;
|
||||
|
||||
char *chunks_found;
|
||||
char *chunks_expected;
|
||||
char *chunks_found;
|
||||
char *chunks_expected;
|
||||
|
||||
ressize = attr->va_content.va_external.va_extsize;
|
||||
numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
|
||||
numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
|
||||
|
||||
chunks_found = palloc(numchunks);
|
||||
chunks_found = palloc(numchunks);
|
||||
chunks_expected = palloc(numchunks);
|
||||
memset(chunks_found, 0, numchunks);
|
||||
memset(chunks_found, 0, numchunks);
|
||||
memset(chunks_expected, 1, numchunks);
|
||||
|
||||
result = (varattrib *)palloc(ressize + VARHDRSZ);
|
||||
result = (varattrib *) palloc(ressize + VARHDRSZ);
|
||||
VARATT_SIZEP(result) = ressize + VARHDRSZ;
|
||||
if (VARATT_IS_COMPRESSED(attr))
|
||||
VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
|
||||
@@ -999,8 +1007,8 @@ toast_fetch_datum(varattrib *attr)
|
||||
* Open the toast relation and it's index
|
||||
* ----------
|
||||
*/
|
||||
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
||||
AccessShareLock);
|
||||
toastrel = heap_open(attr->va_content.va_external.va_toastrelid,
|
||||
AccessShareLock);
|
||||
toasttupDesc = toastrel->rd_att;
|
||||
toastidx = index_open(attr->va_content.va_external.va_toastidxid);
|
||||
|
||||
@@ -1009,10 +1017,10 @@ toast_fetch_datum(varattrib *attr)
|
||||
* ----------
|
||||
*/
|
||||
ScanKeyEntryInitialize(&toastkey,
|
||||
(bits16) 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
(bits16) 0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) F_OIDEQ,
|
||||
ObjectIdGetDatum(attr->va_content.va_external.va_valueid));
|
||||
|
||||
/* ----------
|
||||
* Read the chunks by index
|
||||
@@ -1049,7 +1057,7 @@ toast_fetch_datum(varattrib *attr)
|
||||
elog(ERROR, "unexpected chunk number %d for toast value %d",
|
||||
residx,
|
||||
attr->va_content.va_external.va_valueid);
|
||||
if (residx < numchunks-1)
|
||||
if (residx < numchunks - 1)
|
||||
{
|
||||
if (chunksize != TOAST_MAX_CHUNK_SIZE)
|
||||
elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %d",
|
||||
@@ -1072,7 +1080,7 @@ toast_fetch_datum(varattrib *attr)
|
||||
* Copy the data into proper place in our result
|
||||
* ----------
|
||||
*/
|
||||
memcpy(((char *)VARATT_DATA(result)) + residx * TOAST_MAX_CHUNK_SIZE,
|
||||
memcpy(((char *) VARATT_DATA(result)) + residx * TOAST_MAX_CHUNK_SIZE,
|
||||
VARATT_DATA(chunk),
|
||||
chunksize);
|
||||
|
||||
@@ -1085,7 +1093,7 @@ toast_fetch_datum(varattrib *attr)
|
||||
*/
|
||||
if (memcmp(chunks_found, chunks_expected, numchunks) != 0)
|
||||
elog(ERROR, "not all toast chunks found for value %d",
|
||||
attr->va_content.va_external.va_valueid);
|
||||
attr->va_content.va_external.va_valueid);
|
||||
pfree(chunks_expected);
|
||||
pfree(chunks_found);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.48 2001/01/24 19:42:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.49 2001/03/22 03:59:13 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -239,8 +239,8 @@ StrategyTermEvaluate(StrategyTerm term,
|
||||
break;
|
||||
|
||||
case SK_NEGATE:
|
||||
result = ! DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
left, right));
|
||||
result = !DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
left, right));
|
||||
break;
|
||||
|
||||
case SK_COMMUTE:
|
||||
@@ -249,8 +249,8 @@ StrategyTermEvaluate(StrategyTerm term,
|
||||
break;
|
||||
|
||||
case SK_NEGATE | SK_COMMUTE:
|
||||
result = ! DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
right, left));
|
||||
result = !DatumGetBool(FunctionCall2(&entry->sk_func,
|
||||
right, left));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -263,6 +263,7 @@ StrategyTermEvaluate(StrategyTerm term,
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@@ -465,6 +466,7 @@ RelationInvokeStrategy(Relation relation,
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@@ -519,7 +521,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
|
||||
|
||||
if (!RegProcedureIsValid(entry->sk_procedure))
|
||||
elog(ERROR,
|
||||
"OperatorRelationFillScanKeyEntry: no procedure for operator %u",
|
||||
"OperatorRelationFillScanKeyEntry: no procedure for operator %u",
|
||||
operatorObjectId);
|
||||
|
||||
fmgr_info(entry->sk_procedure, &entry->sk_func);
|
||||
@@ -597,9 +599,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
|
||||
}
|
||||
|
||||
if (cachesearch)
|
||||
{
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
heap_endscan(scan);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.40 2001/01/24 19:42:48 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.41 2001/03/22 03:59:14 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@@ -150,8 +150,8 @@ btoidvectorcmp(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btabstimecmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
AbsoluteTime a = PG_GETARG_ABSOLUTETIME(0);
|
||||
AbsoluteTime b = PG_GETARG_ABSOLUTETIME(1);
|
||||
AbsoluteTime a = PG_GETARG_ABSOLUTETIME(0);
|
||||
AbsoluteTime b = PG_GETARG_ABSOLUTETIME(1);
|
||||
|
||||
if (AbsoluteTimeIsBefore(a, b))
|
||||
PG_RETURN_INT32(-1);
|
||||
@@ -236,9 +236,10 @@ bttextcmp(PG_FUNCTION_ARGS)
|
||||
|
||||
if (res == 0 && VARSIZE(a) != VARSIZE(b))
|
||||
{
|
||||
|
||||
/*
|
||||
* The two strings are the same in the first len bytes,
|
||||
* and they are of different lengths.
|
||||
* The two strings are the same in the first len bytes, and they
|
||||
* are of different lengths.
|
||||
*/
|
||||
if (VARSIZE(a) < VARSIZE(b))
|
||||
res = -1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.50 2001/02/07 23:35:33 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.51 2001/03/22 03:59:14 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "miscadmin.h"
|
||||
#include "storage/lmgr.h"
|
||||
|
||||
extern bool FixBTree; /* comments in nbtree.c */
|
||||
extern bool FixBTree; /* comments in nbtree.c */
|
||||
extern Buffer _bt_fixroot(Relation rel, Buffer oldrootbuf, bool release);
|
||||
|
||||
/*
|
||||
@@ -100,7 +100,7 @@ _bt_metapinit(Relation rel)
|
||||
*
|
||||
* The access type parameter (BT_READ or BT_WRITE) controls whether
|
||||
* a new root page will be created or not. If access = BT_READ,
|
||||
* and no root page exists, we just return InvalidBuffer. For
|
||||
* and no root page exists, we just return InvalidBuffer. For
|
||||
* BT_WRITE, we try to create the root page if it doesn't exist.
|
||||
* NOTE that the returned root page will have only a read lock set
|
||||
* on it even if access = BT_WRITE!
|
||||
@@ -178,20 +178,20 @@ _bt_getroot(Relation rel, int access)
|
||||
|
||||
/* XLOG stuff */
|
||||
{
|
||||
xl_btree_newroot xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata;
|
||||
xl_btree_newroot xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata;
|
||||
|
||||
xlrec.node = rel->rd_node;
|
||||
xlrec.level = 1;
|
||||
BlockIdSet(&(xlrec.rootblk), rootblkno);
|
||||
rdata.buffer = InvalidBuffer;
|
||||
rdata.data = (char*)&xlrec;
|
||||
rdata.data = (char *) &xlrec;
|
||||
rdata.len = SizeOfBtreeNewroot;
|
||||
rdata.next = NULL;
|
||||
|
||||
recptr = XLogInsert(RM_BTREE_ID,
|
||||
XLOG_BTREE_NEWROOT|XLOG_BTREE_LEAF, &rdata);
|
||||
XLOG_BTREE_NEWROOT | XLOG_BTREE_LEAF, &rdata);
|
||||
|
||||
PageSetLSN(rootpage, recptr);
|
||||
PageSetSUI(rootpage, ThisStartUpID);
|
||||
@@ -212,6 +212,7 @@ _bt_getroot(Relation rel, int access)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Metadata initialized by someone else. In order to
|
||||
* guarantee no deadlocks, we have to release the metadata
|
||||
@@ -232,30 +233,31 @@ _bt_getroot(Relation rel, int access)
|
||||
/*
|
||||
* Race condition: If the root page split between the time we looked
|
||||
* at the metadata page and got the root buffer, then we got the wrong
|
||||
* buffer. Release it and try again.
|
||||
* buffer. Release it and try again.
|
||||
*/
|
||||
rootpage = BufferGetPage(rootbuf);
|
||||
rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
|
||||
|
||||
if (! P_ISROOT(rootopaque))
|
||||
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 again and again.
|
||||
* It happened, but if root page splitter failed to create new
|
||||
* root page then we'll go in loop trying to call _bt_getroot
|
||||
* again and again.
|
||||
*/
|
||||
if (FixBTree)
|
||||
{
|
||||
Buffer newrootbuf;
|
||||
Buffer newrootbuf;
|
||||
|
||||
check_parent:;
|
||||
if (BTreeInvalidParent(rootopaque)) /* unupdated! */
|
||||
check_parent:;
|
||||
if (BTreeInvalidParent(rootopaque)) /* unupdated! */
|
||||
{
|
||||
LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);
|
||||
LockBuffer(rootbuf, BT_WRITE);
|
||||
|
||||
/* handle concurrent fix of root page */
|
||||
if (BTreeInvalidParent(rootopaque)) /* unupdated! */
|
||||
if (BTreeInvalidParent(rootopaque)) /* unupdated! */
|
||||
{
|
||||
elog(NOTICE, "bt_getroot[%s]: fixing root page", RelationGetRelationName(rel));
|
||||
newrootbuf = _bt_fixroot(rel, rootbuf, true);
|
||||
@@ -266,20 +268,22 @@ check_parent:;
|
||||
rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
|
||||
/* New root might be splitted while changing lock */
|
||||
if (P_ISROOT(rootopaque))
|
||||
return(rootbuf);
|
||||
return (rootbuf);
|
||||
/* rootbuf is read locked */
|
||||
goto check_parent;
|
||||
}
|
||||
else /* someone else already fixed root */
|
||||
else
|
||||
/* someone else already fixed root */
|
||||
{
|
||||
LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);
|
||||
LockBuffer(rootbuf, BT_READ);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ok, here we have old root page with btpo_parent pointing
|
||||
* to upper level - check parent page because of there is
|
||||
* good chance that parent is root page.
|
||||
* Ok, here we have old root page with btpo_parent pointing to
|
||||
* upper level - check parent page because of there is good
|
||||
* chance that parent is root page.
|
||||
*/
|
||||
newrootbuf = _bt_getbuf(rel, rootopaque->btpo_parent, BT_READ);
|
||||
_bt_relbuf(rel, rootbuf, BT_READ);
|
||||
@@ -287,7 +291,7 @@ check_parent:;
|
||||
rootpage = BufferGetPage(rootbuf);
|
||||
rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);
|
||||
if (P_ISROOT(rootopaque))
|
||||
return(rootbuf);
|
||||
return (rootbuf);
|
||||
/* no luck -:( */
|
||||
}
|
||||
|
||||
@@ -366,7 +370,7 @@ _bt_relbuf(Relation rel, Buffer buf, int access)
|
||||
* and a pin on the buffer.
|
||||
*
|
||||
* NOTE: actually, the buffer manager just marks the shared buffer page
|
||||
* dirty here, the real I/O happens later. Since we can't persuade the
|
||||
* dirty here, the real I/O happens later. Since we can't persuade the
|
||||
* Unix kernel to schedule disk writes in a particular order, there's not
|
||||
* much point in worrying about this. The most we can say is that all the
|
||||
* writes will occur before commit.
|
||||
@@ -468,14 +472,14 @@ _bt_pagedel(Relation rel, ItemPointer tid)
|
||||
PageIndexTupleDelete(page, offno);
|
||||
/* XLOG stuff */
|
||||
{
|
||||
xl_btree_delete xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
xl_btree_delete xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
|
||||
xlrec.target.node = rel->rd_node;
|
||||
xlrec.target.tid = *tid;
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = SizeOfBtreeDelete;
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
|
||||
@@ -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.78 2001/02/07 23:35:33 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.79 2001/03/22 03:59:15 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -30,7 +30,8 @@
|
||||
|
||||
bool BuildingBtree = false; /* see comment in btbuild() */
|
||||
bool FastBuild = true; /* use sort/build instead */
|
||||
/* of insertion build */
|
||||
|
||||
/* of insertion build */
|
||||
|
||||
|
||||
/*
|
||||
@@ -52,12 +53,14 @@ static void _bt_restscan(IndexScanDesc scan);
|
||||
Datum
|
||||
btbuild(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
Node *oldPred = (Node *) PG_GETARG_POINTER(3);
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
Node *oldPred = (Node *) PG_GETARG_POINTER(3);
|
||||
|
||||
#ifdef NOT_USED
|
||||
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
|
||||
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
|
||||
|
||||
#endif
|
||||
HeapScanDesc hscan;
|
||||
HeapTuple htup;
|
||||
@@ -69,9 +72,11 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
int nhtups,
|
||||
nitups;
|
||||
Node *pred = indexInfo->ii_Predicate;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
TupleTable tupleTable;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
#endif
|
||||
ExprContext *econtext;
|
||||
InsertIndexResult res = NULL;
|
||||
@@ -79,15 +84,16 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
BTItem btitem;
|
||||
bool usefast;
|
||||
Snapshot snapshot;
|
||||
TransactionId XmaxRecent;
|
||||
TransactionId XmaxRecent;
|
||||
|
||||
/*
|
||||
* spool2 is needed only when the index is an unique index.
|
||||
* Dead tuples are put into spool2 instead of spool in
|
||||
* order to avoid uniqueness check.
|
||||
* spool2 is needed only when the index is an unique index. Dead
|
||||
* tuples are put into spool2 instead of spool in order to avoid
|
||||
* uniqueness check.
|
||||
*/
|
||||
BTSpool *spool2 = NULL;
|
||||
BTSpool *spool2 = NULL;
|
||||
bool tupleIsAlive;
|
||||
int dead_count;
|
||||
int dead_count;
|
||||
|
||||
/* note that this is a new btree */
|
||||
BuildingBtree = true;
|
||||
@@ -103,7 +109,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
#ifdef BTREE_BUILD_STATS
|
||||
if (Show_btree_build_stats)
|
||||
ResetUsage();
|
||||
#endif /* BTREE_BUILD_STATS */
|
||||
#endif /* BTREE_BUILD_STATS */
|
||||
|
||||
/* initialize the btree index metadata page (if this is a new index) */
|
||||
if (oldPred == NULL)
|
||||
@@ -155,10 +161,10 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
if (usefast)
|
||||
{
|
||||
spool = _bt_spoolinit(index, indexInfo->ii_Unique);
|
||||
|
||||
/*
|
||||
* Different from spool,the uniqueness isn't checked
|
||||
* for spool2.
|
||||
*/
|
||||
* Different from spool,the uniqueness isn't checked for spool2.
|
||||
*/
|
||||
if (indexInfo->ii_Unique)
|
||||
spool2 = _bt_spoolinit(index, false);
|
||||
}
|
||||
@@ -187,12 +193,13 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
}
|
||||
else
|
||||
tupleIsAlive = true;
|
||||
|
||||
|
||||
MemoryContextReset(econtext->ecxt_per_tuple_memory);
|
||||
|
||||
nhtups++;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
|
||||
/*
|
||||
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
|
||||
* this tuple if it was already in the existing partial index
|
||||
@@ -253,8 +260,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
* btree pages - NULLs greater NOT_NULLs and NULL = NULL is TRUE.
|
||||
* Sure, it's just rule for placing/finding items and no more -
|
||||
* keytest'll return FALSE for a = 5 for items having 'a' isNULL.
|
||||
* Look at _bt_compare for how it works.
|
||||
* - vadim 03/23/97
|
||||
* Look at _bt_compare for how it works. - vadim 03/23/97
|
||||
*
|
||||
* if (itup->t_info & INDEX_NULL_MASK) { pfree(itup); continue; }
|
||||
*/
|
||||
@@ -271,7 +277,8 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (tupleIsAlive || !spool2)
|
||||
_bt_spool(btitem, spool);
|
||||
else /* dead tuples are put into spool2 */
|
||||
else
|
||||
/* dead tuples are put into spool2 */
|
||||
{
|
||||
dead_count++;
|
||||
_bt_spool(btitem, spool2);
|
||||
@@ -288,7 +295,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
|
||||
/* okay, all heap tuples are indexed */
|
||||
heap_endscan(hscan);
|
||||
if (spool2 && !dead_count) /* spool2 was found to be unnecessary */
|
||||
if (spool2 && !dead_count) /* spool2 was found to be unnecessary */
|
||||
{
|
||||
_bt_spooldestroy(spool2);
|
||||
spool2 = NULL;
|
||||
@@ -296,9 +303,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
if (pred != NULL || oldPred != NULL)
|
||||
{
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
}
|
||||
#endif /* OMIT_PARTIAL_INDEX */
|
||||
FreeExprContext(econtext);
|
||||
|
||||
@@ -322,7 +327,7 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
ShowUsage();
|
||||
ResetUsage();
|
||||
}
|
||||
#endif /* BTREE_BUILD_STATS */
|
||||
#endif /* BTREE_BUILD_STATS */
|
||||
|
||||
/*
|
||||
* Since we just counted the tuples in the heap, we update its stats
|
||||
@@ -368,11 +373,11 @@ btbuild(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btinsert(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
|
||||
char *nulls = (char *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
|
||||
char *nulls = (char *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
InsertIndexResult res;
|
||||
BTItem btitem;
|
||||
IndexTuple itup;
|
||||
@@ -396,8 +401,8 @@ btinsert(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btgettuple(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
RetrieveIndexResult res;
|
||||
|
||||
/*
|
||||
@@ -408,10 +413,11 @@ 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 buffer, too.
|
||||
* to btgettuple(). _bt_restscan() re-grabs the read lock on the
|
||||
* buffer, too.
|
||||
*/
|
||||
_bt_restscan(scan);
|
||||
res = _bt_next(scan, dir);
|
||||
@@ -421,8 +427,8 @@ 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!
|
||||
* lock on the buffer so that we aren't blocking other backends. NOTE:
|
||||
* we do keep the pin on the buffer!
|
||||
*/
|
||||
if (res)
|
||||
{
|
||||
@@ -461,11 +467,13 @@ btbeginscan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btrescan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
|
||||
#ifdef NOT_USED /* XXX surely it's wrong to ignore this? */
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
|
||||
#endif
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
|
||||
ItemPointer iptr;
|
||||
BTScanOpaque so;
|
||||
|
||||
@@ -540,7 +548,7 @@ btmovescan(IndexScanDesc scan, Datum v)
|
||||
Datum
|
||||
btendscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer iptr;
|
||||
BTScanOpaque so;
|
||||
|
||||
@@ -578,7 +586,7 @@ btendscan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btmarkpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer iptr;
|
||||
BTScanOpaque so;
|
||||
|
||||
@@ -610,7 +618,7 @@ btmarkpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btrestrpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ItemPointer iptr;
|
||||
BTScanOpaque so;
|
||||
|
||||
@@ -640,8 +648,8 @@ btrestrpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
btdelete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||
ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
|
||||
/* adjust any active scans that will be affected by this deletion */
|
||||
_bt_adjscans(rel, tid);
|
||||
@@ -671,8 +679,8 @@ _bt_restscan(IndexScanDesc scan)
|
||||
BlockNumber blkno;
|
||||
|
||||
/*
|
||||
* Get back the read lock we were holding on the buffer.
|
||||
* (We still have a reference-count pin on it, though.)
|
||||
* Get back the read lock we were holding on the buffer. (We still
|
||||
* have a reference-count pin on it, though.)
|
||||
*/
|
||||
LockBuffer(buf, BT_READ);
|
||||
|
||||
@@ -689,13 +697,13 @@ _bt_restscan(IndexScanDesc scan)
|
||||
if (!ItemPointerIsValid(&target))
|
||||
{
|
||||
ItemPointerSetOffsetNumber(current,
|
||||
OffsetNumberPrev(P_FIRSTDATAKEY(opaque)));
|
||||
OffsetNumberPrev(P_FIRSTDATAKEY(opaque)));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The item we were on may have moved right due to insertions.
|
||||
* Find it again.
|
||||
* The item we were on may have moved right due to insertions. Find it
|
||||
* again.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
@@ -717,7 +725,8 @@ _bt_restscan(IndexScanDesc scan)
|
||||
}
|
||||
|
||||
/*
|
||||
* By here, the item we're looking for moved right at least one page
|
||||
* By here, the item we're looking for moved right at least one
|
||||
* page
|
||||
*/
|
||||
if (P_RIGHTMOST(opaque))
|
||||
elog(FATAL, "_bt_restscan: my bits moved right off the end of the world!"
|
||||
@@ -742,14 +751,14 @@ _bt_restore_page(Page page, char *from, int len)
|
||||
Size itemsz;
|
||||
char *end = from + len;
|
||||
|
||||
for ( ; from < end; )
|
||||
for (; from < end;)
|
||||
{
|
||||
memcpy(&btdata, from, sizeof(BTItemData));
|
||||
itemsz = IndexTupleDSize(btdata.bti_itup) +
|
||||
(sizeof(BTItemData) - sizeof(IndexTupleData));
|
||||
(sizeof(BTItemData) - sizeof(IndexTupleData));
|
||||
itemsz = MAXALIGN(itemsz);
|
||||
if (PageAddItem(page, (Item) from, itemsz,
|
||||
FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(STOP, "_bt_restore_page: can't add item to page");
|
||||
from += itemsz;
|
||||
}
|
||||
@@ -758,20 +767,20 @@ _bt_restore_page(Page page, char *from, int len)
|
||||
static void
|
||||
btree_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_btree_delete *xlrec;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
xl_btree_delete *xlrec;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
if (!redo || (record->xl_info & XLR_BKP_BLOCK_1))
|
||||
return;
|
||||
|
||||
xlrec = (xl_btree_delete*) XLogRecGetData(record);
|
||||
xlrec = (xl_btree_delete *) XLogRecGetData(record);
|
||||
reln = XLogOpenRelation(redo, RM_BTREE_ID, xlrec->target.node);
|
||||
if (!RelationIsValid(reln))
|
||||
return;
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "btree_delete_redo: block unfound");
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
@@ -796,21 +805,21 @@ btree_xlog_delete(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
static void
|
||||
btree_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_btree_insert *xlrec;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
xl_btree_insert *xlrec;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
|
||||
if (redo && (record->xl_info & XLR_BKP_BLOCK_1))
|
||||
return;
|
||||
|
||||
xlrec = (xl_btree_insert*) XLogRecGetData(record);
|
||||
xlrec = (xl_btree_insert *) XLogRecGetData(record);
|
||||
reln = XLogOpenRelation(redo, RM_BTREE_ID, xlrec->target.node);
|
||||
if (!RelationIsValid(reln))
|
||||
return;
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "btree_insert_%sdo: block unfound", (redo) ? "re" : "un");
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
@@ -825,11 +834,11 @@ btree_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return;
|
||||
}
|
||||
if (PageAddItem(page, (Item)((char*)xlrec + SizeOfBtreeInsert),
|
||||
record->xl_len - SizeOfBtreeInsert,
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
LP_USED) == InvalidOffsetNumber)
|
||||
elog(STOP, "btree_insert_redo: failed to add item");
|
||||
if (PageAddItem(page, (Item) ((char *) xlrec + SizeOfBtreeInsert),
|
||||
record->xl_len - SizeOfBtreeInsert,
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
LP_USED) == InvalidOffsetNumber)
|
||||
elog(STOP, "btree_insert_redo: failed to add item");
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
@@ -840,7 +849,7 @@ btree_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
if (XLByteLT(PageGetLSN(page), lsn))
|
||||
elog(STOP, "btree_insert_undo: bad page LSN");
|
||||
|
||||
if (! P_ISLEAF(pageop))
|
||||
if (!P_ISLEAF(pageop))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return;
|
||||
@@ -855,14 +864,14 @@ btree_xlog_insert(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
static void
|
||||
btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_btree_split *xlrec = (xl_btree_split*) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
BlockNumber blkno;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
char *op = (redo) ? "redo" : "undo";
|
||||
bool isleaf = (record->xl_info & XLOG_BTREE_LEAF);
|
||||
xl_btree_split *xlrec = (xl_btree_split *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
BlockNumber blkno;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
char *op = (redo) ? "redo" : "undo";
|
||||
bool isleaf = (record->xl_info & XLOG_BTREE_LEAF);
|
||||
|
||||
reln = XLogOpenRelation(redo, RM_BTREE_ID, xlrec->target.node);
|
||||
if (!RelationIsValid(reln))
|
||||
@@ -870,7 +879,7 @@ btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
/* Left (original) sibling */
|
||||
blkno = (onleft) ? ItemPointerGetBlockNumber(&(xlrec->target.tid)) :
|
||||
BlockIdGetBlockNumber(&(xlrec->otherblk));
|
||||
BlockIdGetBlockNumber(&(xlrec->otherblk));
|
||||
buffer = XLogReadBuffer(false, reln, blkno);
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "btree_split_%s: lost left sibling", op);
|
||||
@@ -892,13 +901,14 @@ btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
pageop->btpo_next = ItemPointerGetBlockNumber(&(xlrec->target.tid));
|
||||
pageop->btpo_flags = (isleaf) ? BTP_LEAF : 0;
|
||||
|
||||
_bt_restore_page(page, (char*)xlrec + SizeOfBtreeSplit, xlrec->leftlen);
|
||||
_bt_restore_page(page, (char *) xlrec + SizeOfBtreeSplit, xlrec->leftlen);
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
UnlockAndWriteBuffer(buffer);
|
||||
}
|
||||
else /* undo */
|
||||
else
|
||||
/* undo */
|
||||
{
|
||||
if (XLByteLT(PageGetLSN(page), lsn))
|
||||
elog(STOP, "btree_split_undo: bad left sibling LSN");
|
||||
@@ -906,8 +916,8 @@ btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
}
|
||||
|
||||
/* Right (new) sibling */
|
||||
blkno = (onleft) ? BlockIdGetBlockNumber(&(xlrec->otherblk)) :
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid));
|
||||
blkno = (onleft) ? BlockIdGetBlockNumber(&(xlrec->otherblk)) :
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid));
|
||||
buffer = XLogReadBuffer((redo) ? true : false, reln, blkno);
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "btree_split_%s: lost right sibling", op);
|
||||
@@ -922,21 +932,22 @@ btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
if (redo)
|
||||
{
|
||||
pageop->btpo_parent = BlockIdGetBlockNumber(&(xlrec->parentblk));
|
||||
pageop->btpo_prev = (onleft) ?
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)) :
|
||||
BlockIdGetBlockNumber(&(xlrec->otherblk));
|
||||
pageop->btpo_prev = (onleft) ?
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)) :
|
||||
BlockIdGetBlockNumber(&(xlrec->otherblk));
|
||||
pageop->btpo_next = BlockIdGetBlockNumber(&(xlrec->rightblk));
|
||||
pageop->btpo_flags = (isleaf) ? BTP_LEAF : 0;
|
||||
|
||||
_bt_restore_page(page,
|
||||
(char*)xlrec + SizeOfBtreeSplit + xlrec->leftlen,
|
||||
record->xl_len - SizeOfBtreeSplit - xlrec->leftlen);
|
||||
(char *) xlrec + SizeOfBtreeSplit + xlrec->leftlen,
|
||||
record->xl_len - SizeOfBtreeSplit - xlrec->leftlen);
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
UnlockAndWriteBuffer(buffer);
|
||||
}
|
||||
else /* undo */
|
||||
else
|
||||
/* undo */
|
||||
{
|
||||
if (XLByteLT(PageGetLSN(page), lsn))
|
||||
elog(STOP, "btree_split_undo: bad right sibling LSN");
|
||||
@@ -965,9 +976,9 @@ btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
return;
|
||||
}
|
||||
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
pageop->btpo_prev = (onleft) ?
|
||||
BlockIdGetBlockNumber(&(xlrec->otherblk)) :
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid));
|
||||
pageop->btpo_prev = (onleft) ?
|
||||
BlockIdGetBlockNumber(&(xlrec->otherblk)) :
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid));
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
@@ -977,14 +988,14 @@ btree_xlog_split(bool redo, bool onleft, XLogRecPtr lsn, XLogRecord *record)
|
||||
static void
|
||||
btree_xlog_newroot(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
xl_btree_newroot *xlrec = (xl_btree_newroot*) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
Buffer metabuf;
|
||||
Page metapg;
|
||||
BTMetaPageData md;
|
||||
xl_btree_newroot *xlrec = (xl_btree_newroot *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
Buffer metabuf;
|
||||
Page metapg;
|
||||
BTMetaPageData md;
|
||||
|
||||
if (!redo)
|
||||
return;
|
||||
@@ -1011,8 +1022,8 @@ btree_xlog_newroot(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
if (record->xl_len > SizeOfBtreeNewroot)
|
||||
_bt_restore_page(page,
|
||||
(char*)xlrec + SizeOfBtreeNewroot,
|
||||
record->xl_len - SizeOfBtreeNewroot);
|
||||
(char *) xlrec + SizeOfBtreeNewroot,
|
||||
record->xl_len - SizeOfBtreeNewroot);
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
@@ -1037,7 +1048,7 @@ btree_xlog_newroot(bool redo, XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
btree_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
info &= ~XLOG_BTREE_LEAF;
|
||||
if (info == XLOG_BTREE_DELETE)
|
||||
@@ -1045,9 +1056,9 @@ btree_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
else if (info == XLOG_BTREE_INSERT)
|
||||
btree_xlog_insert(true, lsn, record);
|
||||
else if (info == XLOG_BTREE_SPLIT)
|
||||
btree_xlog_split(true, false, lsn, record); /* new item on the right */
|
||||
btree_xlog_split(true, false, lsn, record); /* new item on the right */
|
||||
else if (info == XLOG_BTREE_SPLEFT)
|
||||
btree_xlog_split(true, true, lsn, record); /* new item on the left */
|
||||
btree_xlog_split(true, true, lsn, record); /* new item on the left */
|
||||
else if (info == XLOG_BTREE_NEWROOT)
|
||||
btree_xlog_newroot(true, lsn, record);
|
||||
else
|
||||
@@ -1057,7 +1068,7 @@ btree_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
btree_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
info &= ~XLOG_BTREE_LEAF;
|
||||
if (info == XLOG_BTREE_DELETE)
|
||||
@@ -1065,9 +1076,9 @@ btree_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
else if (info == XLOG_BTREE_INSERT)
|
||||
btree_xlog_insert(false, lsn, record);
|
||||
else if (info == XLOG_BTREE_SPLIT)
|
||||
btree_xlog_split(false, false, lsn, record);/* new item on the right */
|
||||
btree_xlog_split(false, false, lsn, record); /* new item on the right */
|
||||
else if (info == XLOG_BTREE_SPLEFT)
|
||||
btree_xlog_split(false, true, lsn, record); /* new item on the left */
|
||||
btree_xlog_split(false, true, lsn, record); /* new item on the left */
|
||||
else if (info == XLOG_BTREE_NEWROOT)
|
||||
btree_xlog_newroot(false, lsn, record);
|
||||
else
|
||||
@@ -1078,45 +1089,49 @@ static void
|
||||
out_target(char *buf, xl_btreetid *target)
|
||||
{
|
||||
sprintf(buf + strlen(buf), "node %u/%u; tid %u/%u",
|
||||
target->node.tblNode, target->node.relNode,
|
||||
ItemPointerGetBlockNumber(&(target->tid)),
|
||||
ItemPointerGetOffsetNumber(&(target->tid)));
|
||||
target->node.tblNode, target->node.relNode,
|
||||
ItemPointerGetBlockNumber(&(target->tid)),
|
||||
ItemPointerGetOffsetNumber(&(target->tid)));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
btree_desc(char *buf, uint8 xl_info, char* rec)
|
||||
btree_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
info &= ~XLOG_BTREE_LEAF;
|
||||
if (info == XLOG_BTREE_INSERT)
|
||||
{
|
||||
xl_btree_insert *xlrec = (xl_btree_insert*) rec;
|
||||
xl_btree_insert *xlrec = (xl_btree_insert *) rec;
|
||||
|
||||
strcat(buf, "insert: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
}
|
||||
else if (info == XLOG_BTREE_DELETE)
|
||||
{
|
||||
xl_btree_delete *xlrec = (xl_btree_delete*) rec;
|
||||
xl_btree_delete *xlrec = (xl_btree_delete *) rec;
|
||||
|
||||
strcat(buf, "delete: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
}
|
||||
else if (info == XLOG_BTREE_SPLIT || info == XLOG_BTREE_SPLEFT)
|
||||
{
|
||||
xl_btree_split *xlrec = (xl_btree_split*) rec;
|
||||
sprintf(buf + strlen(buf), "split(%s): ",
|
||||
(info == XLOG_BTREE_SPLIT) ? "right" : "left");
|
||||
xl_btree_split *xlrec = (xl_btree_split *) rec;
|
||||
|
||||
sprintf(buf + strlen(buf), "split(%s): ",
|
||||
(info == XLOG_BTREE_SPLIT) ? "right" : "left");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
BlockIdGetBlockNumber(&xlrec->otherblk),
|
||||
BlockIdGetBlockNumber(&xlrec->rightblk));
|
||||
BlockIdGetBlockNumber(&xlrec->otherblk),
|
||||
BlockIdGetBlockNumber(&xlrec->rightblk));
|
||||
}
|
||||
else if (info == XLOG_BTREE_NEWROOT)
|
||||
{
|
||||
xl_btree_newroot *xlrec = (xl_btree_newroot*) rec;
|
||||
xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
|
||||
|
||||
sprintf(buf + strlen(buf), "root: node %u/%u; blk %u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
BlockIdGetBlockNumber(&xlrec->rootblk));
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
BlockIdGetBlockNumber(&xlrec->rootblk));
|
||||
}
|
||||
else
|
||||
strcat(buf, "UNKNOWN");
|
||||
|
||||
@@ -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.63 2001/01/24 19:42:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.64 2001/03/22 03:59:15 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -32,20 +32,20 @@ static RetrieveIndexResult _bt_endpoint(IndexScanDesc scan, ScanDirection dir);
|
||||
*
|
||||
* NOTE that the returned buffer is read-locked regardless of the access
|
||||
* parameter. However, access = BT_WRITE will allow an empty root page
|
||||
* to be created and returned. When access = BT_READ, an empty index
|
||||
* to be created and returned. When access = BT_READ, an empty index
|
||||
* will result in *bufP being set to InvalidBuffer.
|
||||
*/
|
||||
BTStack
|
||||
_bt_search(Relation rel, int keysz, ScanKey scankey,
|
||||
Buffer *bufP, int access)
|
||||
{
|
||||
BTStack stack_in = NULL;
|
||||
BTStack stack_in = NULL;
|
||||
|
||||
/* Get the root page to start with */
|
||||
*bufP = _bt_getroot(rel, access);
|
||||
|
||||
/* If index is empty and access = BT_READ, no root page is created. */
|
||||
if (! BufferIsValid(*bufP))
|
||||
if (!BufferIsValid(*bufP))
|
||||
return (BTStack) NULL;
|
||||
|
||||
/* Loop iterates once per level descended in the tree */
|
||||
@@ -79,13 +79,13 @@ _bt_search(Relation rel, int keysz, ScanKey scankey,
|
||||
par_blkno = BufferGetBlockNumber(*bufP);
|
||||
|
||||
/*
|
||||
* We need to save the bit image of the index entry we chose in the
|
||||
* parent page on a stack. In case we split the tree, we'll use this
|
||||
* bit image to figure out what our real parent page is, in case the
|
||||
* parent splits while we're working lower in the tree. See the paper
|
||||
* by Lehman and Yao for how this is detected and handled. (We use the
|
||||
* child link to disambiguate duplicate keys in the index -- Lehman
|
||||
* and Yao disallow duplicate keys.)
|
||||
* We need to save the bit image of the index entry we chose in
|
||||
* the parent page on a stack. In case we split the tree, we'll
|
||||
* use this bit image to figure out what our real parent page is,
|
||||
* in case the parent splits while we're working lower in the
|
||||
* tree. See the paper by Lehman and Yao for how this is detected
|
||||
* and handled. (We use the child link to disambiguate duplicate
|
||||
* keys in the index -- Lehman and Yao disallow duplicate keys.)
|
||||
*/
|
||||
new_stack = (BTStack) palloc(sizeof(BTStackData));
|
||||
new_stack->bts_blkno = par_blkno;
|
||||
@@ -98,9 +98,9 @@ _bt_search(Relation rel, int keysz, ScanKey scankey,
|
||||
*bufP = _bt_getbuf(rel, blkno, BT_READ);
|
||||
|
||||
/*
|
||||
* Race -- the page we just grabbed may have split since we read its
|
||||
* pointer in the parent. If it has, we may need to move right to its
|
||||
* new sibling. Do that.
|
||||
* Race -- the page we just grabbed may have split since we read
|
||||
* its pointer in the parent. If it has, we may need to move
|
||||
* right to its new sibling. Do that.
|
||||
*/
|
||||
*bufP = _bt_moveright(rel, *bufP, keysz, scankey, BT_READ);
|
||||
|
||||
@@ -127,7 +127,7 @@ _bt_search(Relation rel, int keysz, ScanKey scankey,
|
||||
*
|
||||
* On entry, we have the buffer pinned and a lock of the proper type.
|
||||
* If we move right, we release the buffer and lock and acquire the
|
||||
* same on the right sibling. Return value is the buffer we stop at.
|
||||
* same on the right sibling. Return value is the buffer we stop at.
|
||||
*/
|
||||
Buffer
|
||||
_bt_moveright(Relation rel,
|
||||
@@ -153,7 +153,7 @@ _bt_moveright(Relation rel,
|
||||
_bt_compare(rel, keysz, scankey, page, P_HIKEY) > 0)
|
||||
{
|
||||
/* step right one page */
|
||||
BlockNumber rblkno = opaque->btpo_next;
|
||||
BlockNumber rblkno = opaque->btpo_next;
|
||||
|
||||
_bt_relbuf(rel, buf, access);
|
||||
buf = _bt_getbuf(rel, rblkno, access);
|
||||
@@ -184,7 +184,7 @@ _bt_moveright(Relation rel,
|
||||
* find all leaf keys >= given scankey.
|
||||
*
|
||||
* This procedure is not responsible for walking right, it just examines
|
||||
* the given page. _bt_binsrch() has no lock or refcount side effects
|
||||
* the given page. _bt_binsrch() has no lock or refcount side effects
|
||||
* on the buffer.
|
||||
*/
|
||||
OffsetNumber
|
||||
@@ -299,7 +299,7 @@ _bt_compare(Relation rel,
|
||||
* Force result ">" if target item is first data item on an internal
|
||||
* page --- see NOTE above.
|
||||
*/
|
||||
if (! P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
|
||||
if (!P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
|
||||
return 1;
|
||||
|
||||
btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offnum));
|
||||
@@ -327,7 +327,7 @@ _bt_compare(Relation rel,
|
||||
datum = index_getattr(itup, entry->sk_attno, itupdesc, &isNull);
|
||||
|
||||
/* see comments about NULLs handling in btbuild */
|
||||
if (entry->sk_flags & SK_ISNULL) /* key is NULL */
|
||||
if (entry->sk_flags & SK_ISNULL) /* key is NULL */
|
||||
{
|
||||
if (isNull)
|
||||
result = 0; /* NULL "=" NULL */
|
||||
@@ -458,10 +458,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
_bt_orderkeys(rel, so);
|
||||
|
||||
/*
|
||||
* Quit now if _bt_orderkeys() discovered that the scan keys can
|
||||
* never be satisfied (eg, x == 1 AND x > 2).
|
||||
* Quit now if _bt_orderkeys() discovered that the scan keys can never
|
||||
* be satisfied (eg, x == 1 AND x > 2).
|
||||
*/
|
||||
if (! so->qual_ok)
|
||||
if (!so->qual_ok)
|
||||
return (RetrieveIndexResult) NULL;
|
||||
|
||||
/*
|
||||
@@ -484,17 +484,16 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
break;
|
||||
strat = _bt_getstrat(rel, attno,
|
||||
so->keyData[i].sk_procedure);
|
||||
|
||||
/*
|
||||
* Can we use this key as a starting boundary for this attr?
|
||||
*
|
||||
* We can use multiple keys if they look like, say, = >= =
|
||||
* but we have to stop after accepting a > or < boundary.
|
||||
* We can use multiple keys if they look like, say, = >= = but we
|
||||
* have to stop after accepting a > or < boundary.
|
||||
*/
|
||||
if (strat == strat_total ||
|
||||
strat == BTEqualStrategyNumber)
|
||||
{
|
||||
nKeyIs[keysCount++] = i;
|
||||
}
|
||||
else if (ScanDirectionIsBackward(dir) &&
|
||||
(strat == BTLessStrategyNumber ||
|
||||
strat == BTLessEqualStrategyNumber))
|
||||
@@ -536,7 +535,11 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
for (i = 0; i < keysCount; i++)
|
||||
{
|
||||
j = nKeyIs[i];
|
||||
/* _bt_orderkeys disallows it, but it's place to add some code later */
|
||||
|
||||
/*
|
||||
* _bt_orderkeys disallows it, but it's place to add some code
|
||||
* later
|
||||
*/
|
||||
if (so->keyData[j].sk_flags & SK_ISNULL)
|
||||
{
|
||||
pfree(nKeyIs);
|
||||
@@ -562,7 +565,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
/* don't need to keep the stack around... */
|
||||
_bt_freestack(stack);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
if (!BufferIsValid(buf))
|
||||
{
|
||||
/* Only get here if index is completely empty */
|
||||
ItemPointerSetInvalid(current);
|
||||
@@ -601,6 +604,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
switch (strat_total)
|
||||
{
|
||||
case BTLessStrategyNumber:
|
||||
|
||||
/*
|
||||
* Back up one to arrive at last item < scankey
|
||||
*/
|
||||
@@ -612,6 +616,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
break;
|
||||
|
||||
case BTLessEqualStrategyNumber:
|
||||
|
||||
/*
|
||||
* We need to find the last item <= scankey, so step forward
|
||||
* till we find one > scankey, then step back one.
|
||||
@@ -645,9 +650,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
break;
|
||||
|
||||
case BTEqualStrategyNumber:
|
||||
|
||||
/*
|
||||
* Make sure we are on the first equal item; might have to step
|
||||
* forward if currently at end of page.
|
||||
* Make sure we are on the first equal item; might have to
|
||||
* step forward if currently at end of page.
|
||||
*/
|
||||
if (offnum > PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
@@ -661,7 +667,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
}
|
||||
result = _bt_compare(rel, keysCount, scankeys, page, offnum);
|
||||
if (result != 0)
|
||||
goto nomatches; /* no equal items! */
|
||||
goto nomatches; /* no equal items! */
|
||||
|
||||
/*
|
||||
* If a backward scan was specified, need to start with last
|
||||
* equal item not first one.
|
||||
@@ -685,6 +692,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
break;
|
||||
|
||||
case BTGreaterEqualStrategyNumber:
|
||||
|
||||
/*
|
||||
* We want the first item >= scankey, which is where we are...
|
||||
* unless we're not anywhere at all...
|
||||
@@ -700,9 +708,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||
break;
|
||||
|
||||
case BTGreaterStrategyNumber:
|
||||
|
||||
/*
|
||||
* We want the first item > scankey, so make sure we are on
|
||||
* an item and then step over any equal items.
|
||||
* We want the first item > scankey, so make sure we are on an
|
||||
* item and then step over any equal items.
|
||||
*/
|
||||
if (offnum > PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
@@ -850,11 +859,12 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||
*bufP = _bt_getbuf(rel, blkno, BT_READ);
|
||||
page = BufferGetPage(*bufP);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
||||
/*
|
||||
* If the adjacent page just split, then we have to walk
|
||||
* right to find the block that's now adjacent to where
|
||||
* we were. Because pages only split right, we don't have
|
||||
* to worry about this failing to terminate.
|
||||
* right to find the block that's now adjacent to where we
|
||||
* were. Because pages only split right, we don't have to
|
||||
* worry about this failing to terminate.
|
||||
*/
|
||||
while (opaque->btpo_next != obknum)
|
||||
{
|
||||
@@ -912,12 +922,12 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||
|
||||
/*
|
||||
* Scan down to the leftmost or rightmost leaf page. This is a
|
||||
* simplified version of _bt_search(). We don't maintain a stack
|
||||
* simplified version of _bt_search(). We don't maintain a stack
|
||||
* since we know we won't need it.
|
||||
*/
|
||||
buf = _bt_getroot(rel, BT_READ);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
if (!BufferIsValid(buf))
|
||||
{
|
||||
/* empty index... */
|
||||
ItemPointerSetInvalid(current);
|
||||
@@ -981,7 +991,8 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||
Assert(P_RIGHTMOST(opaque));
|
||||
|
||||
start = PageGetMaxOffsetNumber(page);
|
||||
if (start < P_FIRSTDATAKEY(opaque)) /* watch out for empty page */
|
||||
if (start < P_FIRSTDATAKEY(opaque)) /* watch out for empty
|
||||
* page */
|
||||
start = P_FIRSTDATAKEY(opaque);
|
||||
}
|
||||
else
|
||||
@@ -995,8 +1006,8 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||
so->btso_curbuf = buf;
|
||||
|
||||
/*
|
||||
* Left/rightmost page could be empty due to deletions,
|
||||
* if so step till we find a nonempty page.
|
||||
* Left/rightmost page could be empty due to deletions, if so step
|
||||
* till we find a nonempty page.
|
||||
*/
|
||||
if (start > maxoff)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
* We use tuplesort.c to sort the given index tuples into order.
|
||||
* Then we scan the index tuples in order and build the btree pages
|
||||
* for each level. We load source tuples into leaf-level pages.
|
||||
* for each level. We load source tuples into leaf-level pages.
|
||||
* Whenever we fill a page at one level, we add a link to it to its
|
||||
* parent level (starting a new parent level if necessary). When
|
||||
* done, we write out each final page on each level, adding it to
|
||||
@@ -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.59 2001/01/24 19:42:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.60 2001/03/22 03:59:15 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -57,7 +57,7 @@ struct BTSpool
|
||||
};
|
||||
|
||||
/*
|
||||
* Status record for a btree page being built. We have one of these
|
||||
* Status record for a btree page being built. We have one of these
|
||||
* for each active tree level.
|
||||
*
|
||||
* The reason we need to store a copy of the minimum key is that we'll
|
||||
@@ -73,11 +73,13 @@ typedef struct BTPageState
|
||||
{
|
||||
Buffer btps_buf; /* current buffer & page */
|
||||
Page btps_page;
|
||||
BTItem btps_minkey; /* copy of minimum key (first item) on page */
|
||||
BTItem btps_minkey; /* copy of minimum key (first item) on
|
||||
* page */
|
||||
OffsetNumber btps_lastoff; /* last item offset loaded */
|
||||
int btps_level; /* tree level (0 = leaf) */
|
||||
Size btps_full; /* "full" if less than this much free space */
|
||||
struct BTPageState *btps_next; /* link to parent level, if any */
|
||||
Size btps_full; /* "full" if less than this much free
|
||||
* space */
|
||||
struct BTPageState *btps_next; /* link to parent level, if any */
|
||||
} BTPageState;
|
||||
|
||||
|
||||
@@ -92,7 +94,7 @@ static void _bt_blnewpage(Relation index, Buffer *buf, Page *page, int flags);
|
||||
static BTPageState *_bt_pagestate(Relation index, int flags, int level);
|
||||
static void _bt_slideleft(Relation index, Buffer buf, Page page);
|
||||
static void _bt_sortaddtup(Page page, Size itemsize,
|
||||
BTItem btitem, OffsetNumber itup_off);
|
||||
BTItem btitem, OffsetNumber itup_off);
|
||||
static void _bt_buildadd(Relation index, BTPageState *state, BTItem bti);
|
||||
static void _bt_uppershutdown(Relation index, BTPageState *state);
|
||||
static void _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2);
|
||||
@@ -162,7 +164,7 @@ _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
|
||||
ShowUsage();
|
||||
ResetUsage();
|
||||
}
|
||||
#endif /* BTREE_BUILD_STATS */
|
||||
#endif /* BTREE_BUILD_STATS */
|
||||
tuplesort_performsort(btspool->sortstate);
|
||||
|
||||
if (btspool2)
|
||||
@@ -269,9 +271,9 @@ _bt_sortaddtup(Page page,
|
||||
OffsetNumber itup_off)
|
||||
{
|
||||
BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
BTItemData truncitem;
|
||||
BTItemData truncitem;
|
||||
|
||||
if (! P_ISLEAF(opaque) && itup_off == P_FIRSTKEY)
|
||||
if (!P_ISLEAF(opaque) && itup_off == P_FIRSTKEY)
|
||||
{
|
||||
memcpy(&truncitem, btitem, sizeof(BTItemData));
|
||||
truncitem.bti_itup.t_info = sizeof(BTItemData);
|
||||
@@ -290,7 +292,7 @@ _bt_sortaddtup(Page page,
|
||||
* We must be careful to observe the page layout conventions of nbtsearch.c:
|
||||
* - rightmost pages start data items at P_HIKEY instead of at P_FIRSTKEY.
|
||||
* - on non-leaf pages, the key portion of the first item need not be
|
||||
* stored, we should store only the link.
|
||||
* stored, we should store only the link.
|
||||
*
|
||||
* A leaf page being built looks like:
|
||||
*
|
||||
@@ -347,11 +349,12 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
*/
|
||||
if (btisz > (PageGetPageSize(npage) - sizeof(PageHeaderData) - MAXALIGN(sizeof(BTPageOpaqueData))) / 3 - sizeof(ItemIdData))
|
||||
elog(ERROR, "btree: index item size %lu exceeds maximum %ld",
|
||||
(unsigned long)btisz,
|
||||
(PageGetPageSize(npage) - sizeof(PageHeaderData) - MAXALIGN(sizeof(BTPageOpaqueData))) /3 - sizeof(ItemIdData));
|
||||
(unsigned long) btisz,
|
||||
(PageGetPageSize(npage) - sizeof(PageHeaderData) - MAXALIGN(sizeof(BTPageOpaqueData))) / 3 - sizeof(ItemIdData));
|
||||
|
||||
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.
|
||||
@@ -388,9 +391,9 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
((PageHeader) opage)->pd_lower -= sizeof(ItemIdData);
|
||||
|
||||
/*
|
||||
* Link the old buffer into its parent, using its minimum key.
|
||||
* If we don't have a parent, we have to create one;
|
||||
* this adds a new btree level.
|
||||
* Link the old buffer into its parent, using its minimum key. If
|
||||
* we don't have a parent, we have to create one; this adds a new
|
||||
* btree level.
|
||||
*/
|
||||
if (state->btps_next == (BTPageState *) NULL)
|
||||
{
|
||||
@@ -405,8 +408,8 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
|
||||
/*
|
||||
* Save a copy of the minimum key for the new page. We have to
|
||||
* copy it off the old page, not the new one, in case we are
|
||||
* not at leaf level.
|
||||
* copy it off the old page, not the new one, in case we are not
|
||||
* at leaf level.
|
||||
*/
|
||||
state->btps_minkey = _bt_formitem(&(obti->bti_itup));
|
||||
|
||||
@@ -414,13 +417,13 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
* Set the sibling links for both pages, and parent links too.
|
||||
*
|
||||
* It's not necessary to set the parent link at all, because it's
|
||||
* only used for handling concurrent root splits, but we may as well
|
||||
* do it as a debugging aid. Note we set new page's link as well
|
||||
* as old's, because if the new page turns out to be the last of
|
||||
* the level, _bt_uppershutdown won't change it. The links may be
|
||||
* out of date by the time the build finishes, but that's OK; they
|
||||
* need only point to a left-sibling of the true parent. See the
|
||||
* README file for more info.
|
||||
* only used for handling concurrent root splits, but we may as
|
||||
* well do it as a debugging aid. Note we set new page's link as
|
||||
* well as old's, because if the new page turns out to be the last
|
||||
* of the level, _bt_uppershutdown won't change it. The links may
|
||||
* be out of date by the time the build finishes, but that's OK;
|
||||
* they need only point to a left-sibling of the true parent. See
|
||||
* the README file for more info.
|
||||
*/
|
||||
{
|
||||
BTPageOpaque oopaque = (BTPageOpaque) PageGetSpecialPointer(opage);
|
||||
@@ -434,7 +437,7 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the old page. We never want to see it again, so we
|
||||
* Write out the old page. We never want to see it again, so we
|
||||
* can give up our lock (if we had one; most likely BuildingBtree
|
||||
* is set, so we aren't locking).
|
||||
*/
|
||||
@@ -449,8 +452,8 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
|
||||
/*
|
||||
* If the new item is the first for its page, stash a copy for later.
|
||||
* Note this will only happen for the first item on a level; on later
|
||||
* pages, the first item for a page is copied from the prior page
|
||||
* in the code above.
|
||||
* pages, the first item for a page is copied from the prior page in
|
||||
* the code above.
|
||||
*/
|
||||
if (last_off == P_HIKEY)
|
||||
{
|
||||
@@ -493,8 +496,8 @@ _bt_uppershutdown(Relation index, BTPageState *state)
|
||||
*
|
||||
* If we're at the top, it's the root, so attach it to the metapage.
|
||||
* Otherwise, add an entry for it to its parent using its minimum
|
||||
* key. This may cause the last page of the parent level to split,
|
||||
* but that's not a problem -- we haven't gotten to it yet.
|
||||
* key. This may cause the last page of the parent level to
|
||||
* split, but that's not a problem -- we haven't gotten to it yet.
|
||||
*/
|
||||
if (s->btps_next == (BTPageState *) NULL)
|
||||
{
|
||||
@@ -513,7 +516,7 @@ _bt_uppershutdown(Relation index, BTPageState *state)
|
||||
|
||||
/*
|
||||
* This is the rightmost page, so the ItemId array needs to be
|
||||
* slid back one slot. Then we can dump out the page.
|
||||
* slid back one slot. Then we can dump out the page.
|
||||
*/
|
||||
_bt_slideleft(index, s->btps_buf, s->btps_page);
|
||||
_bt_wrtbuf(index, s->btps_buf);
|
||||
@@ -529,22 +532,29 @@ _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
|
||||
{
|
||||
BTPageState *state = NULL;
|
||||
bool merge = (btspool2 != NULL);
|
||||
BTItem bti, bti2 = NULL;
|
||||
bool should_free, should_free2, load1;
|
||||
BTItem bti,
|
||||
bti2 = NULL;
|
||||
bool should_free,
|
||||
should_free2,
|
||||
load1;
|
||||
TupleDesc tupdes = RelationGetDescr(index);
|
||||
int i, keysz = RelationGetNumberOfAttributes(index);
|
||||
int i,
|
||||
keysz = RelationGetNumberOfAttributes(index);
|
||||
ScanKey indexScanKey = NULL;
|
||||
|
||||
if (merge)
|
||||
{
|
||||
|
||||
/*
|
||||
* Another BTSpool for dead tuples exists.
|
||||
* Now we have to merge btspool and btspool2.
|
||||
*/
|
||||
ScanKey entry;
|
||||
Datum attrDatum1, attrDatum2;
|
||||
bool isFirstNull, isSecondNull;
|
||||
int32 compare;
|
||||
* Another BTSpool for dead tuples exists. Now we have to merge
|
||||
* btspool and btspool2.
|
||||
*/
|
||||
ScanKey entry;
|
||||
Datum attrDatum1,
|
||||
attrDatum2;
|
||||
bool isFirstNull,
|
||||
isSecondNull;
|
||||
int32 compare;
|
||||
|
||||
/* the preparation of merge */
|
||||
bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true, &should_free);
|
||||
@@ -552,7 +562,7 @@ _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
|
||||
indexScanKey = _bt_mkscankey_nodata(index);
|
||||
for (;;)
|
||||
{
|
||||
load1 = true; /* load BTSpool next ? */
|
||||
load1 = true; /* load BTSpool next ? */
|
||||
if (NULL == bti2)
|
||||
{
|
||||
if (NULL == bti)
|
||||
@@ -564,8 +574,8 @@ _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
|
||||
for (i = 1; i <= keysz; i++)
|
||||
{
|
||||
entry = indexScanKey + i - 1;
|
||||
attrDatum1 = index_getattr((IndexTuple)bti, i, tupdes, &isFirstNull);
|
||||
attrDatum2 = index_getattr((IndexTuple)bti2, i, tupdes, &isSecondNull);
|
||||
attrDatum1 = index_getattr((IndexTuple) bti, i, tupdes, &isFirstNull);
|
||||
attrDatum2 = index_getattr((IndexTuple) bti2, i, tupdes, &isSecondNull);
|
||||
if (isFirstNull)
|
||||
{
|
||||
if (!isSecondNull)
|
||||
@@ -586,7 +596,7 @@ _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
|
||||
}
|
||||
else if (compare < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -613,7 +623,8 @@ _bt_load(Relation index, BTSpool *btspool, BTSpool *btspool2)
|
||||
}
|
||||
_bt_freeskey(indexScanKey);
|
||||
}
|
||||
else /* merge is unnecessary */
|
||||
else
|
||||
/* merge is unnecessary */
|
||||
{
|
||||
while (bti = (BTItem) tuplesort_getindextuple(btspool->sortstate, true, &should_free), bti != (BTItem) NULL)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.42 2001/01/24 19:42:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.43 2001/03/22 03:59:15 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -124,7 +124,7 @@ _bt_freestack(BTStack stack)
|
||||
* Construct a BTItem from a plain IndexTuple.
|
||||
*
|
||||
* This is now useless code, since a BTItem *is* an index tuple with
|
||||
* no extra stuff. We hang onto it for the moment to preserve the
|
||||
* no extra stuff. We hang onto it for the moment to preserve the
|
||||
* notational distinction, in case we want to add some extra stuff
|
||||
* again someday.
|
||||
*/
|
||||
@@ -165,7 +165,7 @@ _bt_formitem(IndexTuple itup)
|
||||
* are "x = 1 AND y < 4 AND z < 5", then _bt_checkkeys will reject a tuple
|
||||
* (1,2,7), but we must continue the scan in case there are tuples (1,3,z).
|
||||
* But once we reach tuples like (1,4,z) we can stop scanning because no
|
||||
* later tuples could match. This is reflected by setting
|
||||
* later tuples could match. This is reflected by setting
|
||||
* so->numberOfRequiredKeys to the number of leading keys that must be
|
||||
* matched to continue the scan. numberOfRequiredKeys is equal to the
|
||||
* number of leading "=" keys plus the key(s) for the first non "="
|
||||
@@ -178,7 +178,7 @@ _bt_formitem(IndexTuple itup)
|
||||
*
|
||||
* XXX this routine is one of many places that fail to handle SK_COMMUTE
|
||||
* scankeys properly. Currently, the planner is careful never to generate
|
||||
* any indexquals that would require SK_COMMUTE to be set. Someday we ought
|
||||
* any indexquals that would require SK_COMMUTE to be set. Someday we ought
|
||||
* to try to fix this, though it's not real critical as long as indexable
|
||||
* operators all have commutators...
|
||||
*
|
||||
@@ -191,7 +191,7 @@ _bt_formitem(IndexTuple itup)
|
||||
void
|
||||
_bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
{
|
||||
ScanKeyData xform[BTMaxStrategyNumber];
|
||||
ScanKeyData xform[BTMaxStrategyNumber];
|
||||
bool init[BTMaxStrategyNumber];
|
||||
uint16 numberOfKeys = so->numberOfKeys;
|
||||
ScanKey key;
|
||||
@@ -240,14 +240,14 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
/*
|
||||
* Initialize for processing of keys for attr 1.
|
||||
*
|
||||
* xform[i] holds a copy of the current scan key of strategy type i+1,
|
||||
* if any; init[i] is TRUE if we have found such a key for this attr.
|
||||
* xform[i] holds a copy of the current scan key of strategy type i+1, if
|
||||
* any; init[i] is TRUE if we have found such a key for this attr.
|
||||
*/
|
||||
attno = 1;
|
||||
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
BTMaxStrategyNumber,
|
||||
attno);
|
||||
MemSet(xform, 0, sizeof(xform)); /* not really necessary */
|
||||
MemSet(xform, 0, sizeof(xform)); /* not really necessary */
|
||||
MemSet(init, 0, sizeof(init));
|
||||
|
||||
/*
|
||||
@@ -255,7 +255,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
* pass to handle after-last-key processing. Actual exit from the
|
||||
* loop is at the "break" statement below.
|
||||
*/
|
||||
for (i = 0; ; cur++, i++)
|
||||
for (i = 0;; cur++, i++)
|
||||
{
|
||||
if (i < numberOfKeys)
|
||||
{
|
||||
@@ -263,7 +263,9 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
if (cur->sk_flags & SK_ISNULL)
|
||||
{
|
||||
so->qual_ok = false;
|
||||
/* Quit processing so we don't try to invoke comparison
|
||||
|
||||
/*
|
||||
* Quit processing so we don't try to invoke comparison
|
||||
* routines on NULLs.
|
||||
*/
|
||||
return;
|
||||
@@ -271,8 +273,8 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are at the end of the keys for a particular attr,
|
||||
* finish up processing and emit the cleaned-up keys.
|
||||
* If we are at the end of the keys for a particular attr, finish
|
||||
* up processing and emit the cleaned-up keys.
|
||||
*/
|
||||
if (i == numberOfKeys || cur->sk_attno != attno)
|
||||
{
|
||||
@@ -296,7 +298,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
eq = &xform[BTEqualStrategyNumber - 1];
|
||||
for (j = BTMaxStrategyNumber; --j >= 0;)
|
||||
{
|
||||
if (! init[j] ||
|
||||
if (!init[j] ||
|
||||
j == (BTEqualStrategyNumber - 1))
|
||||
continue;
|
||||
chk = &xform[j];
|
||||
@@ -313,6 +315,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* No "=" for this key, so we're done with required keys
|
||||
*/
|
||||
@@ -355,8 +358,8 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
* Emit the cleaned-up keys back into the key[] array in the
|
||||
* correct order. Note we are overwriting our input here!
|
||||
* It's OK because (a) xform[] is a physical copy of the keys
|
||||
* we want, (b) we cannot emit more keys than we input, so
|
||||
* we won't overwrite as-yet-unprocessed keys.
|
||||
* we want, (b) we cannot emit more keys than we input, so we
|
||||
* won't overwrite as-yet-unprocessed keys.
|
||||
*/
|
||||
for (j = BTMaxStrategyNumber; --j >= 0;)
|
||||
{
|
||||
@@ -383,7 +386,7 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation),
|
||||
BTMaxStrategyNumber,
|
||||
attno);
|
||||
MemSet(xform, 0, sizeof(xform)); /* not really necessary */
|
||||
MemSet(xform, 0, sizeof(xform)); /* not really necessary */
|
||||
MemSet(init, 0, sizeof(init));
|
||||
}
|
||||
|
||||
@@ -409,7 +412,8 @@ _bt_orderkeys(Relation relation, BTScanOpaque so)
|
||||
if (DatumGetBool(test))
|
||||
xform[j].sk_argument = cur->sk_argument;
|
||||
else if (j == (BTEqualStrategyNumber - 1))
|
||||
so->qual_ok = false; /* key == a && key == b, but a != b */
|
||||
so->qual_ok = false; /* key == a && key == b, but a !=
|
||||
* b */
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -473,16 +477,18 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
|
||||
|
||||
if (isNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since NULLs are sorted after non-NULLs, we know we have
|
||||
* reached the upper limit of the range of values for this
|
||||
* index attr. On a forward scan, we can stop if this qual
|
||||
* is one of the "must match" subset. On a backward scan,
|
||||
* index attr. On a forward scan, we can stop if this qual is
|
||||
* one of the "must match" subset. On a backward scan,
|
||||
* however, we should keep going.
|
||||
*/
|
||||
if (keysok < so->numberOfRequiredKeys &&
|
||||
ScanDirectionIsForward(dir))
|
||||
*continuescan = false;
|
||||
|
||||
/*
|
||||
* In any case, this indextuple doesn't match the qual.
|
||||
*/
|
||||
@@ -498,9 +504,10 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
|
||||
|
||||
if (DatumGetBool(test) == !!(key->sk_flags & SK_NEGATE))
|
||||
{
|
||||
|
||||
/*
|
||||
* Tuple fails this qual. If it's a required qual, then
|
||||
* we can conclude no further tuples will pass, either.
|
||||
* Tuple fails this qual. If it's a required qual, then we
|
||||
* can conclude no further tuples will pass, either.
|
||||
*/
|
||||
if (keysok < so->numberOfRequiredKeys)
|
||||
*continuescan = false;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtget.c,v 1.24 2001/01/24 19:42:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtget.c,v 1.25 2001/03/22 03:59:16 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -30,8 +30,8 @@ static ItemPointer rtheapptr(Relation r, ItemPointer itemp);
|
||||
Datum
|
||||
rtgettuple(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
|
||||
RetrieveIndexResult res;
|
||||
|
||||
/* if we have it cached in the scan desc, just return the value */
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* NOTE: for largely-historical reasons, the intersection functions should
|
||||
* return a NULL pointer (*not* an SQL null value) to indicate "no
|
||||
* intersection". The size functions must be prepared to accept such
|
||||
* a pointer and return 0. This convention means that only pass-by-reference
|
||||
* a pointer and return 0. This convention means that only pass-by-reference
|
||||
* data types can be used as the output of the union and intersection
|
||||
* routines, but that's not a big problem.
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.31 2001/01/24 19:42:49 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.32 2001/03/22 03:59:16 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -70,6 +70,7 @@ Datum
|
||||
rt_box_size(PG_FUNCTION_ARGS)
|
||||
{
|
||||
BOX *a = PG_GETARG_BOX_P(0);
|
||||
|
||||
/* NB: size is an output argument */
|
||||
float *size = (float *) PG_GETARG_POINTER(1);
|
||||
|
||||
@@ -98,8 +99,8 @@ rt_bigbox_size(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rt_poly_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
POLYGON *a = PG_GETARG_POLYGON_P(0);
|
||||
POLYGON *b = PG_GETARG_POLYGON_P(1);
|
||||
POLYGON *a = PG_GETARG_POLYGON_P(0);
|
||||
POLYGON *b = PG_GETARG_POLYGON_P(1);
|
||||
POLYGON *p;
|
||||
|
||||
p = (POLYGON *) palloc(sizeof(POLYGON));
|
||||
@@ -122,8 +123,8 @@ rt_poly_union(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rt_poly_inter(PG_FUNCTION_ARGS)
|
||||
{
|
||||
POLYGON *a = PG_GETARG_POLYGON_P(0);
|
||||
POLYGON *b = PG_GETARG_POLYGON_P(1);
|
||||
POLYGON *a = PG_GETARG_POLYGON_P(0);
|
||||
POLYGON *b = PG_GETARG_POLYGON_P(1);
|
||||
POLYGON *p;
|
||||
|
||||
p = (POLYGON *) palloc(sizeof(POLYGON));
|
||||
@@ -155,13 +156,15 @@ Datum
|
||||
rt_poly_size(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Pointer aptr = PG_GETARG_POINTER(0);
|
||||
|
||||
/* NB: size is an output argument */
|
||||
float *size = (float *) PG_GETARG_POINTER(1);
|
||||
POLYGON *a;
|
||||
POLYGON *a;
|
||||
double xdim,
|
||||
ydim;
|
||||
|
||||
/* Can't just use GETARG because of possibility that input is NULL;
|
||||
/*
|
||||
* Can't just use GETARG because of possibility that input is NULL;
|
||||
* since POLYGON is toastable, GETARG will try to inspect its value
|
||||
*/
|
||||
if (aptr == NULL)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.60 2001/03/07 21:20:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.61 2001/03/22 03:59:16 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -68,12 +68,12 @@ static InsertIndexResult rtdoinsert(Relation r, IndexTuple itup,
|
||||
static void rttighten(Relation r, RTSTACK *stk, Datum datum, int att_size,
|
||||
RTSTATE *rtstate);
|
||||
static InsertIndexResult rtdosplit(Relation r, Buffer buffer, RTSTACK *stack,
|
||||
IndexTuple itup, RTSTATE *rtstate);
|
||||
IndexTuple itup, RTSTATE *rtstate);
|
||||
static void rtintinsert(Relation r, RTSTACK *stk, IndexTuple ltup,
|
||||
IndexTuple rtup, RTSTATE *rtstate);
|
||||
static void rtnewroot(Relation r, IndexTuple lt, IndexTuple rt);
|
||||
static void rtpicksplit(Relation r, Page page, SPLITVEC *v, IndexTuple itup,
|
||||
RTSTATE *rtstate);
|
||||
RTSTATE *rtstate);
|
||||
static void RTInitBuffer(Buffer b, uint32 f);
|
||||
static OffsetNumber choose(Relation r, Page p, IndexTuple it,
|
||||
RTSTATE *rtstate);
|
||||
@@ -84,12 +84,14 @@ static void initRtstate(RTSTATE *rtstate, Relation index);
|
||||
Datum
|
||||
rtbuild(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
Node *oldPred = (Node *) PG_GETARG_POINTER(3);
|
||||
Relation heap = (Relation) PG_GETARG_POINTER(0);
|
||||
Relation index = (Relation) PG_GETARG_POINTER(1);
|
||||
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
|
||||
Node *oldPred = (Node *) PG_GETARG_POINTER(3);
|
||||
|
||||
#ifdef NOT_USED
|
||||
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
|
||||
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
|
||||
|
||||
#endif
|
||||
HeapScanDesc hscan;
|
||||
HeapTuple htup;
|
||||
@@ -101,9 +103,11 @@ rtbuild(PG_FUNCTION_ARGS)
|
||||
int nhtups,
|
||||
nitups;
|
||||
Node *pred = indexInfo->ii_Predicate;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
TupleTable tupleTable;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
#endif
|
||||
ExprContext *econtext;
|
||||
InsertIndexResult res = NULL;
|
||||
@@ -171,6 +175,7 @@ rtbuild(PG_FUNCTION_ARGS)
|
||||
nhtups++;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
|
||||
/*
|
||||
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
|
||||
* this tuple if it was already in the existing partial index
|
||||
@@ -232,9 +237,7 @@ rtbuild(PG_FUNCTION_ARGS)
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
if (pred != NULL || oldPred != NULL)
|
||||
{
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
}
|
||||
#endif /* OMIT_PARTIAL_INDEX */
|
||||
FreeExprContext(econtext);
|
||||
|
||||
@@ -278,12 +281,14 @@ rtbuild(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rtinsert(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation r = (Relation) PG_GETARG_POINTER(0);
|
||||
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
|
||||
char *nulls = (char *) PG_GETARG_POINTER(2);
|
||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||
Relation r = (Relation) PG_GETARG_POINTER(0);
|
||||
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);
|
||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||
|
||||
#endif
|
||||
InsertIndexResult res;
|
||||
IndexTuple itup;
|
||||
@@ -412,7 +417,7 @@ rttighten(Relation r,
|
||||
p = BufferGetPage(b);
|
||||
|
||||
oldud = IndexTupleGetDatum(PageGetItem(p,
|
||||
PageGetItemId(p, stk->rts_child)));
|
||||
PageGetItemId(p, stk->rts_child)));
|
||||
|
||||
FunctionCall2(&rtstate->sizeFn, oldud,
|
||||
PointerGetDatum(&old_size));
|
||||
@@ -564,7 +569,7 @@ rtdosplit(Relation r,
|
||||
res = (InsertIndexResult) palloc(sizeof(InsertIndexResultData));
|
||||
|
||||
/* now insert the new index tuple */
|
||||
if (*spl_left == maxoff+1)
|
||||
if (*spl_left == maxoff + 1)
|
||||
{
|
||||
if (PageAddItem(left, (Item) itup, IndexTupleSize(itup),
|
||||
leftoff, LP_USED) == InvalidOffsetNumber)
|
||||
@@ -576,7 +581,7 @@ rtdosplit(Relation r,
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(*spl_right == maxoff+1);
|
||||
Assert(*spl_right == maxoff + 1);
|
||||
if (PageAddItem(right, (Item) itup, IndexTupleSize(itup),
|
||||
rightoff, LP_USED) == InvalidOffsetNumber)
|
||||
elog(ERROR, "rtdosplit: failed to add index item to %s",
|
||||
@@ -665,10 +670,10 @@ rtintinsert(Relation r,
|
||||
old = (IndexTuple) PageGetItem(p, PageGetItemId(p, stk->rts_child));
|
||||
|
||||
/*
|
||||
* This is a hack. Right now, we force rtree internal keys to be constant
|
||||
* size. To fix this, need delete the old key and add both left and
|
||||
* right for the two new pages. The insertion of left may force a
|
||||
* split if the new left key is bigger than the old key.
|
||||
* This is a hack. Right now, we force rtree internal keys to be
|
||||
* constant size. To fix this, need delete the old key and add both
|
||||
* left and right for the two new pages. The insertion of left may
|
||||
* force a split if the new left key is bigger than the old key.
|
||||
*/
|
||||
|
||||
if (IndexTupleSize(old) != IndexTupleSize(ltup))
|
||||
@@ -734,7 +739,7 @@ rtnewroot(Relation r, IndexTuple lt, IndexTuple rt)
|
||||
* We return two vectors of index item numbers, one for the items to be
|
||||
* put on the left page, one for the items to be put on the right page.
|
||||
* In addition, the item to be added (itup) is listed in the appropriate
|
||||
* vector. It is represented by item number N+1 (N = # of items on page).
|
||||
* vector. It is represented by item number N+1 (N = # of items on page).
|
||||
*
|
||||
* Both vectors appear in sequence order with a terminating sentinel value
|
||||
* of InvalidOffsetNumber.
|
||||
@@ -747,9 +752,9 @@ rtnewroot(Relation r, IndexTuple lt, IndexTuple rt)
|
||||
*
|
||||
* We must also deal with a consideration not found in Guttman's algorithm:
|
||||
* variable-length data. In particular, the incoming item might be
|
||||
* large enough that not just any split will work. In the worst case,
|
||||
* large enough that not just any split will work. In the worst case,
|
||||
* our "split" may have to be the new item on one page and all the existing
|
||||
* items on the other. Short of that, we have to take care that we do not
|
||||
* items on the other. Short of that, we have to take care that we do not
|
||||
* make a split that leaves both pages too full for the new item.
|
||||
*/
|
||||
static void
|
||||
@@ -794,9 +799,10 @@ rtpicksplit(Relation r,
|
||||
right_avail_space;
|
||||
|
||||
/*
|
||||
* First, make sure the new item is not so large that we can't possibly
|
||||
* fit it on a page, even by itself. (It's sufficient to make this test
|
||||
* here, since any oversize tuple must lead to a page split attempt.)
|
||||
* First, make sure the new item is not so large that we can't
|
||||
* possibly fit it on a page, even by itself. (It's sufficient to
|
||||
* make this test here, since any oversize tuple must lead to a page
|
||||
* split attempt.)
|
||||
*/
|
||||
newitemsz = IndexTupleTotalSize(itup);
|
||||
if (newitemsz > RTPageAvailSpace)
|
||||
@@ -804,7 +810,8 @@ rtpicksplit(Relation r,
|
||||
(unsigned long) newitemsz, (unsigned long) RTPageAvailSpace);
|
||||
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
newitemoff = OffsetNumberNext(maxoff); /* phony index for new item */
|
||||
newitemoff = OffsetNumberNext(maxoff); /* phony index for new
|
||||
* item */
|
||||
|
||||
/* Make arrays big enough for worst case, including sentinel */
|
||||
nbytes = (maxoff + 2) * sizeof(OffsetNumber);
|
||||
@@ -827,8 +834,8 @@ rtpicksplit(Relation r,
|
||||
item_2_sz = IndexTupleTotalSize(item_2);
|
||||
|
||||
/*
|
||||
* Ignore seed pairs that don't leave room for the new item
|
||||
* on either split page.
|
||||
* Ignore seed pairs that don't leave room for the new item on
|
||||
* either split page.
|
||||
*/
|
||||
if (newitemsz + item_1_sz > RTPageAvailSpace &&
|
||||
newitemsz + item_2_sz > RTPageAvailSpace)
|
||||
@@ -841,8 +848,10 @@ rtpicksplit(Relation r,
|
||||
PointerGetDatum(&size_union));
|
||||
inter_d = FunctionCall2(&rtstate->interFn,
|
||||
datum_alpha, datum_beta);
|
||||
/* The interFn may return a NULL pointer (not an SQL null!)
|
||||
* to indicate no intersection. sizeFn must cope with this.
|
||||
|
||||
/*
|
||||
* The interFn may return a NULL pointer (not an SQL null!) to
|
||||
* indicate no intersection. sizeFn must cope with this.
|
||||
*/
|
||||
FunctionCall2(&rtstate->sizeFn, inter_d,
|
||||
PointerGetDatum(&size_inter));
|
||||
@@ -869,6 +878,7 @@ 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,
|
||||
@@ -916,14 +926,14 @@ rtpicksplit(Relation r,
|
||||
|
||||
for (i = FirstOffsetNumber; i <= newitemoff; i = OffsetNumberNext(i))
|
||||
{
|
||||
bool left_feasible,
|
||||
right_feasible,
|
||||
choose_left;
|
||||
bool left_feasible,
|
||||
right_feasible,
|
||||
choose_left;
|
||||
|
||||
/*
|
||||
* If we've already decided where to place this item, just put it
|
||||
* on the correct list. Otherwise, we need to figure out which page
|
||||
* needs the least enlargement in order to store the item.
|
||||
* on the correct list. Otherwise, we need to figure out which
|
||||
* page needs the least enlargement in order to store the item.
|
||||
*/
|
||||
|
||||
if (i == seed_1)
|
||||
@@ -961,12 +971,13 @@ rtpicksplit(Relation r,
|
||||
PointerGetDatum(&size_beta));
|
||||
|
||||
/*
|
||||
* We prefer the page that shows smaller enlargement of its union area
|
||||
* (Guttman's algorithm), but we must take care that at least one page
|
||||
* will still have room for the new item after this one is added.
|
||||
* We prefer the page that shows smaller enlargement of its union
|
||||
* area (Guttman's algorithm), but we must take care that at least
|
||||
* one page will still have room for the new item after this one
|
||||
* is added.
|
||||
*
|
||||
* (We know that all the old items together can fit on one page,
|
||||
* so we need not worry about any other problem than failing to fit
|
||||
* (We know that all the old items together can fit on one page, so
|
||||
* we need not worry about any other problem than failing to fit
|
||||
* the new item.)
|
||||
*/
|
||||
left_feasible = (left_avail_space >= item_1_sz &&
|
||||
@@ -987,7 +998,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)
|
||||
@@ -1012,7 +1023,7 @@ rtpicksplit(Relation r,
|
||||
}
|
||||
}
|
||||
|
||||
*left = *right = InvalidOffsetNumber; /* add ending sentinels */
|
||||
*left = *right = InvalidOffsetNumber; /* add ending sentinels */
|
||||
|
||||
v->spl_ldatum = datum_l;
|
||||
v->spl_rdatum = datum_r;
|
||||
@@ -1096,8 +1107,8 @@ freestack(RTSTACK *s)
|
||||
Datum
|
||||
rtdelete(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Relation r = (Relation) PG_GETARG_POINTER(0);
|
||||
ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
Relation r = (Relation) PG_GETARG_POINTER(0);
|
||||
ItemPointer tid = (ItemPointer) PG_GETARG_POINTER(1);
|
||||
BlockNumber blkno;
|
||||
OffsetNumber offnum;
|
||||
Buffer buf;
|
||||
@@ -1203,14 +1214,14 @@ rtree_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
elog(STOP, "rtree_redo: unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rtree_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
elog(STOP, "rtree_undo: unimplemented");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rtree_desc(char *buf, uint8 xl_info, char* rec)
|
||||
rtree_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.35 2001/01/24 19:42:50 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.36 2001/03/22 03:59:16 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -75,9 +75,9 @@ rtbeginscan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rtrescan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
bool fromEnd = PG_GETARG_BOOL(1);
|
||||
ScanKey key = (ScanKey) PG_GETARG_POINTER(2);
|
||||
RTreeScanOpaque p;
|
||||
RegProcedure internal_proc;
|
||||
int i;
|
||||
@@ -162,7 +162,7 @@ rtrescan(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rtmarkpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
RTreeScanOpaque p;
|
||||
RTSTACK *o,
|
||||
*n,
|
||||
@@ -198,7 +198,7 @@ rtmarkpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rtrestrpos(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
RTreeScanOpaque p;
|
||||
RTSTACK *o,
|
||||
*n,
|
||||
@@ -234,7 +234,7 @@ rtrestrpos(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
rtendscan(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
IndexScanDesc s = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
RTreeScanOpaque p;
|
||||
|
||||
p = (RTreeScanOpaque) s->opaque;
|
||||
|
||||
@@ -9,21 +9,21 @@
|
||||
#include "storage/smgr.h"
|
||||
#include "commands/sequence.h"
|
||||
|
||||
RmgrData RmgrTable[] = {
|
||||
{"XLOG", xlog_redo, xlog_undo, xlog_desc},
|
||||
{"Transaction", xact_redo, xact_undo, xact_desc},
|
||||
{"Storage", smgr_redo, smgr_undo, smgr_desc},
|
||||
{"Reserved 3", NULL, NULL, NULL},
|
||||
{"Reserved 4", NULL, NULL, NULL},
|
||||
{"Reserved 5", NULL, NULL, NULL},
|
||||
{"Reserved 6", NULL, NULL, NULL},
|
||||
{"Reserved 7", NULL, NULL, NULL},
|
||||
{"Reserved 8", NULL, NULL, NULL},
|
||||
{"Reserved 9", NULL, NULL, NULL},
|
||||
{"Heap", heap_redo, heap_undo, heap_desc},
|
||||
{"Btree", btree_redo, btree_undo, btree_desc},
|
||||
{"Hash", hash_redo, hash_undo, hash_desc},
|
||||
{"Rtree", rtree_redo, rtree_undo, rtree_desc},
|
||||
{"Gist", gist_redo, gist_undo, gist_desc},
|
||||
{"Sequence", seq_redo, seq_undo, seq_desc}
|
||||
RmgrData RmgrTable[] = {
|
||||
{"XLOG", xlog_redo, xlog_undo, xlog_desc},
|
||||
{"Transaction", xact_redo, xact_undo, xact_desc},
|
||||
{"Storage", smgr_redo, smgr_undo, smgr_desc},
|
||||
{"Reserved 3", NULL, NULL, NULL},
|
||||
{"Reserved 4", NULL, NULL, NULL},
|
||||
{"Reserved 5", NULL, NULL, NULL},
|
||||
{"Reserved 6", NULL, NULL, NULL},
|
||||
{"Reserved 7", NULL, NULL, NULL},
|
||||
{"Reserved 8", NULL, NULL, NULL},
|
||||
{"Reserved 9", NULL, NULL, NULL},
|
||||
{"Heap", heap_redo, heap_undo, heap_desc},
|
||||
{"Btree", btree_redo, btree_undo, btree_desc},
|
||||
{"Hash", hash_redo, hash_undo, hash_desc},
|
||||
{"Rtree", rtree_redo, rtree_undo, rtree_desc},
|
||||
{"Gist", gist_redo, gist_undo, gist_desc},
|
||||
{"Sequence", seq_redo, seq_undo, seq_desc}
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.41 2001/03/18 20:18:59 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.42 2001/03/22 03:59:17 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains the high level access-method interface to the
|
||||
@@ -427,8 +427,8 @@ InitializeTransactionLog(void)
|
||||
TransactionLogUpdate(AmiTransactionId, XID_COMMIT);
|
||||
TransactionIdStore(AmiTransactionId, &cachedTestXid);
|
||||
cachedTestXidStatus = XID_COMMIT;
|
||||
Assert(!IsUnderPostmaster &&
|
||||
ShmemVariableCache->nextXid <= FirstTransactionId);
|
||||
Assert(!IsUnderPostmaster &&
|
||||
ShmemVariableCache->nextXid <= FirstTransactionId);
|
||||
ShmemVariableCache->nextXid = FirstTransactionId;
|
||||
}
|
||||
else if (RecoveryCheckingEnabled())
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.28 2001/01/24 19:42:51 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.29 2001/03/22 03:59:17 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This file contains support functions for the high
|
||||
@@ -186,7 +186,7 @@ TransBlockGetXidStatus(Block tblock,
|
||||
bits8 bit2;
|
||||
BitIndex offset;
|
||||
|
||||
tblock = (Block) ((char*) tblock + sizeof(XLogRecPtr));
|
||||
tblock = (Block) ((char *) tblock + sizeof(XLogRecPtr));
|
||||
|
||||
/* ----------------
|
||||
* calculate the index into the transaction data where
|
||||
@@ -229,7 +229,7 @@ TransBlockSetXidStatus(Block tblock,
|
||||
Index index;
|
||||
BitIndex offset;
|
||||
|
||||
tblock = (Block) ((char*) tblock + sizeof(XLogRecPtr));
|
||||
tblock = (Block) ((char *) tblock + sizeof(XLogRecPtr));
|
||||
|
||||
/* ----------------
|
||||
* calculate the index into the transaction data where
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2000, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.37 2001/03/18 20:18:59 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.38 2001/03/22 03:59:17 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -23,8 +23,8 @@
|
||||
#define VAR_OID_PREFETCH 8192
|
||||
|
||||
/* Spinlocks for serializing generation of XIDs and OIDs, respectively */
|
||||
SPINLOCK XidGenLockId;
|
||||
SPINLOCK OidGenLockId;
|
||||
SPINLOCK XidGenLockId;
|
||||
SPINLOCK OidGenLockId;
|
||||
|
||||
/* pointer to "variable cache" in shared memory (set up by shmem.c) */
|
||||
VariableCache ShmemVariableCache = NULL;
|
||||
@@ -32,9 +32,10 @@ VariableCache ShmemVariableCache = NULL;
|
||||
void
|
||||
GetNewTransactionId(TransactionId *xid)
|
||||
{
|
||||
|
||||
/*
|
||||
* During bootstrap initialization, we return the special
|
||||
* bootstrap transaction id.
|
||||
* During bootstrap initialization, we return the special bootstrap
|
||||
* transaction id.
|
||||
*/
|
||||
if (AMI_OVERRIDE)
|
||||
{
|
||||
@@ -60,9 +61,10 @@ GetNewTransactionId(TransactionId *xid)
|
||||
void
|
||||
ReadNewTransactionId(TransactionId *xid)
|
||||
{
|
||||
|
||||
/*
|
||||
* During bootstrap initialization, we return the special
|
||||
* bootstrap transaction id.
|
||||
* During bootstrap initialization, we return the special bootstrap
|
||||
* transaction id.
|
||||
*/
|
||||
if (AMI_OVERRIDE)
|
||||
{
|
||||
@@ -80,7 +82,7 @@ ReadNewTransactionId(TransactionId *xid)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static Oid lastSeenOid = InvalidOid;
|
||||
static Oid lastSeenOid = InvalidOid;
|
||||
|
||||
void
|
||||
GetNewObjectId(Oid *oid_return)
|
||||
@@ -119,10 +121,10 @@ CheckMaxObjectId(Oid assigned_oid)
|
||||
}
|
||||
|
||||
/* If we are in the logged oid range, just bump nextOid up */
|
||||
if (assigned_oid <= ShmemVariableCache->nextOid +
|
||||
ShmemVariableCache->oidCount - 1)
|
||||
if (assigned_oid <= ShmemVariableCache->nextOid +
|
||||
ShmemVariableCache->oidCount - 1)
|
||||
{
|
||||
ShmemVariableCache->oidCount -=
|
||||
ShmemVariableCache->oidCount -=
|
||||
assigned_oid - ShmemVariableCache->nextOid + 1;
|
||||
ShmemVariableCache->nextOid = assigned_oid + 1;
|
||||
SpinRelease(OidGenLockId);
|
||||
@@ -130,10 +132,9 @@ CheckMaxObjectId(Oid assigned_oid)
|
||||
}
|
||||
|
||||
/*
|
||||
* We have exceeded the logged oid range.
|
||||
* We should lock the database and kill all other backends
|
||||
* but we are loading oid's that we can not guarantee are unique
|
||||
* anyway, so we must rely on the user.
|
||||
* We have exceeded the logged oid range. We should lock the database
|
||||
* and kill all other backends but we are loading oid's that we can
|
||||
* not guarantee are unique anyway, so we must rely on the user.
|
||||
*/
|
||||
|
||||
XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.99 2001/03/13 01:17:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.100 2001/03/22 03:59:18 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Transaction aborts can now occur two ways:
|
||||
@@ -222,9 +222,10 @@ int DefaultXactIsoLevel = XACT_READ_COMMITTED;
|
||||
int XactIsoLevel;
|
||||
|
||||
int CommitDelay = 0; /* precommit delay in microseconds */
|
||||
int CommitSiblings = 5; /* number of concurrent xacts needed to sleep */
|
||||
int CommitSiblings = 5; /* number of concurrent xacts needed to
|
||||
* sleep */
|
||||
|
||||
static void (*_RollbackFunc)(void*) = NULL;
|
||||
static void (*_RollbackFunc) (void *) = NULL;
|
||||
static void *_RollbackData = NULL;
|
||||
|
||||
/* ----------------
|
||||
@@ -666,39 +667,40 @@ RecordTransactionCommit()
|
||||
|
||||
if (MyLastRecPtr.xrecoff != 0)
|
||||
{
|
||||
XLogRecData rdata;
|
||||
xl_xact_commit xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata;
|
||||
xl_xact_commit xlrec;
|
||||
XLogRecPtr recptr;
|
||||
|
||||
BufmgrCommit();
|
||||
|
||||
xlrec.xtime = time(NULL);
|
||||
rdata.buffer = InvalidBuffer;
|
||||
rdata.data = (char *)(&xlrec);
|
||||
rdata.data = (char *) (&xlrec);
|
||||
rdata.len = SizeOfXactCommit;
|
||||
rdata.next = NULL;
|
||||
|
||||
START_CRIT_SECTION();
|
||||
|
||||
/*
|
||||
* SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP
|
||||
*/
|
||||
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, &rdata);
|
||||
|
||||
/*
|
||||
* Sleep before commit! So we can flush more than one
|
||||
* commit records per single fsync. (The idea is some other
|
||||
* backend may do the XLogFlush while we're sleeping. This
|
||||
* needs work still, because on most Unixen, the minimum
|
||||
* select() delay is 10msec or more, which is way too long.)
|
||||
/*
|
||||
* Sleep before commit! So we can flush more than one commit
|
||||
* records per single fsync. (The idea is some other backend may
|
||||
* do the XLogFlush while we're sleeping. This needs work still,
|
||||
* because on most Unixen, the minimum select() delay is 10msec or
|
||||
* more, which is way too long.)
|
||||
*
|
||||
* We do not sleep if enableFsync is not turned on, nor if there
|
||||
* are fewer than CommitSiblings other backends with active
|
||||
* We do not sleep if enableFsync is not turned on, nor if there are
|
||||
* fewer than CommitSiblings other backends with active
|
||||
* transactions.
|
||||
*/
|
||||
if (CommitDelay > 0 && enableFsync &&
|
||||
CountActiveBackends() >= CommitSiblings)
|
||||
{
|
||||
struct timeval delay;
|
||||
struct timeval delay;
|
||||
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_usec = CommitDelay;
|
||||
@@ -812,13 +814,13 @@ RecordTransactionAbort(void)
|
||||
*/
|
||||
if (MyLastRecPtr.xrecoff != 0 && !TransactionIdDidCommit(xid))
|
||||
{
|
||||
XLogRecData rdata;
|
||||
xl_xact_abort xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata;
|
||||
xl_xact_abort xlrec;
|
||||
XLogRecPtr recptr;
|
||||
|
||||
xlrec.xtime = time(NULL);
|
||||
rdata.buffer = InvalidBuffer;
|
||||
rdata.data = (char *)(&xlrec);
|
||||
rdata.data = (char *) (&xlrec);
|
||||
rdata.len = SizeOfXactAbort;
|
||||
rdata.next = NULL;
|
||||
|
||||
@@ -879,7 +881,7 @@ AtAbort_Memory(void)
|
||||
{
|
||||
/* ----------------
|
||||
* Make sure we are in a valid context (not a child of
|
||||
* TransactionCommandContext...). Note that it is possible
|
||||
* TransactionCommandContext...). Note that it is possible
|
||||
* for this code to be called when we aren't in a transaction
|
||||
* at all; go directly to TopMemoryContext in that case.
|
||||
* ----------------
|
||||
@@ -896,9 +898,7 @@ AtAbort_Memory(void)
|
||||
MemoryContextResetAndDeleteChildren(TransactionCommandContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1021,6 +1021,7 @@ CurrentXactInProgress(void)
|
||||
{
|
||||
return CurrentTransactionState->state == TRANS_INPROGRESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------------------------
|
||||
@@ -1106,7 +1107,7 @@ CommitTransaction(void)
|
||||
AtCommit_Memory();
|
||||
AtEOXact_Files();
|
||||
|
||||
SharedBufferChanged = false; /* safest place to do it */
|
||||
SharedBufferChanged = false;/* safest place to do it */
|
||||
|
||||
/* ----------------
|
||||
* done with commit processing, set current transaction
|
||||
@@ -1143,15 +1144,16 @@ AbortTransaction(void)
|
||||
|
||||
/*
|
||||
* Release any spinlocks or buffer context locks we might be holding
|
||||
* as quickly as possible. (Real locks, however, must be held till
|
||||
* we finish aborting.) Releasing spinlocks is critical since we
|
||||
* might try to grab them again while cleaning up!
|
||||
* as quickly as possible. (Real locks, however, must be held till we
|
||||
* finish aborting.) Releasing spinlocks is critical since we might
|
||||
* try to grab them again while cleaning up!
|
||||
*/
|
||||
ProcReleaseSpins(NULL);
|
||||
UnlockBuffers();
|
||||
|
||||
/*
|
||||
* Also clean up any open wait for lock, since the lock manager
|
||||
* will choke if we try to wait for another lock before doing this.
|
||||
* Also clean up any open wait for lock, since the lock manager will
|
||||
* choke if we try to wait for another lock before doing this.
|
||||
*/
|
||||
LockWaitCancel();
|
||||
|
||||
@@ -1203,7 +1205,7 @@ AbortTransaction(void)
|
||||
AtEOXact_Files();
|
||||
AtAbort_Locks();
|
||||
|
||||
SharedBufferChanged = false; /* safest place to do it */
|
||||
SharedBufferChanged = false;/* safest place to do it */
|
||||
|
||||
/* ----------------
|
||||
* State remains TRANS_ABORT until CleanupTransaction().
|
||||
@@ -1327,8 +1329,8 @@ StartTransactionCommand(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* We must switch to TransactionCommandContext before returning.
|
||||
* This is already done if we called StartTransaction, otherwise not.
|
||||
* We must switch to TransactionCommandContext before returning. This
|
||||
* is already done if we called StartTransaction, otherwise not.
|
||||
*/
|
||||
Assert(TransactionCommandContext != NULL);
|
||||
MemoryContextSwitchTo(TransactionCommandContext);
|
||||
@@ -1757,7 +1759,7 @@ IsTransactionBlock(void)
|
||||
void
|
||||
xact_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
if (info == XLOG_XACT_COMMIT)
|
||||
{
|
||||
@@ -1765,9 +1767,7 @@ xact_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
/* SHOULD REMOVE FILES OF ALL DROPPED RELATIONS */
|
||||
}
|
||||
else if (info == XLOG_XACT_ABORT)
|
||||
{
|
||||
TransactionIdAbort(record->xl_xid);
|
||||
}
|
||||
else
|
||||
elog(STOP, "xact_redo: unknown op code %u", info);
|
||||
}
|
||||
@@ -1775,43 +1775,43 @@ xact_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
xact_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
|
||||
if (info == XLOG_XACT_COMMIT) /* shouldn't be called by XLOG */
|
||||
elog(STOP, "xact_undo: can't undo committed xaction");
|
||||
else if (info != XLOG_XACT_ABORT)
|
||||
elog(STOP, "xact_redo: unknown op code %u", info);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xact_desc(char *buf, uint8 xl_info, char* rec)
|
||||
xact_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
|
||||
if (info == XLOG_XACT_COMMIT)
|
||||
{
|
||||
xl_xact_commit *xlrec = (xl_xact_commit*) rec;
|
||||
struct tm *tm = localtime(&xlrec->xtime);
|
||||
xl_xact_commit *xlrec = (xl_xact_commit *) rec;
|
||||
struct tm *tm = localtime(&xlrec->xtime);
|
||||
|
||||
sprintf(buf + strlen(buf), "commit: %04u-%02u-%02u %02u:%02u:%02u",
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
else if (info == XLOG_XACT_ABORT)
|
||||
{
|
||||
xl_xact_abort *xlrec = (xl_xact_abort*) rec;
|
||||
struct tm *tm = localtime(&xlrec->xtime);
|
||||
xl_xact_abort *xlrec = (xl_xact_abort *) rec;
|
||||
struct tm *tm = localtime(&xlrec->xtime);
|
||||
|
||||
sprintf(buf + strlen(buf), "abort: %04u-%02u-%02u %02u:%02u:%02u",
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
||||
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
else
|
||||
strcat(buf, "UNKNOWN");
|
||||
}
|
||||
|
||||
void
|
||||
XactPushRollback(void (*func) (void *), void* data)
|
||||
XactPushRollback(void (*func) (void *), void *data)
|
||||
{
|
||||
#ifdef XLOG_II
|
||||
if (_RollbackFunc != NULL)
|
||||
|
||||
@@ -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.29 2001/01/24 19:42:51 momjian Exp $
|
||||
* $Id: xid.c,v 1.30 2001/03/22 03:59:18 momjian Exp $
|
||||
*
|
||||
* OLD COMMENTS
|
||||
* XXX WARNING
|
||||
@@ -26,8 +26,8 @@
|
||||
/*
|
||||
* TransactionId is typedef'd as uint32, so...
|
||||
*/
|
||||
#define PG_GETARG_TRANSACTIONID(n) PG_GETARG_UINT32(n)
|
||||
#define PG_RETURN_TRANSACTIONID(x) PG_RETURN_UINT32(x)
|
||||
#define PG_GETARG_TRANSACTIONID(n) PG_GETARG_UINT32(n)
|
||||
#define PG_RETURN_TRANSACTIONID(x) PG_RETURN_UINT32(x)
|
||||
|
||||
|
||||
extern TransactionId NullTransactionId;
|
||||
@@ -49,6 +49,7 @@ Datum
|
||||
xidout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
|
||||
|
||||
/* maximum 32 bit unsigned integer representation takes 10 chars */
|
||||
char *representation = palloc(11);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.14 2001/03/13 01:17:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlogutils.c,v 1.15 2001/03/22 03:59:18 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,26 +37,26 @@
|
||||
* xaction/command and return
|
||||
*
|
||||
* - -1 if not
|
||||
* - 0 if there is no tuple at all
|
||||
* - 1 if yes
|
||||
* - 0 if there is no tuple at all
|
||||
* - 1 if yes
|
||||
*/
|
||||
int
|
||||
XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
|
||||
TransactionId xid, CommandId cid)
|
||||
XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
|
||||
TransactionId xid, CommandId cid)
|
||||
{
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
ItemId lp;
|
||||
HeapTupleHeader htup;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
ItemId lp;
|
||||
HeapTupleHeader htup;
|
||||
|
||||
reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
|
||||
if (!RelationIsValid(reln))
|
||||
return(0);
|
||||
return (0);
|
||||
|
||||
buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
|
||||
if (!BufferIsValid(buffer))
|
||||
return(0);
|
||||
return (0);
|
||||
|
||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
@@ -64,13 +64,13 @@ XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
|
||||
ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
|
||||
if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
htup = (HeapTupleHeader) PageGetItem(page, lp);
|
||||
@@ -79,11 +79,11 @@ XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
|
||||
if (htup->t_xmin != xid || htup->t_cmin != cid)
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(-1);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(1);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -95,19 +95,19 @@ XLogIsOwnerOfTuple(RelFileNode hnode, ItemPointer iptr,
|
||||
bool
|
||||
XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr)
|
||||
{
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
ItemId lp;
|
||||
HeapTupleHeader htup;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
ItemId lp;
|
||||
HeapTupleHeader htup;
|
||||
|
||||
reln = XLogOpenRelation(false, RM_HEAP_ID, hnode);
|
||||
if (!RelationIsValid(reln))
|
||||
return(false);
|
||||
return (false);
|
||||
|
||||
buffer = ReadBuffer(reln, ItemPointerGetBlockNumber(iptr));
|
||||
if (!BufferIsValid(buffer))
|
||||
return(false);
|
||||
return (false);
|
||||
|
||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
@@ -115,21 +115,21 @@ XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr)
|
||||
ItemPointerGetOffsetNumber(iptr) > PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(false);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (PageGetSUI(page) != ThisStartUpID)
|
||||
{
|
||||
Assert(PageGetSUI(page) < ThisStartUpID);
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(true);
|
||||
return (true);
|
||||
}
|
||||
|
||||
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(iptr));
|
||||
if (!ItemIdIsUsed(lp) || ItemIdDeleted(lp))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(false);
|
||||
return (false);
|
||||
}
|
||||
|
||||
htup = (HeapTupleHeader) PageGetItem(page, lp);
|
||||
@@ -140,22 +140,22 @@ XLogIsValidTuple(RelFileNode hnode, ItemPointer iptr)
|
||||
{
|
||||
if (htup->t_infomask & HEAP_XMIN_INVALID ||
|
||||
(htup->t_infomask & HEAP_MOVED_IN &&
|
||||
TransactionIdDidAbort((TransactionId)htup->t_cmin)) ||
|
||||
TransactionIdDidAbort((TransactionId) htup->t_cmin)) ||
|
||||
TransactionIdDidAbort(htup->t_xmin))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(false);
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
return(true);
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open pg_log in recovery
|
||||
*/
|
||||
extern Relation LogRelation; /* pg_log relation */
|
||||
extern Relation LogRelation; /* pg_log relation */
|
||||
|
||||
void
|
||||
XLogOpenLogRelation(void)
|
||||
@@ -189,32 +189,32 @@ XLogOpenLogRelation(void)
|
||||
Buffer
|
||||
XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno)
|
||||
{
|
||||
BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
|
||||
BlockNumber lastblock = RelationGetNumberOfBlocks(reln);
|
||||
Buffer buffer;
|
||||
|
||||
if (blkno >= lastblock)
|
||||
{
|
||||
buffer = InvalidBuffer;
|
||||
if (extend) /* we do this in recovery only - no locks */
|
||||
if (extend) /* we do this in recovery only - no locks */
|
||||
{
|
||||
Assert(InRecovery);
|
||||
while (lastblock <= blkno)
|
||||
{
|
||||
if (buffer != InvalidBuffer)
|
||||
ReleaseBuffer(buffer); /* must be WriteBuffer()? */
|
||||
ReleaseBuffer(buffer); /* must be WriteBuffer()? */
|
||||
buffer = ReadBuffer(reln, P_NEW);
|
||||
lastblock++;
|
||||
}
|
||||
}
|
||||
if (buffer != InvalidBuffer)
|
||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
return(buffer);
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
buffer = ReadBuffer(reln, blkno);
|
||||
if (buffer != InvalidBuffer)
|
||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||
return(buffer);
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -223,32 +223,33 @@ XLogReadBuffer(bool extend, Relation reln, BlockNumber blkno)
|
||||
|
||||
typedef struct XLogRelDesc
|
||||
{
|
||||
RelationData reldata;
|
||||
struct XLogRelDesc *lessRecently;
|
||||
struct XLogRelDesc *moreRecently;
|
||||
RelationData reldata;
|
||||
struct XLogRelDesc *lessRecently;
|
||||
struct XLogRelDesc *moreRecently;
|
||||
} XLogRelDesc;
|
||||
|
||||
typedef struct XLogRelCacheEntry
|
||||
{
|
||||
RelFileNode rnode;
|
||||
XLogRelDesc *rdesc;
|
||||
RelFileNode rnode;
|
||||
XLogRelDesc *rdesc;
|
||||
} XLogRelCacheEntry;
|
||||
|
||||
static HTAB *_xlrelcache;
|
||||
static XLogRelDesc *_xlrelarr = NULL;
|
||||
static Form_pg_class _xlpgcarr = NULL;
|
||||
static int _xlast = 0;
|
||||
static int _xlcnt = 0;
|
||||
#define _XLOG_RELCACHESIZE 512
|
||||
static HTAB *_xlrelcache;
|
||||
static XLogRelDesc *_xlrelarr = NULL;
|
||||
static Form_pg_class _xlpgcarr = NULL;
|
||||
static int _xlast = 0;
|
||||
static int _xlcnt = 0;
|
||||
|
||||
#define _XLOG_RELCACHESIZE 512
|
||||
|
||||
static void
|
||||
_xl_init_rel_cache(void)
|
||||
{
|
||||
HASHCTL ctl;
|
||||
HASHCTL ctl;
|
||||
|
||||
_xlcnt = _XLOG_RELCACHESIZE;
|
||||
_xlast = 0;
|
||||
_xlrelarr = (XLogRelDesc*) malloc(sizeof(XLogRelDesc) * _xlcnt);
|
||||
_xlrelarr = (XLogRelDesc *) malloc(sizeof(XLogRelDesc) * _xlcnt);
|
||||
memset(_xlrelarr, 0, sizeof(XLogRelDesc) * _xlcnt);
|
||||
_xlpgcarr = (Form_pg_class) malloc(sizeof(FormData_pg_class) * _xlcnt);
|
||||
memset(_xlpgcarr, 0, sizeof(FormData_pg_class) * _xlcnt);
|
||||
@@ -258,26 +259,26 @@ _xl_init_rel_cache(void)
|
||||
|
||||
memset(&ctl, 0, (int) sizeof(ctl));
|
||||
ctl.keysize = sizeof(RelFileNode);
|
||||
ctl.datasize = sizeof(XLogRelDesc*);
|
||||
ctl.datasize = sizeof(XLogRelDesc *);
|
||||
ctl.hash = tag_hash;
|
||||
|
||||
_xlrelcache = hash_create(_XLOG_RELCACHESIZE, &ctl,
|
||||
HASH_ELEM | HASH_FUNCTION);
|
||||
HASH_ELEM | HASH_FUNCTION);
|
||||
}
|
||||
|
||||
static void
|
||||
_xl_remove_hash_entry(XLogRelDesc **edata, Datum dummy)
|
||||
{
|
||||
XLogRelCacheEntry *hentry;
|
||||
bool found;
|
||||
XLogRelDesc *rdesc = *edata;
|
||||
Form_pg_class tpgc = rdesc->reldata.rd_rel;
|
||||
XLogRelCacheEntry *hentry;
|
||||
bool found;
|
||||
XLogRelDesc *rdesc = *edata;
|
||||
Form_pg_class tpgc = rdesc->reldata.rd_rel;
|
||||
|
||||
rdesc->lessRecently->moreRecently = rdesc->moreRecently;
|
||||
rdesc->moreRecently->lessRecently = rdesc->lessRecently;
|
||||
|
||||
hentry = (XLogRelCacheEntry*) hash_search(_xlrelcache,
|
||||
(char*)&(rdesc->reldata.rd_node), HASH_REMOVE, &found);
|
||||
hentry = (XLogRelCacheEntry *) hash_search(_xlrelcache,
|
||||
(char *) &(rdesc->reldata.rd_node), HASH_REMOVE, &found);
|
||||
|
||||
if (hentry == NULL)
|
||||
elog(STOP, "_xl_remove_hash_entry: can't delete from cache");
|
||||
@@ -294,16 +295,16 @@ _xl_remove_hash_entry(XLogRelDesc **edata, Datum dummy)
|
||||
return;
|
||||
}
|
||||
|
||||
static XLogRelDesc*
|
||||
static XLogRelDesc *
|
||||
_xl_new_reldesc(void)
|
||||
{
|
||||
XLogRelDesc *res;
|
||||
XLogRelDesc *res;
|
||||
|
||||
_xlast++;
|
||||
if (_xlast < _xlcnt)
|
||||
{
|
||||
_xlrelarr[_xlast].reldata.rd_rel = &(_xlpgcarr[_xlast]);
|
||||
return(&(_xlrelarr[_xlast]));
|
||||
return (&(_xlrelarr[_xlast]));
|
||||
}
|
||||
|
||||
/* reuse */
|
||||
@@ -312,7 +313,7 @@ _xl_new_reldesc(void)
|
||||
_xl_remove_hash_entry(&res, 0);
|
||||
|
||||
_xlast--;
|
||||
return(res);
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
@@ -344,12 +345,12 @@ XLogCloseRelationCache(void)
|
||||
Relation
|
||||
XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
|
||||
{
|
||||
XLogRelDesc *res;
|
||||
XLogRelCacheEntry *hentry;
|
||||
bool found;
|
||||
XLogRelDesc *res;
|
||||
XLogRelCacheEntry *hentry;
|
||||
bool found;
|
||||
|
||||
hentry = (XLogRelCacheEntry*)
|
||||
hash_search(_xlrelcache, (char*)&rnode, HASH_FIND, &found);
|
||||
hentry = (XLogRelCacheEntry *)
|
||||
hash_search(_xlrelcache, (char *) &rnode, HASH_FIND, &found);
|
||||
|
||||
if (hentry == NULL)
|
||||
elog(STOP, "XLogOpenRelation: error in cache");
|
||||
@@ -372,8 +373,8 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
|
||||
res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
|
||||
res->reldata.rd_node = rnode;
|
||||
|
||||
hentry = (XLogRelCacheEntry*)
|
||||
hash_search(_xlrelcache, (char*)&rnode, HASH_ENTER, &found);
|
||||
hentry = (XLogRelCacheEntry *)
|
||||
hash_search(_xlrelcache, (char *) &rnode, HASH_ENTER, &found);
|
||||
|
||||
if (hentry == NULL)
|
||||
elog(STOP, "XLogOpenRelation: can't insert into cache");
|
||||
@@ -385,7 +386,7 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
|
||||
|
||||
res->reldata.rd_fd = -1;
|
||||
res->reldata.rd_fd = smgropen(DEFAULT_SMGR, &(res->reldata),
|
||||
true /* allow failure */);
|
||||
true /* allow failure */ );
|
||||
}
|
||||
|
||||
res->moreRecently = &(_xlrelarr[0]);
|
||||
@@ -393,8 +394,8 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
|
||||
_xlrelarr[0].lessRecently = res;
|
||||
res->lessRecently->moreRecently = res;
|
||||
|
||||
if (res->reldata.rd_fd < 0) /* file doesn't exist */
|
||||
return(NULL);
|
||||
if (res->reldata.rd_fd < 0) /* file doesn't exist */
|
||||
return (NULL);
|
||||
|
||||
return(&(res->reldata));
|
||||
return (&(res->reldata));
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.46 2001/01/24 19:42:51 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.47 2001/03/22 03:59:18 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* See acl.h.
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
static int32 aclcheck(char *relname, Acl *acl, AclId id,
|
||||
AclIdType idtype, AclMode mode);
|
||||
AclIdType idtype, AclMode mode);
|
||||
|
||||
/* warning messages, now more explicit. */
|
||||
/* MUST correspond to the order of the ACLCHK_* result codes in acl.h. */
|
||||
@@ -59,7 +59,7 @@ dumpacl(Acl *acl)
|
||||
for (i = 0; i < ACL_NUM(acl); ++i)
|
||||
elog(DEBUG, " acl[%d]: %s", i,
|
||||
DatumGetCString(DirectFunctionCall1(aclitemout,
|
||||
PointerGetDatum(aip + i))));
|
||||
PointerGetDatum(aip + i))));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -250,8 +250,8 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
|
||||
num;
|
||||
|
||||
/*
|
||||
* If ACL is null, default to "OK" --- this should not happen,
|
||||
* since caller should have inserted appropriate default
|
||||
* If ACL is null, default to "OK" --- this should not happen, since
|
||||
* caller should have inserted appropriate default
|
||||
*/
|
||||
if (!acl)
|
||||
{
|
||||
@@ -265,8 +265,8 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
|
||||
/*
|
||||
* We'll treat the empty ACL like that, too, although this is more
|
||||
* like an error (i.e., you manually blew away your ACL array) -- the
|
||||
* system never creates an empty ACL, since there must always be
|
||||
* a "world" entry in the first slot.
|
||||
* system never creates an empty ACL, since there must always be a
|
||||
* "world" entry in the first slot.
|
||||
*/
|
||||
if (num < 1)
|
||||
{
|
||||
@@ -352,7 +352,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
|
||||
{
|
||||
int32 result;
|
||||
HeapTuple tuple;
|
||||
char *usename;
|
||||
char *usename;
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
Acl *acl;
|
||||
@@ -439,7 +439,7 @@ pg_ownercheck(Oid userid,
|
||||
{
|
||||
HeapTuple tuple;
|
||||
AclId owner_id;
|
||||
char *usename;
|
||||
char *usename;
|
||||
|
||||
tuple = SearchSysCache(SHADOWSYSID,
|
||||
ObjectIdGetDatum(userid),
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.39 2001/01/24 19:42:51 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.40 2001/03/22 03:59:19 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -105,7 +105,7 @@ relpath_blind(const char *dbname, const char *relname,
|
||||
return path;
|
||||
}
|
||||
|
||||
#else /* ! OLD_FILE_NAMING */
|
||||
#else /* ! OLD_FILE_NAMING */
|
||||
|
||||
/*
|
||||
* relpath - construct path to a relation's file
|
||||
@@ -118,7 +118,7 @@ relpath(RelFileNode rnode)
|
||||
{
|
||||
char *path;
|
||||
|
||||
if (rnode.tblNode == (Oid) 0) /* "global tablespace" */
|
||||
if (rnode.tblNode == (Oid) 0) /* "global tablespace" */
|
||||
{
|
||||
/* Shared system relations live in {datadir}/global */
|
||||
path = (char *) palloc(strlen(DataDir) + 8 + sizeof(NameData) + 1);
|
||||
@@ -127,8 +127,8 @@ relpath(RelFileNode rnode)
|
||||
else
|
||||
{
|
||||
path = (char *) palloc(strlen(DataDir) + 6 + 2 * sizeof(NameData) + 3);
|
||||
sprintf(path, "%s%cbase%c%u%c%u", DataDir, SEP_CHAR, SEP_CHAR,
|
||||
rnode.tblNode, SEP_CHAR, rnode.relNode);
|
||||
sprintf(path, "%s%cbase%c%u%c%u", DataDir, SEP_CHAR, SEP_CHAR,
|
||||
rnode.tblNode, SEP_CHAR, rnode.relNode);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
@@ -144,7 +144,7 @@ GetDatabasePath(Oid tblNode)
|
||||
{
|
||||
char *path;
|
||||
|
||||
if (tblNode == (Oid) 0) /* "global tablespace" */
|
||||
if (tblNode == (Oid) 0) /* "global tablespace" */
|
||||
{
|
||||
/* Shared system relations live in {datadir}/global */
|
||||
path = (char *) palloc(strlen(DataDir) + 8);
|
||||
@@ -158,7 +158,7 @@ GetDatabasePath(Oid tblNode)
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
|
||||
/*
|
||||
* IsSystemRelationName
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.160 2001/02/14 21:34:59 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.161 2001/03/22 03:59:19 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
|
||||
static void AddNewRelationTuple(Relation pg_class_desc,
|
||||
Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
|
||||
Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid,
|
||||
int natts, char relkind, char *temp_relname);
|
||||
static void DeleteAttributeTuples(Relation rel);
|
||||
static void DeleteRelationTuple(Relation rel);
|
||||
@@ -76,7 +76,7 @@ static void DeleteTypeTuple(Relation rel);
|
||||
static void RelationRemoveIndexes(Relation relation);
|
||||
static void RelationRemoveInheritance(Relation relation);
|
||||
static void AddNewRelationType(char *typeName, Oid new_rel_oid,
|
||||
Oid new_type_oid);
|
||||
Oid new_type_oid);
|
||||
static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
|
||||
bool updatePgAttribute);
|
||||
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
|
||||
@@ -178,13 +178,13 @@ heap_create(char *relname,
|
||||
{
|
||||
static unsigned int uniqueId = 0;
|
||||
|
||||
Oid relid;
|
||||
Relation rel;
|
||||
bool nailme = false;
|
||||
int natts = tupDesc->natts;
|
||||
int i;
|
||||
MemoryContext oldcxt;
|
||||
Oid tblNode = MyDatabaseId;
|
||||
Oid relid;
|
||||
Relation rel;
|
||||
bool nailme = false;
|
||||
int natts = tupDesc->natts;
|
||||
int i;
|
||||
MemoryContext oldcxt;
|
||||
Oid tblNode = MyDatabaseId;
|
||||
|
||||
/* ----------------
|
||||
* sanity checks
|
||||
@@ -270,7 +270,11 @@ heap_create(char *relname,
|
||||
|
||||
if (istemp)
|
||||
{
|
||||
/* replace relname of caller with a unique name for a temp relation */
|
||||
|
||||
/*
|
||||
* replace relname of caller with a unique name for a temp
|
||||
* relation
|
||||
*/
|
||||
snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u",
|
||||
(int) MyProcPid, uniqueId++);
|
||||
}
|
||||
@@ -738,6 +742,7 @@ AddNewRelationTuple(Relation pg_class_desc,
|
||||
static void
|
||||
AddNewRelationType(char *typeName, Oid new_rel_oid, Oid new_type_oid)
|
||||
{
|
||||
|
||||
/*
|
||||
* The sizes are set to oid size because it makes implementing sets
|
||||
* MUCH easier, and no one (we hope) uses these fields to figure out
|
||||
@@ -1025,9 +1030,7 @@ RelationRemoveInheritance(Relation relation)
|
||||
&entry);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
simple_heap_delete(catalogRelation, &tuple->t_self);
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
heap_close(catalogRelation, RowExclusiveLock);
|
||||
@@ -1152,8 +1155,8 @@ RelationTruncateIndexes(Oid heapId)
|
||||
/*
|
||||
* We have to re-open the heap rel each time through this loop
|
||||
* because index_build will close it again. We need grab no lock,
|
||||
* however, because we assume heap_truncate is holding an exclusive
|
||||
* lock on the heap rel.
|
||||
* however, because we assume heap_truncate is holding an
|
||||
* exclusive lock on the heap rel.
|
||||
*/
|
||||
heapRelation = heap_open(heapId, NoLock);
|
||||
|
||||
@@ -1164,8 +1167,8 @@ RelationTruncateIndexes(Oid heapId)
|
||||
LockRelation(currentIndex, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* Drop any buffers associated with this index. If they're
|
||||
* dirty, they're just dropped without bothering to flush to disk.
|
||||
* Drop any buffers associated with this index. If they're dirty,
|
||||
* they're just dropped without bothering to flush to disk.
|
||||
*/
|
||||
DropRelationBuffers(currentIndex);
|
||||
|
||||
@@ -1177,6 +1180,7 @@ RelationTruncateIndexes(Oid heapId)
|
||||
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
|
||||
currentIndex, accessMethodId);
|
||||
index_build(heapRelation, currentIndex, indexInfo, NULL);
|
||||
|
||||
/*
|
||||
* index_build will close both the heap and index relations (but
|
||||
* not give up the locks we hold on them).
|
||||
@@ -1514,7 +1518,7 @@ heap_drop_with_catalog(const char *relname,
|
||||
|
||||
if (has_toasttable)
|
||||
{
|
||||
char toast_relname[NAMEDATALEN];
|
||||
char toast_relname[NAMEDATALEN];
|
||||
|
||||
sprintf(toast_relname, "pg_toast_%u", rid);
|
||||
heap_drop_with_catalog(toast_relname, true);
|
||||
@@ -1553,16 +1557,16 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
|
||||
* deparse it
|
||||
*/
|
||||
adsrc = deparse_expression(expr,
|
||||
deparse_context_for(RelationGetRelationName(rel),
|
||||
RelationGetRelid(rel)),
|
||||
deparse_context_for(RelationGetRelationName(rel),
|
||||
RelationGetRelid(rel)),
|
||||
false);
|
||||
|
||||
values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
|
||||
values[Anum_pg_attrdef_adnum - 1] = attnum;
|
||||
values[Anum_pg_attrdef_adbin - 1] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(adbin));
|
||||
CStringGetDatum(adbin));
|
||||
values[Anum_pg_attrdef_adsrc - 1] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(adsrc));
|
||||
CStringGetDatum(adsrc));
|
||||
adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);
|
||||
tuple = heap_formtuple(adrel->rd_att, values, nulls);
|
||||
heap_insert(adrel, tuple);
|
||||
@@ -1631,17 +1635,17 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
|
||||
* deparse it
|
||||
*/
|
||||
ccsrc = deparse_expression(expr,
|
||||
deparse_context_for(RelationGetRelationName(rel),
|
||||
RelationGetRelid(rel)),
|
||||
deparse_context_for(RelationGetRelationName(rel),
|
||||
RelationGetRelid(rel)),
|
||||
false);
|
||||
|
||||
values[Anum_pg_relcheck_rcrelid - 1] = RelationGetRelid(rel);
|
||||
values[Anum_pg_relcheck_rcname - 1] = DirectFunctionCall1(namein,
|
||||
CStringGetDatum(ccname));
|
||||
CStringGetDatum(ccname));
|
||||
values[Anum_pg_relcheck_rcbin - 1] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(ccbin));
|
||||
CStringGetDatum(ccbin));
|
||||
values[Anum_pg_relcheck_rcsrc - 1] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(ccsrc));
|
||||
CStringGetDatum(ccsrc));
|
||||
rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock);
|
||||
tuple = heap_formtuple(rcrel->rd_att, values, nulls);
|
||||
heap_insert(rcrel, tuple);
|
||||
@@ -1981,9 +1985,7 @@ RemoveAttrDefault(Relation rel)
|
||||
adscan = heap_beginscan(adrel, 0, SnapshotNow, 1, &key);
|
||||
|
||||
while (HeapTupleIsValid(tup = heap_getnext(adscan, 0)))
|
||||
{
|
||||
simple_heap_delete(adrel, &tup->t_self);
|
||||
}
|
||||
|
||||
heap_endscan(adscan);
|
||||
heap_close(adrel, RowExclusiveLock);
|
||||
@@ -2005,9 +2007,7 @@ RemoveRelCheck(Relation rel)
|
||||
rcscan = heap_beginscan(rcrel, 0, SnapshotNow, 1, &key);
|
||||
|
||||
while (HeapTupleIsValid(tup = heap_getnext(rcscan, 0)))
|
||||
{
|
||||
simple_heap_delete(rcrel, &tup->t_self);
|
||||
}
|
||||
|
||||
heap_endscan(rcscan);
|
||||
heap_close(rcrel, RowExclusiveLock);
|
||||
@@ -2044,9 +2044,7 @@ RemoveStatistics(Relation rel)
|
||||
scan = heap_beginscan(pgstatistic, false, SnapshotNow, 1, &key);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
simple_heap_delete(pgstatistic, &tuple->t_self);
|
||||
}
|
||||
|
||||
heap_endscan(scan);
|
||||
heap_close(pgstatistic, RowExclusiveLock);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.142 2001/02/23 09:31:52 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.143 2001/03/22 03:59:19 momjian Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -63,19 +63,19 @@ static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
|
||||
bool istemp);
|
||||
static TupleDesc BuildFuncTupleDesc(Oid funcOid);
|
||||
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
|
||||
int numatts, AttrNumber *attNums);
|
||||
int numatts, AttrNumber *attNums);
|
||||
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 islossy, bool primary);
|
||||
IndexInfo *indexInfo,
|
||||
Oid *classOids,
|
||||
bool islossy, bool primary);
|
||||
static void DefaultBuild(Relation heapRelation, Relation indexRelation,
|
||||
IndexInfo *indexInfo, Node *oldPred,
|
||||
IndexStrategy indexStrategy);
|
||||
IndexInfo *indexInfo, Node *oldPred,
|
||||
IndexStrategy indexStrategy);
|
||||
static Oid IndexGetRelation(Oid indexId);
|
||||
static bool activate_index(Oid indexId, bool activate, bool inplace);
|
||||
|
||||
@@ -301,7 +301,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
||||
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
|
||||
|
||||
/*
|
||||
* Fix the stuff that should not be the same as the underlying attr
|
||||
* Fix the stuff that should not be the same as the underlying
|
||||
* attr
|
||||
*/
|
||||
to->attnum = i + 1;
|
||||
|
||||
@@ -311,9 +312,9 @@ ConstructTupleDescriptor(Relation heapRelation,
|
||||
to->attcacheoff = -1;
|
||||
|
||||
/*
|
||||
* We do not yet have the correct relation OID for the index,
|
||||
* so just set it invalid for now. InitializeAttributeOids()
|
||||
* will fix it later.
|
||||
* We do not yet have the correct relation OID for the index, so
|
||||
* just set it invalid for now. InitializeAttributeOids() will
|
||||
* fix it later.
|
||||
*/
|
||||
to->attrelid = InvalidOid;
|
||||
}
|
||||
@@ -331,7 +332,7 @@ ConstructTupleDescriptor(Relation heapRelation,
|
||||
* typically CacheMemoryContext).
|
||||
*
|
||||
* There was a note here about adding indexing, but I don't see a need
|
||||
* for it. There are so few tuples in pg_am that an indexscan would
|
||||
* for it. There are so few tuples in pg_am that an indexscan would
|
||||
* surely be slower.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
@@ -394,7 +395,7 @@ static void
|
||||
ConstructIndexReldesc(Relation indexRelation, Oid amoid)
|
||||
{
|
||||
indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid,
|
||||
CacheMemoryContext);
|
||||
CacheMemoryContext);
|
||||
|
||||
/* ----------------
|
||||
* XXX missing the initialization of some other fields
|
||||
@@ -625,12 +626,12 @@ UpdateIndexRelation(Oid indexoid,
|
||||
{
|
||||
predString = nodeToString(indexInfo->ii_Predicate);
|
||||
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
||||
CStringGetDatum(predString)));
|
||||
CStringGetDatum(predString)));
|
||||
pfree(predString);
|
||||
}
|
||||
else
|
||||
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
||||
CStringGetDatum("")));
|
||||
CStringGetDatum("")));
|
||||
|
||||
predLen = VARSIZE(predText);
|
||||
itupLen = predLen + sizeof(FormData_pg_index);
|
||||
@@ -646,7 +647,7 @@ UpdateIndexRelation(Oid indexoid,
|
||||
indexForm->indproc = indexInfo->ii_FuncOid;
|
||||
indexForm->indisclustered = false;
|
||||
indexForm->indislossy = islossy;
|
||||
indexForm->indhaskeytype = true; /* not actually used anymore */
|
||||
indexForm->indhaskeytype = true; /* not actually used anymore */
|
||||
indexForm->indisunique = indexInfo->ii_Unique;
|
||||
indexForm->indisprimary = primary;
|
||||
memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
|
||||
@@ -747,12 +748,12 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
|
||||
{
|
||||
predString = nodeToString(newPred);
|
||||
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
||||
CStringGetDatum(predString)));
|
||||
CStringGetDatum(predString)));
|
||||
pfree(predString);
|
||||
}
|
||||
else
|
||||
predText = DatumGetTextP(DirectFunctionCall1(textin,
|
||||
CStringGetDatum("")));
|
||||
CStringGetDatum("")));
|
||||
|
||||
/* open the index system catalog relation */
|
||||
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
|
||||
@@ -911,15 +912,15 @@ index_create(char *heapRelationName,
|
||||
else
|
||||
indexTupDesc = ConstructTupleDescriptor(heapRelation,
|
||||
indexInfo->ii_NumKeyAttrs,
|
||||
indexInfo->ii_KeyAttrNumbers);
|
||||
indexInfo->ii_KeyAttrNumbers);
|
||||
|
||||
if (istemp)
|
||||
{
|
||||
/* save user relation name because heap_create changes it */
|
||||
temp_relname = pstrdup(indexRelationName); /* save original value */
|
||||
temp_relname = pstrdup(indexRelationName); /* save original value */
|
||||
indexRelationName = palloc(NAMEDATALEN);
|
||||
strcpy(indexRelationName, temp_relname); /* heap_create will
|
||||
* change this */
|
||||
strcpy(indexRelationName, temp_relname); /* heap_create will
|
||||
* change this */
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
@@ -1008,9 +1009,7 @@ index_create(char *heapRelationName,
|
||||
/* XXX shouldn't we close the heap and index rels here? */
|
||||
}
|
||||
else
|
||||
{
|
||||
index_build(heapRelation, indexRelation, indexInfo, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -1081,12 +1080,12 @@ index_drop(Oid indexId)
|
||||
heap_freetuple(tuple);
|
||||
|
||||
/*
|
||||
* Update the pg_class tuple for the owning relation. We are presently
|
||||
* too lazy to attempt to compute the new correct value of relhasindex
|
||||
* (the next VACUUM will fix it if necessary). But we must send out a
|
||||
* shared-cache-inval notice on the owning relation to ensure other
|
||||
* backends update their relcache lists of indexes. So, unconditionally
|
||||
* do setRelhasindex(true).
|
||||
* Update the pg_class tuple for the owning relation. We are
|
||||
* presently too lazy to attempt to compute the new correct value of
|
||||
* relhasindex (the next VACUUM will fix it if necessary). But we
|
||||
* must send out a shared-cache-inval notice on the owning relation to
|
||||
* ensure other backends update their relcache lists of indexes. So,
|
||||
* unconditionally do setRelhasindex(true).
|
||||
*/
|
||||
setRelhasindex(heapId, true);
|
||||
|
||||
@@ -1160,11 +1159,11 @@ index_drop(Oid indexId)
|
||||
*
|
||||
* IndexInfo stores the information about the index that's needed by
|
||||
* FormIndexDatum, which is used for both index_build() and later insertion
|
||||
* of individual index tuples. Normally we build an IndexInfo for an index
|
||||
* of individual index tuples. Normally we build an IndexInfo for an index
|
||||
* 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);
|
||||
@@ -1199,7 +1198,7 @@ BuildIndexInfo(HeapTuple indexTuple)
|
||||
{
|
||||
ii->ii_NumIndexAttrs = 1;
|
||||
/* Do a lookup on the function, too */
|
||||
fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
|
||||
fmgr_info(indexStruct->indproc, &ii->ii_FuncInfo);
|
||||
}
|
||||
else
|
||||
ii->ii_NumIndexAttrs = numKeys;
|
||||
@@ -1213,7 +1212,7 @@ BuildIndexInfo(HeapTuple indexTuple)
|
||||
char *predString;
|
||||
|
||||
predString = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(&indexStruct->indpred)));
|
||||
PointerGetDatum(&indexStruct->indpred)));
|
||||
ii->ii_Predicate = stringToNode(predString);
|
||||
pfree(predString);
|
||||
}
|
||||
@@ -1262,8 +1261,8 @@ FormIndexDatum(IndexInfo *indexInfo,
|
||||
* Functional index --- compute the single index attribute
|
||||
* ----------------
|
||||
*/
|
||||
FunctionCallInfoData fcinfo;
|
||||
bool anynull = false;
|
||||
FunctionCallInfoData fcinfo;
|
||||
bool anynull = false;
|
||||
|
||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||
fcinfo.flinfo = &indexInfo->ii_FuncInfo;
|
||||
@@ -1326,8 +1325,8 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
|
||||
Relation relationRelation;
|
||||
|
||||
/*
|
||||
* NOTE: get and hold RowExclusiveLock on pg_class, because caller will
|
||||
* probably modify the rel's pg_class tuple later on.
|
||||
* NOTE: get and hold RowExclusiveLock on pg_class, because caller
|
||||
* will probably modify the rel's pg_class tuple later on.
|
||||
*/
|
||||
relationRelation = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||
classTuple = SearchSysCache(RELOID, PointerGetDatum(relid),
|
||||
@@ -1342,7 +1341,7 @@ LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
|
||||
|
||||
while (1)
|
||||
{
|
||||
ItemPointerData tidsave;
|
||||
ItemPointerData tidsave;
|
||||
|
||||
ItemPointerCopy(&(rtup->t_self), &tidsave);
|
||||
test = heap_mark4update(relationRelation, rtup, buffer);
|
||||
@@ -1393,7 +1392,7 @@ IndexesAreActive(Oid relid, bool confirmCommitted)
|
||||
if (!LockClassinfoForUpdate(relid, &tuple, &buffer, confirmCommitted))
|
||||
elog(ERROR, "IndexesAreActive couldn't lock %u", relid);
|
||||
if (((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_RELATION &&
|
||||
((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
|
||||
((Form_pg_class) GETSTRUCT(&tuple))->relkind != RELKIND_TOASTVALUE)
|
||||
elog(ERROR, "relation %u isn't an indexable relation", relid);
|
||||
isactive = ((Form_pg_class) GETSTRUCT(&tuple))->relhasindex;
|
||||
ReleaseBuffer(buffer);
|
||||
@@ -1438,7 +1437,7 @@ setRelhasindex(Oid relid, bool hasindex)
|
||||
if (!IsIgnoringSystemIndexes())
|
||||
#else
|
||||
if (!IsIgnoringSystemIndexes() && (!IsReindexProcessing() || pg_class->rd_rel->relhasindex))
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
{
|
||||
tuple = SearchSysCacheCopy(RELOID,
|
||||
ObjectIdGetDatum(relid),
|
||||
@@ -1513,18 +1512,19 @@ setRelhasindex(Oid relid, bool hasindex)
|
||||
void
|
||||
setNewRelfilenode(Relation relation)
|
||||
{
|
||||
Relation pg_class, idescs[Num_pg_class_indices];
|
||||
Oid newrelfilenode;
|
||||
Relation pg_class,
|
||||
idescs[Num_pg_class_indices];
|
||||
Oid newrelfilenode;
|
||||
bool in_place_update = false;
|
||||
HeapTupleData lockTupleData;
|
||||
HeapTuple classTuple = NULL;
|
||||
HeapTupleData lockTupleData;
|
||||
HeapTuple classTuple = NULL;
|
||||
Buffer buffer;
|
||||
RelationData workrel;
|
||||
|
||||
RelationData workrel;
|
||||
|
||||
Assert(!IsSystemRelationName(NameStr(relation->rd_rel->relname)) || relation->rd_rel->relkind == RELKIND_INDEX);
|
||||
|
||||
pg_class = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||
/* Fetch and lock the classTuple associated with this relation */
|
||||
/* Fetch and lock the classTuple associated with this relation */
|
||||
if (!LockClassinfoForUpdate(relation->rd_id, &lockTupleData, &buffer, true))
|
||||
elog(ERROR, "setNewRelfilenode impossible to lock class tuple");
|
||||
if (IsIgnoringSystemIndexes())
|
||||
@@ -1567,7 +1567,7 @@ setNewRelfilenode(Relation relation)
|
||||
if (!in_place_update && pg_class->rd_rel->relhasindex)
|
||||
{
|
||||
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
|
||||
idescs);
|
||||
idescs);
|
||||
CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, classTuple);
|
||||
CatalogCloseIndices(Num_pg_class_indices, idescs);
|
||||
}
|
||||
@@ -1577,7 +1577,8 @@ setNewRelfilenode(Relation relation)
|
||||
/* Make sure the relfilenode change */
|
||||
CommandCounterIncrement();
|
||||
}
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
|
||||
/* ----------------
|
||||
* UpdateStats
|
||||
@@ -1639,7 +1640,7 @@ UpdateStats(Oid relid, long reltuples)
|
||||
in_place_upd = (IsReindexProcessing() || IsBootstrapProcessingMode());
|
||||
#else
|
||||
in_place_upd = (IsIgnoringSystemIndexes() || IsReindexProcessing());
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
|
||||
if (!in_place_upd)
|
||||
{
|
||||
@@ -1713,9 +1714,10 @@ UpdateStats(Oid relid, long 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.
|
||||
* visibility of changes, so we cheat. Also cheat if REINDEX.
|
||||
*/
|
||||
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
||||
@@ -1777,7 +1779,7 @@ DefaultBuild(Relation heapRelation,
|
||||
Relation indexRelation,
|
||||
IndexInfo *indexInfo,
|
||||
Node *oldPred,
|
||||
IndexStrategy indexStrategy) /* not used */
|
||||
IndexStrategy indexStrategy) /* not used */
|
||||
{
|
||||
HeapScanDesc scan;
|
||||
HeapTuple heapTuple;
|
||||
@@ -1787,9 +1789,11 @@ DefaultBuild(Relation heapRelation,
|
||||
long reltuples,
|
||||
indtuples;
|
||||
Node *predicate = indexInfo->ii_Predicate;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
TupleTable tupleTable;
|
||||
TupleTableSlot *slot;
|
||||
|
||||
#endif
|
||||
ExprContext *econtext;
|
||||
InsertIndexResult insertResult;
|
||||
@@ -1855,6 +1859,7 @@ DefaultBuild(Relation heapRelation,
|
||||
reltuples++;
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
|
||||
/*
|
||||
* If oldPred != NULL, this is an EXTEND INDEX command, so skip
|
||||
* this tuple if it was already in the existing partial index
|
||||
@@ -1906,9 +1911,7 @@ DefaultBuild(Relation heapRelation,
|
||||
|
||||
#ifndef OMIT_PARTIAL_INDEX
|
||||
if (predicate != NULL || oldPred != NULL)
|
||||
{
|
||||
ExecDropTupleTable(tupleTable, true);
|
||||
}
|
||||
#endif /* OMIT_PARTIAL_INDEX */
|
||||
FreeExprContext(econtext);
|
||||
|
||||
@@ -1972,7 +1975,7 @@ index_build(Relation heapRelation,
|
||||
PointerGetDatum(indexRelation),
|
||||
PointerGetDatum(indexInfo),
|
||||
PointerGetDatum(oldPred),
|
||||
PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
|
||||
PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
|
||||
else
|
||||
DefaultBuild(heapRelation,
|
||||
indexRelation,
|
||||
@@ -2087,21 +2090,22 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
||||
|
||||
#ifndef OLD_FILE_NAMING
|
||||
if (!inplace)
|
||||
{
|
||||
inplace = IsSharedSystemRelationName(NameStr(iRel->rd_rel->relname));
|
||||
{
|
||||
inplace = IsSharedSystemRelationName(NameStr(iRel->rd_rel->relname));
|
||||
if (!inplace)
|
||||
setNewRelfilenode(iRel);
|
||||
}
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
/* Obtain exclusive lock on it, just to be sure */
|
||||
LockRelation(iRel, AccessExclusiveLock);
|
||||
|
||||
if (inplace)
|
||||
{
|
||||
|
||||
/*
|
||||
* Release any buffers associated with this index. If they're dirty,
|
||||
* they're just dropped without bothering to flush to disk.
|
||||
*/
|
||||
* Release any buffers associated with this index. If they're
|
||||
* dirty, they're just dropped without bothering to flush to disk.
|
||||
*/
|
||||
DropRelationBuffers(iRel);
|
||||
|
||||
/* Now truncate the actual data and set blocks to zero */
|
||||
@@ -2115,7 +2119,7 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
||||
|
||||
/*
|
||||
* index_build will close both the heap and index relations (but not
|
||||
* give up the locks we hold on them). So we're done.
|
||||
* give up the locks we hold on them). So we're done.
|
||||
*/
|
||||
|
||||
SetReindexProcessing(old);
|
||||
@@ -2164,31 +2168,37 @@ reindex_relation(Oid relid, bool force)
|
||||
bool old,
|
||||
reindexed;
|
||||
|
||||
bool deactivate_needed, overwrite, upd_pg_class_inplace;
|
||||
bool deactivate_needed,
|
||||
overwrite,
|
||||
upd_pg_class_inplace;
|
||||
|
||||
#ifdef OLD_FILE_NAMING
|
||||
overwrite = upd_pg_class_inplace = deactivate_needed = true;
|
||||
overwrite = upd_pg_class_inplace = deactivate_needed = true;
|
||||
#else
|
||||
Relation rel;
|
||||
overwrite = upd_pg_class_inplace = deactivate_needed = false;
|
||||
Relation rel;
|
||||
|
||||
overwrite = upd_pg_class_inplace = deactivate_needed = false;
|
||||
|
||||
/*
|
||||
* avoid heap_update() pg_class tuples while processing
|
||||
* reindex for pg_class.
|
||||
*/
|
||||
* avoid heap_update() pg_class tuples while processing reindex for
|
||||
* pg_class.
|
||||
*/
|
||||
if (IsIgnoringSystemIndexes())
|
||||
upd_pg_class_inplace = true;
|
||||
|
||||
/*
|
||||
* ignore the indexes of the target system relation while processing
|
||||
* reindex.
|
||||
*/
|
||||
*/
|
||||
rel = RelationIdGetRelation(relid);
|
||||
if (!IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(rel->rd_rel->relname)))
|
||||
deactivate_needed = true;
|
||||
#ifndef ENABLE_REINDEX_NAILED_RELATIONS
|
||||
/*
|
||||
* nailed relations are never updated.
|
||||
* We couldn't keep the consistency between the relation
|
||||
* descriptors and pg_class tuples.
|
||||
*/
|
||||
#ifndef ENABLE_REINDEX_NAILED_RELATIONS
|
||||
|
||||
/*
|
||||
* nailed relations are never updated. We couldn't keep the
|
||||
* consistency between the relation descriptors and pg_class tuples.
|
||||
*/
|
||||
if (rel->rd_isnailed)
|
||||
{
|
||||
if (IsIgnoringSystemIndexes())
|
||||
@@ -2199,10 +2209,11 @@ reindex_relation(Oid relid, bool force)
|
||||
else
|
||||
elog(ERROR, "the target relation %u is nailed", relid);
|
||||
}
|
||||
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
||||
#endif /* ENABLE_REINDEX_NAILED_RELATIONS */
|
||||
|
||||
/*
|
||||
* Shared system indexes must be overwritten because it's
|
||||
* impossible to update pg_class tuples of all databases.
|
||||
* Shared system indexes must be overwritten because it's impossible
|
||||
* to update pg_class tuples of all databases.
|
||||
*/
|
||||
if (IsSharedSystemRelationName(NameStr(rel->rd_rel->relname)))
|
||||
{
|
||||
@@ -2215,7 +2226,7 @@ reindex_relation(Oid relid, bool force)
|
||||
elog(ERROR, "the target relation %u is shared", relid);
|
||||
}
|
||||
RelationClose(rel);
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
old = SetReindexProcessing(true);
|
||||
if (deactivate_needed)
|
||||
{
|
||||
@@ -2252,24 +2263,27 @@ reindex_relation(Oid relid, bool force)
|
||||
heap_endscan(scan);
|
||||
heap_close(indexRelation, AccessShareLock);
|
||||
if (reindexed)
|
||||
/*
|
||||
* Ok,we could use the reindexed indexes of the target
|
||||
* system relation now.
|
||||
*/
|
||||
{
|
||||
|
||||
/*
|
||||
* Ok,we could use the reindexed indexes of the target system
|
||||
* relation now.
|
||||
*/
|
||||
{
|
||||
if (deactivate_needed)
|
||||
{
|
||||
if (!overwrite && relid == RelOid_pg_class)
|
||||
{
|
||||
/*
|
||||
* For pg_class, relhasindex should be set
|
||||
* to true here in place.
|
||||
|
||||
/*
|
||||
* For pg_class, relhasindex should be set to true here in
|
||||
* place.
|
||||
*/
|
||||
setRelhasindex(relid, true);
|
||||
CommandCounterIncrement();
|
||||
/*
|
||||
* However the following setRelhasindex()
|
||||
* is needed to keep consistency with WAL.
|
||||
|
||||
/*
|
||||
* However the following setRelhasindex() is needed to
|
||||
* keep consistency with WAL.
|
||||
*/
|
||||
}
|
||||
setRelhasindex(relid, true);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.76 2001/01/24 19:42:51 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.77 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -124,7 +124,7 @@ CatalogCloseIndices(int nIndices, Relation *idescs)
|
||||
* NOTE: since this routine looks up all the pg_index data on each call,
|
||||
* it's relatively inefficient for inserting a large number of tuples into
|
||||
* the same catalog. We use it only for inserting one or a few tuples
|
||||
* in a given command. See ExecOpenIndices() and related routines if you
|
||||
* in a given command. See ExecOpenIndices() and related routines if you
|
||||
* are inserting tuples in bulk.
|
||||
*
|
||||
* NOTE: we do not bother to handle partial indices. Nor do we try to
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.37 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.38 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -58,7 +58,7 @@ AggregateCreate(char *aggName,
|
||||
Datum values[Natts_pg_aggregate];
|
||||
Form_pg_proc proc;
|
||||
Oid transfn;
|
||||
Oid finalfn = InvalidOid; /* can be omitted */
|
||||
Oid finalfn = InvalidOid; /* can be omitted */
|
||||
Oid basetype;
|
||||
Oid transtype;
|
||||
Oid finaltype;
|
||||
@@ -79,8 +79,8 @@ AggregateCreate(char *aggName,
|
||||
|
||||
/*
|
||||
* Handle the aggregate's base type (input data type). This can be
|
||||
* specified as 'ANY' for a data-independent transition function,
|
||||
* such as COUNT(*).
|
||||
* specified as 'ANY' for a data-independent transition function, such
|
||||
* as COUNT(*).
|
||||
*/
|
||||
basetype = GetSysCacheOid(TYPENAME,
|
||||
PointerGetDatum(aggbasetypeName),
|
||||
@@ -118,9 +118,7 @@ AggregateCreate(char *aggName,
|
||||
nargs = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
nargs = 1;
|
||||
}
|
||||
tup = SearchSysCache(PROCNAME,
|
||||
PointerGetDatum(aggtransfnName),
|
||||
Int32GetDatum(nargs),
|
||||
@@ -134,16 +132,17 @@ AggregateCreate(char *aggName,
|
||||
if (proc->prorettype != transtype)
|
||||
elog(ERROR, "AggregateCreate: return type of '%s' is not '%s'",
|
||||
aggtransfnName, aggtranstypeName);
|
||||
|
||||
/*
|
||||
* If the transfn is strict and the initval is NULL, make sure
|
||||
* input type and transtype are the same (or at least binary-
|
||||
* compatible), so that it's OK to use the first input value
|
||||
* as the initial transValue.
|
||||
* If the transfn is strict and the initval is NULL, make sure input
|
||||
* type and transtype are the same (or at least binary- compatible),
|
||||
* so that it's OK to use the first input value as the initial
|
||||
* transValue.
|
||||
*/
|
||||
if (proc->proisstrict && agginitval == NULL)
|
||||
{
|
||||
if (basetype != transtype &&
|
||||
! IS_BINARY_COMPATIBLE(basetype, transtype))
|
||||
!IS_BINARY_COMPATIBLE(basetype, transtype))
|
||||
elog(ERROR, "AggregateCreate: must not omit initval when transfn is strict and transtype is not compatible with input type");
|
||||
}
|
||||
ReleaseSysCache(tup);
|
||||
@@ -168,6 +167,7 @@ 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_largeobject.c,v 1.7 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_largeobject.c,v 1.8 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -51,7 +51,7 @@ LargeObjectCreate(Oid loid)
|
||||
*/
|
||||
for (i = 0; i < Natts_pg_largeobject; i++)
|
||||
{
|
||||
values[i] = (Datum)NULL;
|
||||
values[i] = (Datum) NULL;
|
||||
nulls[i] = ' ';
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ LargeObjectCreate(Oid loid)
|
||||
values[i++] = Int32GetDatum(0);
|
||||
values[i++] = DirectFunctionCall1(byteain,
|
||||
CStringGetDatum(""));
|
||||
|
||||
|
||||
ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls);
|
||||
|
||||
/*
|
||||
@@ -77,7 +77,7 @@ LargeObjectCreate(Oid loid)
|
||||
CatalogIndexInsert(idescs, Num_pg_largeobject_indices, pg_largeobject, ntup);
|
||||
CatalogCloseIndices(Num_pg_largeobject_indices, idescs);
|
||||
}
|
||||
|
||||
|
||||
heap_close(pg_largeobject, RowExclusiveLock);
|
||||
|
||||
heap_freetuple(ntup);
|
||||
@@ -91,9 +91,9 @@ LargeObjectDrop(Oid loid)
|
||||
bool found = false;
|
||||
Relation pg_largeobject;
|
||||
Relation pg_lo_idx;
|
||||
ScanKeyData skey[1];
|
||||
ScanKeyData skey[1];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData tuple;
|
||||
Buffer buffer;
|
||||
|
||||
@@ -139,9 +139,9 @@ LargeObjectExists(Oid loid)
|
||||
bool retval = false;
|
||||
Relation pg_largeobject;
|
||||
Relation pg_lo_idx;
|
||||
ScanKeyData skey[1];
|
||||
ScanKeyData skey[1];
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTupleData tuple;
|
||||
Buffer buffer;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.55 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.56 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||
@@ -263,7 +263,7 @@ OperatorShellMakeWithOpenRelation(Relation pg_operator_desc,
|
||||
values[i++] = NameGetDatum(&oname);
|
||||
values[i++] = Int32GetDatum(GetUserId());
|
||||
values[i++] = UInt16GetDatum(0);
|
||||
values[i++] = CharGetDatum('b'); /* assume it's binary */
|
||||
values[i++] = CharGetDatum('b'); /* assume it's binary */
|
||||
values[i++] = BoolGetDatum(false);
|
||||
values[i++] = BoolGetDatum(false);
|
||||
values[i++] = ObjectIdGetDatum(leftObjectId); /* <-- left oid */
|
||||
@@ -595,7 +595,7 @@ OperatorDef(char *operatorName,
|
||||
*/
|
||||
if (restrictionName)
|
||||
{ /* optional */
|
||||
Oid restOid;
|
||||
Oid restOid;
|
||||
|
||||
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
typeId[0] = OIDOID; /* operator OID */
|
||||
@@ -623,7 +623,7 @@ OperatorDef(char *operatorName,
|
||||
*/
|
||||
if (joinName)
|
||||
{ /* optional */
|
||||
Oid joinOid;
|
||||
Oid joinOid;
|
||||
|
||||
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
typeId[0] = OIDOID; /* operator OID */
|
||||
@@ -745,7 +745,7 @@ OperatorDef(char *operatorName,
|
||||
otherRightTypeName);
|
||||
if (!OidIsValid(other_oid))
|
||||
elog(ERROR,
|
||||
"OperatorDef: can't create operator shell \"%s\"",
|
||||
"OperatorDef: can't create operator shell \"%s\"",
|
||||
name[j]);
|
||||
values[i++] = ObjectIdGetDatum(other_oid);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.53 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.54 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -156,7 +156,7 @@ ProcedureCreate(char *procedureName,
|
||||
text *prosrctext;
|
||||
|
||||
prosrctext = DatumGetTextP(DirectFunctionCall1(textin,
|
||||
CStringGetDatum(prosrc)));
|
||||
CStringGetDatum(prosrc)));
|
||||
retval = GetSysCacheOid(PROSRC,
|
||||
PointerGetDatum(prosrctext),
|
||||
0, 0, 0);
|
||||
@@ -237,18 +237,18 @@ ProcedureCreate(char *procedureName,
|
||||
prosrc = procedureName;
|
||||
if (fmgr_internal_function(prosrc) == InvalidOid)
|
||||
elog(ERROR,
|
||||
"ProcedureCreate: there is no builtin function named \"%s\"",
|
||||
"ProcedureCreate: there is no builtin function named \"%s\"",
|
||||
prosrc);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is a dynamically loadable procedure, make sure that the
|
||||
* library file exists, is loadable, and contains the specified link
|
||||
* symbol. Also check for a valid function information record.
|
||||
* symbol. Also check for a valid function information record.
|
||||
*
|
||||
* We used to perform these checks only when the function was first
|
||||
* called, but it seems friendlier to verify the library's validity
|
||||
* at CREATE FUNCTION time.
|
||||
* called, but it seems friendlier to verify the library's validity at
|
||||
* CREATE FUNCTION time.
|
||||
*/
|
||||
|
||||
if (languageObjectId == ClanguageId)
|
||||
@@ -355,7 +355,8 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
tlist = parse->targetList;
|
||||
|
||||
/*
|
||||
* The last query must be a SELECT if and only if there is a return type.
|
||||
* The last query must be a SELECT if and only if there is a return
|
||||
* type.
|
||||
*/
|
||||
if (rettype == InvalidOid)
|
||||
{
|
||||
@@ -375,8 +376,8 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
tlistlen = ExecCleanTargetListLength(tlist);
|
||||
|
||||
/*
|
||||
* For base-type returns, the target list should have exactly one entry,
|
||||
* and its type should agree with what the user declared.
|
||||
* For base-type returns, the target list should have exactly one
|
||||
* entry, and its type should agree with what the user declared.
|
||||
*/
|
||||
typerelid = typeidTypeRelid(rettype);
|
||||
if (typerelid == InvalidOid)
|
||||
@@ -388,7 +389,7 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
|
||||
if (resnode->restype != rettype)
|
||||
elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
|
||||
typeidTypeName(rettype), typeidTypeName(resnode->restype));
|
||||
typeidTypeName(rettype), typeidTypeName(resnode->restype));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -397,8 +398,8 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
* If the target list is of length 1, and the type of the varnode in
|
||||
* the target list is the same as the declared return type, this is
|
||||
* okay. This can happen, for example, where the body of the function
|
||||
* is 'SELECT (x = func2())', where func2 has the same return type
|
||||
* as the function that's calling it.
|
||||
* is 'SELECT (x = func2())', where func2 has the same return type as
|
||||
* the function that's calling it.
|
||||
*/
|
||||
if (tlistlen == 1)
|
||||
{
|
||||
@@ -408,10 +409,10 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
}
|
||||
|
||||
/*
|
||||
* By here, the procedure returns a tuple or set of tuples. This part of
|
||||
* the typechecking is a hack. We look up the relation that is the
|
||||
* declared return type, and be sure that attributes 1 .. n in the target
|
||||
* list match the declared types.
|
||||
* By here, the procedure returns a tuple or set of tuples. This part
|
||||
* of the typechecking is a hack. We look up the relation that is the
|
||||
* declared return type, and be sure that attributes 1 .. n in the
|
||||
* target list match the declared types.
|
||||
*/
|
||||
reln = heap_open(typerelid, AccessShareLock);
|
||||
relid = reln->rd_id;
|
||||
@@ -436,7 +437,7 @@ checkretval(Oid rettype, List *queryTreeList)
|
||||
typeidTypeName(rettype),
|
||||
typeidTypeName(tletype),
|
||||
typeidTypeName(reln->rd_att->attrs[i]->atttypid),
|
||||
i+1);
|
||||
i + 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.59 2001/02/12 20:07:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.60 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -171,24 +171,24 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
|
||||
*/
|
||||
i = 0;
|
||||
namestrcpy(&name, typeName);
|
||||
values[i++] = NameGetDatum(&name); /* 1 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 2 */
|
||||
values[i++] = Int16GetDatum(0); /* 3 */
|
||||
values[i++] = Int16GetDatum(0); /* 4 */
|
||||
values[i++] = BoolGetDatum(false); /* 5 */
|
||||
values[i++] = CharGetDatum(0); /* 6 */
|
||||
values[i++] = BoolGetDatum(false); /* 7 */
|
||||
values[i++] = CharGetDatum(0); /* 8 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 9 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 10 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 11 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
|
||||
values[i++] = CharGetDatum('i'); /* 15 */
|
||||
values[i++] = CharGetDatum('p'); /* 16 */
|
||||
values[i++] = NameGetDatum(&name); /* 1 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 2 */
|
||||
values[i++] = Int16GetDatum(0); /* 3 */
|
||||
values[i++] = Int16GetDatum(0); /* 4 */
|
||||
values[i++] = BoolGetDatum(false); /* 5 */
|
||||
values[i++] = CharGetDatum(0); /* 6 */
|
||||
values[i++] = BoolGetDatum(false); /* 7 */
|
||||
values[i++] = CharGetDatum(0); /* 8 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 9 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 10 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 11 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 12 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 13 */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* 14 */
|
||||
values[i++] = CharGetDatum('i'); /* 15 */
|
||||
values[i++] = CharGetDatum('p'); /* 16 */
|
||||
values[i++] = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(typeName)); /* 17 */
|
||||
CStringGetDatum(typeName)); /* 17 */
|
||||
|
||||
/* ----------------
|
||||
* create a new type tuple with FormHeapTuple
|
||||
@@ -368,16 +368,16 @@ TypeCreate(char *typeName,
|
||||
*/
|
||||
i = 0;
|
||||
namestrcpy(&name, typeName);
|
||||
values[i++] = NameGetDatum(&name); /* 1 */
|
||||
values[i++] = NameGetDatum(&name); /* 1 */
|
||||
values[i++] = Int32GetDatum(GetUserId()); /* 2 */
|
||||
values[i++] = Int16GetDatum(internalSize); /* 3 */
|
||||
values[i++] = Int16GetDatum(externalSize); /* 4 */
|
||||
values[i++] = BoolGetDatum(passedByValue); /* 5 */
|
||||
values[i++] = CharGetDatum(typeType); /* 6 */
|
||||
values[i++] = BoolGetDatum(true); /* 7 */
|
||||
values[i++] = BoolGetDatum(true); /* 7 */
|
||||
values[i++] = CharGetDatum(typDelim); /* 8 */
|
||||
values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* 9 */
|
||||
values[i++] = ObjectIdGetDatum(elementObjectId); /* 10 */
|
||||
values[i++] = ObjectIdGetDatum(elementObjectId); /* 10 */
|
||||
|
||||
procs[0] = inputProcedure;
|
||||
procs[1] = outputProcedure;
|
||||
@@ -386,7 +386,7 @@ TypeCreate(char *typeName,
|
||||
|
||||
for (j = 0; j < 4; ++j)
|
||||
{
|
||||
Oid procOid;
|
||||
Oid procOid;
|
||||
|
||||
procname = procs[j];
|
||||
|
||||
@@ -438,27 +438,27 @@ TypeCreate(char *typeName,
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
}
|
||||
|
||||
values[i++] = ObjectIdGetDatum(procOid); /* 11 - 14 */
|
||||
values[i++] = ObjectIdGetDatum(procOid); /* 11 - 14 */
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* set default alignment
|
||||
* ----------------
|
||||
*/
|
||||
values[i++] = CharGetDatum(alignment); /* 15 */
|
||||
values[i++] = CharGetDatum(alignment); /* 15 */
|
||||
|
||||
/* ----------------
|
||||
* set default storage for TOAST
|
||||
* ----------------
|
||||
*/
|
||||
values[i++] = CharGetDatum(storage); /* 16 */
|
||||
values[i++] = CharGetDatum(storage); /* 16 */
|
||||
|
||||
/* ----------------
|
||||
* initialize the default value for this type.
|
||||
* ----------------
|
||||
*/
|
||||
values[i] = DirectFunctionCall1(textin, /* 17 */
|
||||
CStringGetDatum(defaultTypeValue ? defaultTypeValue : "-"));
|
||||
values[i] = DirectFunctionCall1(textin, /* 17 */
|
||||
CStringGetDatum(defaultTypeValue ? defaultTypeValue : "-"));
|
||||
|
||||
/* ----------------
|
||||
* open pg_type and begin a scan for the type name.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.14 2001/02/16 03:16:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.15 2001/03/22 03:59:20 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -86,9 +86,10 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
|
||||
CommitTransactionCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can VACUUM ANALYZE any table except pg_statistic.
|
||||
* see update_relstats
|
||||
* We can VACUUM ANALYZE any table except pg_statistic. see
|
||||
* update_relstats
|
||||
*/
|
||||
if (strcmp(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname),
|
||||
StatisticRelationName) == 0)
|
||||
@@ -104,10 +105,12 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
|
||||
if (!pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
|
||||
RELNAME))
|
||||
{
|
||||
/* we already did an elog during vacuum
|
||||
elog(NOTICE, "Skipping \"%s\" --- only table owner can VACUUM it",
|
||||
RelationGetRelationName(onerel));
|
||||
*/
|
||||
|
||||
/*
|
||||
* we already did an elog during vacuum elog(NOTICE, "Skipping
|
||||
* \"%s\" --- only table owner can VACUUM it",
|
||||
* RelationGetRelationName(onerel));
|
||||
*/
|
||||
heap_close(onerel, NoLock);
|
||||
CommitTransactionCommand();
|
||||
return;
|
||||
@@ -136,7 +139,7 @@ analyze_rel(Oid relid, List *anal_cols2, int MESSAGE_LEVEL)
|
||||
if (namestrcmp(&(attr[i]->attname), col) == 0)
|
||||
break;
|
||||
}
|
||||
if (i < attr_cnt) /* found */
|
||||
if (i < attr_cnt) /* found */
|
||||
attnums[tcnt++] = i;
|
||||
else
|
||||
{
|
||||
@@ -295,15 +298,16 @@ attr_stats(Relation onerel, int attr_cnt, VacAttrStats *vacattrstats, HeapTuple
|
||||
stats->nonnull_cnt++;
|
||||
|
||||
/*
|
||||
* If the value is toasted, detoast it to avoid repeated detoastings
|
||||
* and resultant memory leakage inside the comparison routines.
|
||||
* If the value is toasted, detoast it to avoid repeated
|
||||
* detoastings and resultant memory leakage inside the comparison
|
||||
* routines.
|
||||
*/
|
||||
if (!stats->attr->attbyval && stats->attr->attlen == -1)
|
||||
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
|
||||
else
|
||||
value = origvalue;
|
||||
|
||||
if (! stats->initialized)
|
||||
if (!stats->initialized)
|
||||
{
|
||||
bucketcpy(stats->attr, value, &stats->best, &stats->best_len);
|
||||
/* best_cnt gets incremented below */
|
||||
@@ -433,7 +437,7 @@ bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int *bucket_len)
|
||||
* Of course, this only works for fixed-size never-null columns, but
|
||||
* dispersion is.
|
||||
*
|
||||
* pg_statistic rows are just added normally. This means that
|
||||
* pg_statistic rows are just added normally. This means that
|
||||
* pg_statistic will probably contain some deleted rows at the
|
||||
* completion of a vacuum cycle, unless it happens to get vacuumed last.
|
||||
*
|
||||
@@ -467,7 +471,7 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
|
||||
VacAttrStats *stats;
|
||||
|
||||
attp = (Form_pg_attribute) GETSTRUCT(atup);
|
||||
if (attp->attnum <= 0) /* skip system attributes for now */
|
||||
if (attp->attnum <= 0) /* skip system attributes for now */
|
||||
continue;
|
||||
|
||||
for (i = 0; i < natts; i++)
|
||||
@@ -476,47 +480,45 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
|
||||
break;
|
||||
}
|
||||
if (i >= natts)
|
||||
continue; /* skip attr if no stats collected */
|
||||
continue; /* skip attr if no stats collected */
|
||||
stats = &(vacattrstats[i]);
|
||||
|
||||
if (VacAttrStatsEqValid(stats))
|
||||
{
|
||||
float4 selratio; /* average ratio of rows selected
|
||||
* for a random constant */
|
||||
float4 selratio; /* average ratio of rows selected
|
||||
* for a random constant */
|
||||
|
||||
/* Compute dispersion */
|
||||
if (stats->nonnull_cnt == 0 && stats->null_cnt == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* empty relation, so put a dummy value in
|
||||
* attdispersion
|
||||
* empty relation, so put a dummy value in attdispersion
|
||||
*/
|
||||
selratio = 0;
|
||||
}
|
||||
else if (stats->null_cnt <= 1 && stats->best_cnt == 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* looks like we have a unique-key attribute --- flag
|
||||
* this with special -1.0 flag value.
|
||||
* looks like we have a unique-key attribute --- flag this
|
||||
* with special -1.0 flag value.
|
||||
*
|
||||
* The correct dispersion is 1.0/numberOfRows, but since
|
||||
* the relation row count can get updated without
|
||||
* recomputing dispersion, we want to store a
|
||||
* "symbolic" value and figure 1.0/numberOfRows on the
|
||||
* fly.
|
||||
* The correct dispersion is 1.0/numberOfRows, but since the
|
||||
* relation row count can get updated without recomputing
|
||||
* dispersion, we want to store a "symbolic" value and
|
||||
* figure 1.0/numberOfRows on the fly.
|
||||
*/
|
||||
selratio = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (VacAttrStatsLtGtValid(stats) &&
|
||||
stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
|
||||
stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
|
||||
{
|
||||
|
||||
/*
|
||||
* exact result when there are just 1 or 2
|
||||
* values...
|
||||
* exact result when there are just 1 or 2 values...
|
||||
*/
|
||||
double min_cnt_d = stats->min_cnt,
|
||||
max_cnt_d = stats->max_cnt,
|
||||
@@ -552,12 +554,12 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
|
||||
|
||||
/*
|
||||
* Create pg_statistic tuples for the relation, if we have
|
||||
* gathered the right data. del_stats() previously
|
||||
* deleted all the pg_statistic tuples for the rel, so we
|
||||
* just have to insert new ones here.
|
||||
* gathered the right data. del_stats() previously deleted
|
||||
* all the pg_statistic tuples for the rel, so we just have to
|
||||
* insert new ones here.
|
||||
*
|
||||
* Note analyze_rel() has seen to it that we won't come here
|
||||
* when vacuuming pg_statistic itself.
|
||||
* Note analyze_rel() has seen to it that we won't come here when
|
||||
* vacuuming pg_statistic itself.
|
||||
*/
|
||||
if (VacAttrStatsLtGtValid(stats) && stats->initialized)
|
||||
{
|
||||
@@ -567,7 +569,7 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
|
||||
char *out_string;
|
||||
double best_cnt_d = stats->best_cnt,
|
||||
null_cnt_d = stats->null_cnt,
|
||||
nonnull_cnt_d = stats->nonnull_cnt; /* prevent overflow */
|
||||
nonnull_cnt_d = stats->nonnull_cnt; /* prevent overflow */
|
||||
Datum values[Natts_pg_statistic];
|
||||
char nulls[Natts_pg_statistic];
|
||||
Relation irelations[Num_pg_statistic_indices];
|
||||
@@ -585,31 +587,31 @@ update_attstats(Oid relid, int natts, VacAttrStats *vacattrstats)
|
||||
* ----------------
|
||||
*/
|
||||
i = 0;
|
||||
values[i++] = ObjectIdGetDatum(relid); /* starelid */
|
||||
values[i++] = Int16GetDatum(attp->attnum); /* staattnum */
|
||||
values[i++] = ObjectIdGetDatum(stats->op_cmplt); /* staop */
|
||||
values[i++] = Float4GetDatum(nullratio); /* stanullfrac */
|
||||
values[i++] = Float4GetDatum(bestratio); /* stacommonfrac */
|
||||
values[i++] = ObjectIdGetDatum(relid); /* starelid */
|
||||
values[i++] = Int16GetDatum(attp->attnum); /* staattnum */
|
||||
values[i++] = ObjectIdGetDatum(stats->op_cmplt); /* staop */
|
||||
values[i++] = Float4GetDatum(nullratio); /* stanullfrac */
|
||||
values[i++] = Float4GetDatum(bestratio); /* stacommonfrac */
|
||||
out_string = DatumGetCString(FunctionCall3(&out_function,
|
||||
stats->best,
|
||||
ObjectIdGetDatum(stats->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod)));
|
||||
values[i++] = DirectFunctionCall1(textin, /* stacommonval */
|
||||
CStringGetDatum(out_string));
|
||||
stats->best,
|
||||
ObjectIdGetDatum(stats->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod)));
|
||||
values[i++] = DirectFunctionCall1(textin, /* stacommonval */
|
||||
CStringGetDatum(out_string));
|
||||
pfree(out_string);
|
||||
out_string = DatumGetCString(FunctionCall3(&out_function,
|
||||
stats->min,
|
||||
ObjectIdGetDatum(stats->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod)));
|
||||
values[i++] = DirectFunctionCall1(textin, /* staloval */
|
||||
CStringGetDatum(out_string));
|
||||
stats->min,
|
||||
ObjectIdGetDatum(stats->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod)));
|
||||
values[i++] = DirectFunctionCall1(textin, /* staloval */
|
||||
CStringGetDatum(out_string));
|
||||
pfree(out_string);
|
||||
out_string = DatumGetCString(FunctionCall3(&out_function,
|
||||
stats->max,
|
||||
ObjectIdGetDatum(stats->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod)));
|
||||
values[i++] = DirectFunctionCall1(textin, /* stahival */
|
||||
CStringGetDatum(out_string));
|
||||
stats->max,
|
||||
ObjectIdGetDatum(stats->typelem),
|
||||
Int32GetDatum(stats->attr->atttypmod)));
|
||||
values[i++] = DirectFunctionCall1(textin, /* stahival */
|
||||
CStringGetDatum(out_string));
|
||||
pfree(out_string);
|
||||
|
||||
stup = heap_formtuple(sd->rd_att, values, nulls);
|
||||
@@ -682,6 +684,3 @@ del_stats(Oid relid, int attcnt, int *attnums)
|
||||
*/
|
||||
heap_close(pgstatistic, NoLock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.76 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.77 2001/03/22 03:59:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -130,7 +130,7 @@ static void NotifyMyFrontEnd(char *relname, int32 listenerPID);
|
||||
static int AsyncExistsPendingNotify(char *relname);
|
||||
static void ClearPendingNotifies(void);
|
||||
|
||||
bool Trace_notify = false;
|
||||
bool Trace_notify = false;
|
||||
|
||||
|
||||
/*
|
||||
@@ -161,6 +161,7 @@ Async_Notify(char *relname)
|
||||
/* no point in making duplicate entries in the list ... */
|
||||
if (!AsyncExistsPendingNotify(relname))
|
||||
{
|
||||
|
||||
/*
|
||||
* We allocate list memory from the global malloc pool to ensure
|
||||
* that it will live until we want to use it. This is probably
|
||||
@@ -349,9 +350,7 @@ Async_UnlistenAll()
|
||||
sRel = heap_beginscan(lRel, 0, SnapshotNow, 1, key);
|
||||
|
||||
while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0)))
|
||||
{
|
||||
simple_heap_delete(lRel, &lTuple->t_self);
|
||||
}
|
||||
|
||||
heap_endscan(sRel);
|
||||
heap_close(lRel, AccessExclusiveLock);
|
||||
@@ -499,6 +498,7 @@ AtCommit_Notify()
|
||||
*/
|
||||
if (kill(listenerPID, SIGUSR2) < 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Get rid of pg_listener entry if it refers to a PID
|
||||
* that no longer exists. Presumably, that backend
|
||||
@@ -794,7 +794,7 @@ ProcessIncomingNotify(void)
|
||||
|
||||
if (Trace_notify)
|
||||
elog(DEBUG, "ProcessIncomingNotify: received %s from %d",
|
||||
relname, (int) sourcePID);
|
||||
relname, (int) sourcePID);
|
||||
|
||||
NotifyMyFrontEnd(relname, sourcePID);
|
||||
/* Rewrite the tuple with 0 in notification column */
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.64 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.65 2001/03/22 03:59:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "utils/temprel.h"
|
||||
|
||||
|
||||
static Oid copy_heap(Oid OIDOldHeap, char *NewName, bool istemp);
|
||||
static Oid copy_heap(Oid OIDOldHeap, char *NewName, bool istemp);
|
||||
static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName);
|
||||
static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
|
||||
|
||||
@@ -75,8 +75,8 @@ cluster(char *oldrelname, char *oldindexname)
|
||||
StrNCpy(saveoldindexname, oldindexname, NAMEDATALEN);
|
||||
|
||||
/*
|
||||
* We grab exclusive access to the target rel and index for the duration
|
||||
* of the transaction.
|
||||
* We grab exclusive access to the target rel and index for the
|
||||
* duration of the transaction.
|
||||
*/
|
||||
OldHeap = heap_openr(saveoldrelname, AccessExclusiveLock);
|
||||
OIDOldHeap = RelationGetRelid(OldHeap);
|
||||
@@ -154,8 +154,8 @@ copy_heap(Oid OIDOldHeap, char *NewName, bool istemp)
|
||||
OldHeapDesc = RelationGetDescr(OldHeap);
|
||||
|
||||
/*
|
||||
* Need to make a copy of the tuple descriptor,
|
||||
* since heap_create_with_catalog modifies it.
|
||||
* Need to make a copy of the tuple descriptor, since
|
||||
* heap_create_with_catalog modifies it.
|
||||
*/
|
||||
tupdesc = CreateTupleDescCopyConstr(OldHeapDesc);
|
||||
|
||||
@@ -164,16 +164,15 @@ copy_heap(Oid OIDOldHeap, char *NewName, bool istemp)
|
||||
allowSystemTableMods);
|
||||
|
||||
/*
|
||||
* Advance command counter so that the newly-created
|
||||
* relation's catalog tuples will be visible to heap_open.
|
||||
* Advance command counter so that the newly-created relation's
|
||||
* catalog tuples will be visible to heap_open.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* If necessary, create a TOAST table for the new relation.
|
||||
* Note that AlterTableCreateToastTable ends with
|
||||
* CommandCounterIncrement(), so that the TOAST table will
|
||||
* be visible for insertion.
|
||||
* If necessary, create a TOAST table for the new relation. Note that
|
||||
* AlterTableCreateToastTable ends with CommandCounterIncrement(), so
|
||||
* that the TOAST table will be visible for insertion.
|
||||
*/
|
||||
AlterTableCreateToastTable(NewName, true);
|
||||
|
||||
@@ -198,12 +197,12 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
|
||||
|
||||
/*
|
||||
* Create a new index like the old one. To do this I get the info
|
||||
* from pg_index, and add a new index with a temporary name (that
|
||||
* will be changed later).
|
||||
* from pg_index, and add a new index with a temporary name (that will
|
||||
* be changed later).
|
||||
*
|
||||
* NOTE: index_create will cause the new index to be a temp relation
|
||||
* if its parent table is, so we don't need to do anything special
|
||||
* for the temp-table case here.
|
||||
* NOTE: index_create will cause the new index to be a temp relation if
|
||||
* its parent table is, so we don't need to do anything special for
|
||||
* the temp-table case here.
|
||||
*/
|
||||
Old_pg_index_Tuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(OIDOldIndex),
|
||||
@@ -214,7 +213,7 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
|
||||
indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
|
||||
|
||||
Old_pg_index_relation_Tuple = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(OIDOldIndex),
|
||||
ObjectIdGetDatum(OIDOldIndex),
|
||||
0, 0, 0);
|
||||
Assert(Old_pg_index_relation_Tuple);
|
||||
Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
|
||||
@@ -266,13 +265,15 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
||||
LocalHeapTuple.t_datamcxt = NULL;
|
||||
LocalHeapTuple.t_data = NULL;
|
||||
heap_fetch(LocalOldHeap, SnapshotNow, &LocalHeapTuple, &LocalBuffer);
|
||||
if (LocalHeapTuple.t_data != NULL) {
|
||||
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
|
||||
* retrieved tuple will actually be in a disk buffer! Thus,
|
||||
* the source relation would get trashed, which is bad news
|
||||
* if we abort later on. (This was a bug in releases thru 7.0)
|
||||
* the source relation would get trashed, which is bad news if
|
||||
* we abort later on. (This was a bug in releases thru 7.0)
|
||||
*/
|
||||
HeapTuple copiedTuple = heap_copytuple(&LocalHeapTuple);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.122 2001/02/27 22:07:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.123 2001/03/22 03:59:21 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The PerformAddAttribute() code, like most of the relation
|
||||
@@ -173,29 +173,29 @@ PerformPortalFetch(char *name,
|
||||
* at the end of the available tuples in that direction. If so, do
|
||||
* nothing. (This check exists because not all plan node types are
|
||||
* robust about being called again if they've already returned NULL
|
||||
* once.) If it's OK to do the fetch, call the executor. Then,
|
||||
* once.) If it's OK to do the fetch, call the executor. Then,
|
||||
* update the atStart/atEnd state depending on the number of tuples
|
||||
* that were retrieved.
|
||||
* ----------------
|
||||
*/
|
||||
if (forward)
|
||||
{
|
||||
if (! portal->atEnd)
|
||||
if (!portal->atEnd)
|
||||
{
|
||||
ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
|
||||
if (estate->es_processed > 0)
|
||||
portal->atStart = false; /* OK to back up now */
|
||||
portal->atStart = false; /* OK to back up now */
|
||||
if (count <= 0 || (int) estate->es_processed < count)
|
||||
portal->atEnd = true; /* we retrieved 'em all */
|
||||
portal->atEnd = true; /* we retrieved 'em all */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! portal->atStart)
|
||||
if (!portal->atStart)
|
||||
{
|
||||
ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
|
||||
if (estate->es_processed > 0)
|
||||
portal->atEnd = false; /* OK to go forward now */
|
||||
portal->atEnd = false; /* OK to go forward now */
|
||||
if (count <= 0 || (int) estate->es_processed < count)
|
||||
portal->atStart = true; /* we retrieved 'em all */
|
||||
}
|
||||
@@ -502,8 +502,8 @@ AlterTableAddColumn(const char *relationName,
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
/*
|
||||
* Automatically create the secondary relation for TOAST
|
||||
* if it formerly had no such but now has toastable attributes.
|
||||
* Automatically create the secondary relation for TOAST if it
|
||||
* formerly had no such but now has toastable attributes.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
AlterTableCreateToastTable(relationName, true);
|
||||
@@ -842,7 +842,7 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
|
||||
|
||||
relcheck = (Form_pg_relcheck) GETSTRUCT(htup);
|
||||
ccbin = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(&relcheck->rcbin)));
|
||||
PointerGetDatum(&relcheck->rcbin)));
|
||||
node = stringToNode(ccbin);
|
||||
pfree(ccbin);
|
||||
if (find_attribute_in_node(node, attnum))
|
||||
@@ -890,7 +890,7 @@ RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup)
|
||||
else
|
||||
{
|
||||
htup = SearchSysCache(RELOID,
|
||||
ObjectIdGetDatum(index->indexrelid),
|
||||
ObjectIdGetDatum(index->indexrelid),
|
||||
0, 0, 0);
|
||||
RemoveIndex(NameStr(((Form_pg_class) GETSTRUCT(htup))->relname));
|
||||
ReleaseSysCache(htup);
|
||||
@@ -1106,339 +1106,361 @@ AlterTableAddConstraint(char *relationName,
|
||||
#endif
|
||||
|
||||
/* Disallow ADD CONSTRAINT on views, indexes, sequences, etc */
|
||||
if (! is_relation(relationName))
|
||||
if (!is_relation(relationName))
|
||||
elog(ERROR, "ALTER TABLE ADD CONSTRAINT: %s is not a table",
|
||||
relationName);
|
||||
|
||||
switch (nodeTag(newConstraint))
|
||||
{
|
||||
case T_Constraint:
|
||||
{
|
||||
Constraint *constr = (Constraint *) newConstraint;
|
||||
|
||||
switch (constr->contype)
|
||||
{
|
||||
case CONSTR_CHECK:
|
||||
Constraint *constr = (Constraint *) newConstraint;
|
||||
|
||||
switch (constr->contype)
|
||||
{
|
||||
ParseState *pstate;
|
||||
bool successful = true;
|
||||
HeapScanDesc scan;
|
||||
ExprContext *econtext;
|
||||
TupleTableSlot *slot;
|
||||
HeapTuple tuple;
|
||||
RangeTblEntry *rte;
|
||||
List *qual;
|
||||
List *constlist;
|
||||
Relation rel;
|
||||
Node *expr;
|
||||
char *name;
|
||||
|
||||
if (constr->name)
|
||||
name = constr->name;
|
||||
else
|
||||
name = "<unnamed>";
|
||||
|
||||
constlist = makeList1(constr);
|
||||
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
|
||||
/* make sure it is not a view */
|
||||
if (rel->rd_rel->relkind == RELKIND_VIEW)
|
||||
elog(ERROR, "ALTER TABLE: cannot add constraint to a view");
|
||||
|
||||
/*
|
||||
* Scan all of the rows, looking for a false match
|
||||
*/
|
||||
scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
|
||||
AssertState(scan != NULL);
|
||||
|
||||
/*
|
||||
* We need to make a parse state and range table to allow
|
||||
* us to transformExpr and fix_opids to get a version of
|
||||
* the expression we can pass to ExecQual
|
||||
*/
|
||||
pstate = make_parsestate(NULL);
|
||||
rte = addRangeTableEntry(pstate, relationName, NULL,
|
||||
false, true);
|
||||
addRTEtoQuery(pstate, rte, true, true);
|
||||
|
||||
/* Convert the A_EXPR in raw_expr into an EXPR */
|
||||
expr = transformExpr(pstate, constr->raw_expr,
|
||||
EXPR_COLUMN_FIRST);
|
||||
|
||||
/*
|
||||
* Make sure it yields a boolean result.
|
||||
*/
|
||||
if (exprType(expr) != BOOLOID)
|
||||
elog(ERROR, "CHECK '%s' does not yield boolean result",
|
||||
name);
|
||||
|
||||
/*
|
||||
* Make sure no outside relations are referred to.
|
||||
*/
|
||||
if (length(pstate->p_rtable) != 1)
|
||||
elog(ERROR, "Only relation '%s' can be referenced in CHECK",
|
||||
relationName);
|
||||
|
||||
/*
|
||||
* Might as well try to reduce any constant expressions.
|
||||
*/
|
||||
expr = eval_const_expressions(expr);
|
||||
|
||||
/* And fix the opids */
|
||||
fix_opids(expr);
|
||||
|
||||
qual = makeList1(expr);
|
||||
|
||||
/* Make tuple slot to hold tuples */
|
||||
slot = MakeTupleTableSlot();
|
||||
ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false);
|
||||
/* Make an expression context for ExecQual */
|
||||
econtext = MakeExprContext(slot, CurrentMemoryContext);
|
||||
|
||||
/*
|
||||
* Scan through the rows now, checking the expression
|
||||
* at each row.
|
||||
*/
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
||||
if (!ExecQual(qual, econtext, true))
|
||||
case CONSTR_CHECK:
|
||||
{
|
||||
successful=false;
|
||||
ParseState *pstate;
|
||||
bool successful = true;
|
||||
HeapScanDesc scan;
|
||||
ExprContext *econtext;
|
||||
TupleTableSlot *slot;
|
||||
HeapTuple tuple;
|
||||
RangeTblEntry *rte;
|
||||
List *qual;
|
||||
List *constlist;
|
||||
Relation rel;
|
||||
Node *expr;
|
||||
char *name;
|
||||
|
||||
if (constr->name)
|
||||
name = constr->name;
|
||||
else
|
||||
name = "<unnamed>";
|
||||
|
||||
constlist = makeList1(constr);
|
||||
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
|
||||
/* make sure it is not a view */
|
||||
if (rel->rd_rel->relkind == RELKIND_VIEW)
|
||||
elog(ERROR, "ALTER TABLE: cannot add constraint to a view");
|
||||
|
||||
/*
|
||||
* Scan all of the rows, looking for a false
|
||||
* match
|
||||
*/
|
||||
scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
|
||||
AssertState(scan != NULL);
|
||||
|
||||
/*
|
||||
* We need to make a parse state and range
|
||||
* table to allow us to transformExpr and
|
||||
* fix_opids to get a version of the
|
||||
* expression we can pass to ExecQual
|
||||
*/
|
||||
pstate = make_parsestate(NULL);
|
||||
rte = addRangeTableEntry(pstate, relationName, NULL,
|
||||
false, true);
|
||||
addRTEtoQuery(pstate, rte, true, true);
|
||||
|
||||
/* Convert the A_EXPR in raw_expr into an EXPR */
|
||||
expr = transformExpr(pstate, constr->raw_expr,
|
||||
EXPR_COLUMN_FIRST);
|
||||
|
||||
/*
|
||||
* Make sure it yields a boolean result.
|
||||
*/
|
||||
if (exprType(expr) != BOOLOID)
|
||||
elog(ERROR, "CHECK '%s' does not yield boolean result",
|
||||
name);
|
||||
|
||||
/*
|
||||
* Make sure no outside relations are referred
|
||||
* to.
|
||||
*/
|
||||
if (length(pstate->p_rtable) != 1)
|
||||
elog(ERROR, "Only relation '%s' can be referenced in CHECK",
|
||||
relationName);
|
||||
|
||||
/*
|
||||
* Might as well try to reduce any constant
|
||||
* expressions.
|
||||
*/
|
||||
expr = eval_const_expressions(expr);
|
||||
|
||||
/* And fix the opids */
|
||||
fix_opids(expr);
|
||||
|
||||
qual = makeList1(expr);
|
||||
|
||||
/* Make tuple slot to hold tuples */
|
||||
slot = MakeTupleTableSlot();
|
||||
ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false);
|
||||
/* Make an expression context for ExecQual */
|
||||
econtext = MakeExprContext(slot, CurrentMemoryContext);
|
||||
|
||||
/*
|
||||
* Scan through the rows now, checking the
|
||||
* expression at each row.
|
||||
*/
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
|
||||
if (!ExecQual(qual, econtext, true))
|
||||
{
|
||||
successful = false;
|
||||
break;
|
||||
}
|
||||
ResetExprContext(econtext);
|
||||
}
|
||||
|
||||
FreeExprContext(econtext);
|
||||
pfree(slot);
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
if (!successful)
|
||||
{
|
||||
heap_close(rel, NoLock);
|
||||
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s", name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call AddRelationRawConstraints to do the
|
||||
* real adding -- It duplicates some of the
|
||||
* above, but does not check the validity of
|
||||
* the constraint against tuples already in
|
||||
* the table.
|
||||
*/
|
||||
AddRelationRawConstraints(rel, NIL, constlist);
|
||||
heap_close(rel, NoLock);
|
||||
pfree(constlist);
|
||||
|
||||
break;
|
||||
}
|
||||
ResetExprContext(econtext);
|
||||
}
|
||||
|
||||
FreeExprContext(econtext);
|
||||
pfree(slot);
|
||||
|
||||
heap_endscan(scan);
|
||||
|
||||
if (!successful)
|
||||
{
|
||||
heap_close(rel, NoLock);
|
||||
elog(ERROR, "AlterTableAddConstraint: rejected due to CHECK constraint %s", name);
|
||||
}
|
||||
/*
|
||||
* Call AddRelationRawConstraints to do the real adding --
|
||||
* It duplicates some of the above, but does not check the
|
||||
* validity of the constraint against tuples already in
|
||||
* the table.
|
||||
*/
|
||||
AddRelationRawConstraints(rel, NIL, constlist);
|
||||
heap_close(rel, NoLock);
|
||||
pfree(constlist);
|
||||
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented for that constraint type.");
|
||||
}
|
||||
default:
|
||||
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented for that constraint type.");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_FkConstraint:
|
||||
{
|
||||
FkConstraint *fkconstraint = (FkConstraint *) newConstraint;
|
||||
Relation rel, pkrel;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
Trigger trig;
|
||||
List *list;
|
||||
int count;
|
||||
List *indexoidlist,
|
||||
*indexoidscan;
|
||||
Form_pg_attribute *rel_attrs = NULL;
|
||||
int i;
|
||||
bool found = false;
|
||||
|
||||
if (is_temp_rel_name(fkconstraint->pktable_name) &&
|
||||
!is_temp_rel_name(relationName))
|
||||
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
|
||||
|
||||
/*
|
||||
* Grab an exclusive lock on the pk table, so that someone
|
||||
* doesn't delete rows out from under us.
|
||||
*/
|
||||
|
||||
pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock);
|
||||
if (pkrel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "referenced table \"%s\" not a relation",
|
||||
fkconstraint->pktable_name);
|
||||
|
||||
/*
|
||||
* Grab an exclusive lock on the fk table, and then scan
|
||||
* through each tuple, calling the RI_FKey_Match_Ins
|
||||
* (insert trigger) as if that tuple had just been
|
||||
* inserted. If any of those fail, it should elog(ERROR)
|
||||
* and that's that.
|
||||
*/
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "referencing table \"%s\" not a relation",
|
||||
relationName);
|
||||
|
||||
/* First we check for limited correctness of the constraint */
|
||||
|
||||
rel_attrs = pkrel->rd_att->attrs;
|
||||
indexoidlist = RelationGetIndexList(pkrel);
|
||||
|
||||
foreach(indexoidscan, indexoidlist)
|
||||
{
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
HeapTuple indexTuple;
|
||||
Form_pg_index indexStruct;
|
||||
FkConstraint *fkconstraint = (FkConstraint *) newConstraint;
|
||||
Relation rel,
|
||||
pkrel;
|
||||
HeapScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
Trigger trig;
|
||||
List *list;
|
||||
int count;
|
||||
List *indexoidlist,
|
||||
*indexoidscan;
|
||||
Form_pg_attribute *rel_attrs = NULL;
|
||||
int i;
|
||||
bool found = false;
|
||||
|
||||
indexTuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(indexTuple))
|
||||
elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
|
||||
indexoid);
|
||||
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
|
||||
if (is_temp_rel_name(fkconstraint->pktable_name) &&
|
||||
!is_temp_rel_name(relationName))
|
||||
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT: Unable to reference temporary table from permanent table constraint.");
|
||||
|
||||
if (indexStruct->indisunique)
|
||||
/*
|
||||
* Grab an exclusive lock on the pk table, so that someone
|
||||
* doesn't delete rows out from under us.
|
||||
*/
|
||||
|
||||
pkrel = heap_openr(fkconstraint->pktable_name, AccessExclusiveLock);
|
||||
if (pkrel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "referenced table \"%s\" not a relation",
|
||||
fkconstraint->pktable_name);
|
||||
|
||||
/*
|
||||
* Grab an exclusive lock on the fk table, and then scan
|
||||
* through each tuple, calling the RI_FKey_Match_Ins
|
||||
* (insert trigger) as if that tuple had just been
|
||||
* inserted. If any of those fail, it should elog(ERROR)
|
||||
* and that's that.
|
||||
*/
|
||||
rel = heap_openr(relationName, AccessExclusiveLock);
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "referencing table \"%s\" not a relation",
|
||||
relationName);
|
||||
|
||||
/*
|
||||
* First we check for limited correctness of the
|
||||
* constraint
|
||||
*/
|
||||
|
||||
rel_attrs = pkrel->rd_att->attrs;
|
||||
indexoidlist = RelationGetIndexList(pkrel);
|
||||
|
||||
foreach(indexoidscan, indexoidlist)
|
||||
{
|
||||
List *attrl;
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
HeapTuple indexTuple;
|
||||
Form_pg_index indexStruct;
|
||||
|
||||
/* Make sure this index has the same number of keys -- It obviously
|
||||
* won't match otherwise. */
|
||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
|
||||
if (i!=length(fkconstraint->pk_attrs))
|
||||
found=false;
|
||||
else {
|
||||
/* go through the fkconstraint->pk_attrs list */
|
||||
foreach(attrl, fkconstraint->pk_attrs)
|
||||
{
|
||||
Ident *attr=lfirst(attrl);
|
||||
indexTuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(indexTuple))
|
||||
elog(ERROR, "transformFkeyGetPrimaryKey: index %u not found",
|
||||
indexoid);
|
||||
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
|
||||
|
||||
if (indexStruct->indisunique)
|
||||
{
|
||||
List *attrl;
|
||||
|
||||
/*
|
||||
* Make sure this index has the same number of
|
||||
* keys -- It obviously won't match otherwise.
|
||||
*/
|
||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
|
||||
if (i != length(fkconstraint->pk_attrs))
|
||||
found = false;
|
||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
|
||||
else
|
||||
{
|
||||
/* go through the fkconstraint->pk_attrs list */
|
||||
foreach(attrl, fkconstraint->pk_attrs)
|
||||
{
|
||||
int pkattno = indexStruct->indkey[i];
|
||||
if (pkattno>0)
|
||||
Ident *attr = lfirst(attrl);
|
||||
|
||||
found = false;
|
||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
|
||||
{
|
||||
char *name = NameStr(rel_attrs[pkattno-1]->attname);
|
||||
if (strcmp(name, attr->name)==0)
|
||||
int pkattno = indexStruct->indkey[i];
|
||||
|
||||
if (pkattno > 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
char *name = NameStr(rel_attrs[pkattno - 1]->attname);
|
||||
|
||||
if (strcmp(name, attr->name) == 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ReleaseSysCache(indexTuple);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
|
||||
fkconstraint->pktable_name);
|
||||
|
||||
freeList(indexoidlist);
|
||||
heap_close(pkrel, NoLock);
|
||||
|
||||
rel_attrs = rel->rd_att->attrs;
|
||||
if (fkconstraint->fk_attrs!=NIL) {
|
||||
List *fkattrs;
|
||||
Ident *fkattr;
|
||||
|
||||
found = false;
|
||||
foreach(fkattrs, fkconstraint->fk_attrs) {
|
||||
int count;
|
||||
found = false;
|
||||
fkattr=lfirst(fkattrs);
|
||||
for (count = 0; count < rel->rd_att->natts; count++) {
|
||||
char *name = NameStr(rel->rd_att->attrs[count]->attname);
|
||||
if (strcmp(name, fkattr->name)==0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
ReleaseSysCache(indexTuple);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
elog(ERROR, "columns referenced in foreign key constraint not found.");
|
||||
}
|
||||
elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
|
||||
fkconstraint->pktable_name);
|
||||
|
||||
trig.tgoid = 0;
|
||||
if (fkconstraint->constr_name)
|
||||
trig.tgname = fkconstraint->constr_name;
|
||||
else
|
||||
trig.tgname = "<unknown>";
|
||||
trig.tgfoid = 0;
|
||||
trig.tgtype = 0;
|
||||
trig.tgenabled = TRUE;
|
||||
trig.tgisconstraint = TRUE;
|
||||
trig.tginitdeferred = FALSE;
|
||||
trig.tgdeferrable = FALSE;
|
||||
freeList(indexoidlist);
|
||||
heap_close(pkrel, NoLock);
|
||||
|
||||
trig.tgargs = (char **) palloc(
|
||||
sizeof(char *) * (4 + length(fkconstraint->fk_attrs)
|
||||
+ length(fkconstraint->pk_attrs)));
|
||||
rel_attrs = rel->rd_att->attrs;
|
||||
if (fkconstraint->fk_attrs != NIL)
|
||||
{
|
||||
List *fkattrs;
|
||||
Ident *fkattr;
|
||||
|
||||
if (fkconstraint->constr_name)
|
||||
trig.tgargs[0] = fkconstraint->constr_name;
|
||||
else
|
||||
trig.tgargs[0] = "<unknown>";
|
||||
trig.tgargs[1] = (char *) relationName;
|
||||
trig.tgargs[2] = fkconstraint->pktable_name;
|
||||
trig.tgargs[3] = fkconstraint->match_type;
|
||||
count = 4;
|
||||
foreach(list, fkconstraint->fk_attrs)
|
||||
found = false;
|
||||
foreach(fkattrs, fkconstraint->fk_attrs)
|
||||
{
|
||||
int count;
|
||||
|
||||
found = false;
|
||||
fkattr = lfirst(fkattrs);
|
||||
for (count = 0; count < rel->rd_att->natts; count++)
|
||||
{
|
||||
char *name = NameStr(rel->rd_att->attrs[count]->attname);
|
||||
|
||||
if (strcmp(name, fkattr->name) == 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
elog(ERROR, "columns referenced in foreign key constraint not found.");
|
||||
}
|
||||
|
||||
trig.tgoid = 0;
|
||||
if (fkconstraint->constr_name)
|
||||
trig.tgname = fkconstraint->constr_name;
|
||||
else
|
||||
trig.tgname = "<unknown>";
|
||||
trig.tgfoid = 0;
|
||||
trig.tgtype = 0;
|
||||
trig.tgenabled = TRUE;
|
||||
trig.tgisconstraint = TRUE;
|
||||
trig.tginitdeferred = FALSE;
|
||||
trig.tgdeferrable = FALSE;
|
||||
|
||||
trig.tgargs = (char **) palloc(
|
||||
sizeof(char *) * (4 + length(fkconstraint->fk_attrs)
|
||||
+ length(fkconstraint->pk_attrs)));
|
||||
|
||||
if (fkconstraint->constr_name)
|
||||
trig.tgargs[0] = fkconstraint->constr_name;
|
||||
else
|
||||
trig.tgargs[0] = "<unknown>";
|
||||
trig.tgargs[1] = (char *) relationName;
|
||||
trig.tgargs[2] = fkconstraint->pktable_name;
|
||||
trig.tgargs[3] = fkconstraint->match_type;
|
||||
count = 4;
|
||||
foreach(list, fkconstraint->fk_attrs)
|
||||
{
|
||||
Ident *fk_at = lfirst(list);
|
||||
|
||||
trig.tgargs[count] = fk_at->name;
|
||||
count+=2;
|
||||
count += 2;
|
||||
}
|
||||
count = 5;
|
||||
foreach(list, fkconstraint->pk_attrs)
|
||||
count = 5;
|
||||
foreach(list, fkconstraint->pk_attrs)
|
||||
{
|
||||
Ident *pk_at = lfirst(list);
|
||||
|
||||
trig.tgargs[count] = pk_at->name;
|
||||
count+=2;
|
||||
count += 2;
|
||||
}
|
||||
trig.tgnargs = count-1;
|
||||
trig.tgnargs = count - 1;
|
||||
|
||||
scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
|
||||
AssertState(scan != NULL);
|
||||
scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
|
||||
AssertState(scan != NULL);
|
||||
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
/* Make a call to the check function */
|
||||
/* No parameters are passed, but we do set a context */
|
||||
FunctionCallInfoData fcinfo;
|
||||
TriggerData trigdata;
|
||||
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
{
|
||||
/* Make a call to the check function */
|
||||
/* No parameters are passed, but we do set a context */
|
||||
FunctionCallInfoData fcinfo;
|
||||
TriggerData trigdata;
|
||||
|
||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||
/* We assume RI_FKey_check_ins won't look at flinfo... */
|
||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||
/* We assume RI_FKey_check_ins won't look at flinfo... */
|
||||
|
||||
trigdata.type = T_TriggerData;
|
||||
trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
|
||||
trigdata.tg_relation = rel;
|
||||
trigdata.tg_trigtuple = tuple;
|
||||
trigdata.tg_newtuple = NULL;
|
||||
trigdata.tg_trigger = &trig;
|
||||
trigdata.type = T_TriggerData;
|
||||
trigdata.tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
|
||||
trigdata.tg_relation = rel;
|
||||
trigdata.tg_trigtuple = tuple;
|
||||
trigdata.tg_newtuple = NULL;
|
||||
trigdata.tg_trigger = &trig;
|
||||
|
||||
fcinfo.context = (Node *) &trigdata;
|
||||
fcinfo.context = (Node *) &trigdata;
|
||||
|
||||
RI_FKey_check_ins(&fcinfo);
|
||||
RI_FKey_check_ins(&fcinfo);
|
||||
}
|
||||
heap_endscan(scan);
|
||||
heap_close(rel, NoLock); /* close rel but keep
|
||||
* lock! */
|
||||
|
||||
pfree(trig.tgargs);
|
||||
break;
|
||||
}
|
||||
heap_endscan(scan);
|
||||
heap_close(rel, NoLock); /* close rel but keep
|
||||
* lock! */
|
||||
|
||||
pfree(trig.tgargs);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
elog(ERROR, "ALTER TABLE / ADD CONSTRAINT unable to determine type of constraint passed");
|
||||
}
|
||||
@@ -1464,15 +1486,15 @@ AlterTableDropConstraint(const char *relationName,
|
||||
void
|
||||
AlterTableOwner(const char *relationName, const char *newOwnerName)
|
||||
{
|
||||
Relation class_rel;
|
||||
HeapTuple tuple;
|
||||
Relation class_rel;
|
||||
HeapTuple tuple;
|
||||
int32 newOwnerSysid;
|
||||
Relation idescs[Num_pg_class_indices];
|
||||
|
||||
/*
|
||||
* first check that we are a superuser
|
||||
*/
|
||||
if (! superuser())
|
||||
if (!superuser())
|
||||
elog(ERROR, "ALTER TABLE: permission denied");
|
||||
|
||||
/*
|
||||
@@ -1537,21 +1559,21 @@ AlterTableOwner(const char *relationName, const char *newOwnerName)
|
||||
void
|
||||
AlterTableCreateToastTable(const char *relationName, bool silent)
|
||||
{
|
||||
Relation rel;
|
||||
Oid myrelid;
|
||||
HeapTuple reltup;
|
||||
HeapTupleData classtuple;
|
||||
TupleDesc tupdesc;
|
||||
Relation class_rel;
|
||||
Buffer buffer;
|
||||
Relation ridescs[Num_pg_class_indices];
|
||||
Oid toast_relid;
|
||||
Oid toast_idxid;
|
||||
char toast_relname[NAMEDATALEN + 1];
|
||||
char toast_idxname[NAMEDATALEN + 1];
|
||||
Relation toast_idxrel;
|
||||
IndexInfo *indexInfo;
|
||||
Oid classObjectId[1];
|
||||
Relation rel;
|
||||
Oid myrelid;
|
||||
HeapTuple reltup;
|
||||
HeapTupleData classtuple;
|
||||
TupleDesc tupdesc;
|
||||
Relation class_rel;
|
||||
Buffer buffer;
|
||||
Relation ridescs[Num_pg_class_indices];
|
||||
Oid toast_relid;
|
||||
Oid toast_idxid;
|
||||
char toast_relname[NAMEDATALEN + 1];
|
||||
char toast_idxname[NAMEDATALEN + 1];
|
||||
Relation toast_idxrel;
|
||||
IndexInfo *indexInfo;
|
||||
Oid classObjectId[1];
|
||||
|
||||
/*
|
||||
* permissions checking. XXX exactly what is appropriate here?
|
||||
@@ -1618,7 +1640,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
|
||||
/*
|
||||
* Check to see whether the table actually needs a TOAST table.
|
||||
*/
|
||||
if (! needs_toast_table(rel))
|
||||
if (!needs_toast_table(rel))
|
||||
{
|
||||
if (silent)
|
||||
{
|
||||
@@ -1652,10 +1674,11 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
|
||||
"chunk_data",
|
||||
BYTEAOID,
|
||||
-1, 0, false);
|
||||
|
||||
/*
|
||||
* Ensure that the toast table doesn't itself get toasted,
|
||||
* or we'll be toast :-(. This is essential for chunk_data because
|
||||
* type bytea is toastable; hit the other two just to be sure.
|
||||
* Ensure that the toast table doesn't itself get toasted, or we'll be
|
||||
* toast :-(. This is essential for chunk_data because type bytea is
|
||||
* toastable; hit the other two just to be sure.
|
||||
*/
|
||||
tupdesc->attrs[0]->attstorage = 'p';
|
||||
tupdesc->attrs[1]->attstorage = 'p';
|
||||
@@ -1733,7 +1756,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see whether the table needs a TOAST table. It does only if
|
||||
* Check to see whether the table needs a TOAST table. It does only if
|
||||
* (1) there are any toastable attributes, and (2) the maximum length
|
||||
* of a tuple could exceed TOAST_TUPLE_THRESHOLD. (We don't want to
|
||||
* create a toast table for something like "f1 varchar(20)".)
|
||||
@@ -1745,7 +1768,7 @@ needs_toast_table(Relation rel)
|
||||
bool maxlength_unknown = false;
|
||||
bool has_toastable_attrs = false;
|
||||
TupleDesc tupdesc;
|
||||
Form_pg_attribute *att;
|
||||
Form_pg_attribute *att;
|
||||
int32 tuple_length;
|
||||
int i;
|
||||
|
||||
@@ -1762,8 +1785,8 @@ needs_toast_table(Relation rel)
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 maxlen = type_maximum_size(att[i]->atttypid,
|
||||
att[i]->atttypmod);
|
||||
int32 maxlen = type_maximum_size(att[i]->atttypid,
|
||||
att[i]->atttypmod);
|
||||
|
||||
if (maxlen < 0)
|
||||
maxlength_unknown = true;
|
||||
@@ -1798,7 +1821,7 @@ LockTableCommand(LockStmt *lockstmt)
|
||||
rel = heap_openr(lockstmt->relname, NoLock);
|
||||
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname);
|
||||
elog(ERROR, "LOCK TABLE: %s is not a table", lockstmt->relname);
|
||||
|
||||
if (lockstmt->mode == AccessShareLock)
|
||||
aclresult = pg_aclcheck(lockstmt->relname, GetUserId(), ACL_RD);
|
||||
@@ -1817,9 +1840,9 @@ LockTableCommand(LockStmt *lockstmt)
|
||||
static bool
|
||||
is_relation(char *name)
|
||||
{
|
||||
Relation rel = heap_openr(name, NoLock);
|
||||
Relation rel = heap_openr(name, NoLock);
|
||||
|
||||
bool retval = (rel->rd_rel->relkind == RELKIND_RELATION);
|
||||
bool retval = (rel->rd_rel->relkind == RELKIND_RELATION);
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Copyright (c) 1999, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.26 2001/01/23 04:32:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.27 2001/03/22 03:59:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -55,7 +55,7 @@ static void CommentAggregate(char *aggregate, List *arguments, char *comment);
|
||||
static void CommentProc(char *function, List *arguments, char *comment);
|
||||
static void CommentOperator(char *opname, List *arguments, char *comment);
|
||||
static void CommentTrigger(char *trigger, char *relation, char *comments);
|
||||
static void CreateComments(Oid oid, char *comment);
|
||||
static void CreateComments(Oid oid, char *comment);
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
* CommentObject --
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.134 2001/03/14 21:47:50 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.135 2001/03/22 03:59:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -76,6 +76,7 @@ static StringInfoData attribute_buf;
|
||||
#ifdef MULTIBYTE
|
||||
static int client_encoding;
|
||||
static int server_encoding;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -285,6 +286,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||
elog(ERROR, "You must have Postgres superuser privilege to do a COPY "
|
||||
"directly to or from a file. Anyone can COPY to stdout or "
|
||||
"from stdin. Psql's \\copy command also works for anyone.");
|
||||
|
||||
/*
|
||||
* This restriction is unfortunate, but necessary until the frontend
|
||||
* COPY protocol is redesigned to be binary-safe...
|
||||
@@ -344,8 +346,8 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
|
||||
mode_t oumask; /* Pre-existing umask value */
|
||||
|
||||
/*
|
||||
* Prevent write to relative path ... too easy to shoot oneself
|
||||
* in the foot by overwriting a database file ...
|
||||
* Prevent write to relative path ... too easy to shoot
|
||||
* oneself in the foot by overwriting a database file ...
|
||||
*/
|
||||
if (filename[0] != '/')
|
||||
elog(ERROR, "Relative path not allowed for server side"
|
||||
@@ -408,7 +410,10 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
attr_count = rel->rd_att->natts;
|
||||
attr = rel->rd_att->attrs;
|
||||
|
||||
/* For binary copy we really only need isvarlena, but compute it all... */
|
||||
/*
|
||||
* For binary copy we really only need isvarlena, but compute it
|
||||
* all...
|
||||
*/
|
||||
out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo));
|
||||
elements = (Oid *) palloc(attr_count * sizeof(Oid));
|
||||
isvarlena = (bool *) palloc(attr_count * sizeof(bool));
|
||||
@@ -417,7 +422,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
Oid out_func_oid;
|
||||
|
||||
if (!getTypeOutputInfo(attr[i]->atttypid,
|
||||
&out_func_oid, &elements[i], &isvarlena[i]))
|
||||
&out_func_oid, &elements[i], &isvarlena[i]))
|
||||
elog(ERROR, "COPY: couldn't lookup info for type %u",
|
||||
attr[i]->atttypid);
|
||||
fmgr_info(out_func_oid, &out_functions[i]);
|
||||
@@ -454,7 +459,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
if (binary)
|
||||
{
|
||||
/* Binary per-tuple header */
|
||||
int16 fld_count = attr_count;
|
||||
int16 fld_count = attr_count;
|
||||
|
||||
CopySendData(&fld_count, sizeof(int16), fp);
|
||||
/* Send OID if wanted --- note fld_count doesn't include it */
|
||||
@@ -471,7 +476,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
if (oids)
|
||||
{
|
||||
string = DatumGetCString(DirectFunctionCall1(oidout,
|
||||
ObjectIdGetDatum(tuple->t_data->t_oid)));
|
||||
ObjectIdGetDatum(tuple->t_data->t_oid)));
|
||||
CopySendString(string, fp);
|
||||
pfree(string);
|
||||
need_delim = true;
|
||||
@@ -497,20 +502,22 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
{
|
||||
if (!binary)
|
||||
{
|
||||
CopySendString(null_print, fp); /* null indicator */
|
||||
CopySendString(null_print, fp); /* null indicator */
|
||||
}
|
||||
else
|
||||
{
|
||||
fld_size = 0; /* null marker */
|
||||
fld_size = 0; /* null marker */
|
||||
CopySendData(&fld_size, sizeof(int16), fp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it to avoid
|
||||
* memory leakage inside the type's output routine (or
|
||||
* for binary case, becase we must output untoasted value).
|
||||
* If we have a toasted datum, forcibly detoast it to
|
||||
* avoid memory leakage inside the type's output routine
|
||||
* (or for binary case, becase we must output untoasted
|
||||
* value).
|
||||
*/
|
||||
if (isvarlena[i])
|
||||
value = PointerGetDatum(PG_DETOAST_DATUM(origvalue));
|
||||
@@ -520,9 +527,9 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
if (!binary)
|
||||
{
|
||||
string = DatumGetCString(FunctionCall3(&out_functions[i],
|
||||
value,
|
||||
ObjectIdGetDatum(elements[i]),
|
||||
Int32GetDatum(attr[i]->atttypmod)));
|
||||
value,
|
||||
ObjectIdGetDatum(elements[i]),
|
||||
Int32GetDatum(attr[i]->atttypmod)));
|
||||
CopyAttributeOut(fp, string, delim);
|
||||
pfree(string);
|
||||
}
|
||||
@@ -552,8 +559,9 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
Datum datumBuf;
|
||||
|
||||
/*
|
||||
* We need this horsing around because we don't know
|
||||
* how shorter data values are aligned within a Datum.
|
||||
* We need this horsing around because we don't
|
||||
* know how shorter data values are aligned within
|
||||
* a Datum.
|
||||
*/
|
||||
store_att_byval(&datumBuf, value, fld_size);
|
||||
CopySendData(&datumBuf,
|
||||
@@ -577,7 +585,7 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
if (binary)
|
||||
{
|
||||
/* Generate trailer for a binary copy */
|
||||
int16 fld_count = -1;
|
||||
int16 fld_count = -1;
|
||||
|
||||
CopySendData(&fld_count, sizeof(int16), fp);
|
||||
}
|
||||
@@ -609,7 +617,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
int done = 0;
|
||||
char *string;
|
||||
ResultRelInfo *resultRelInfo;
|
||||
EState *estate = CreateExecutorState(); /* for ExecConstraints() */
|
||||
EState *estate = CreateExecutorState(); /* for ExecConstraints() */
|
||||
TupleTable tupleTable;
|
||||
TupleTableSlot *slot;
|
||||
Oid loaded_oid = InvalidOid;
|
||||
@@ -622,11 +630,11 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
|
||||
/*
|
||||
* We need a ResultRelInfo so we can use the regular executor's
|
||||
* index-entry-making machinery. (There used to be a huge amount
|
||||
* of code here that basically duplicated execUtils.c ...)
|
||||
* index-entry-making machinery. (There used to be a huge amount of
|
||||
* code here that basically duplicated execUtils.c ...)
|
||||
*/
|
||||
resultRelInfo = makeNode(ResultRelInfo);
|
||||
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
|
||||
resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
|
||||
resultRelInfo->ri_RelationDesc = rel;
|
||||
|
||||
ExecOpenIndices(resultRelInfo);
|
||||
@@ -673,7 +681,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
if (CopyGetEof(fp))
|
||||
elog(ERROR, "COPY BINARY: bogus file header (missing flags)");
|
||||
file_has_oids = (tmp & (1 << 16)) != 0;
|
||||
tmp &= ~ (1 << 16);
|
||||
tmp &= ~(1 << 16);
|
||||
if ((tmp >> 16) != 0)
|
||||
elog(ERROR, "COPY BINARY: unrecognized critical flags in header");
|
||||
/* Header extension length */
|
||||
@@ -727,7 +735,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
else
|
||||
{
|
||||
loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin,
|
||||
CStringGetDatum(string)));
|
||||
CStringGetDatum(string)));
|
||||
if (loaded_oid == InvalidOid)
|
||||
elog(ERROR, "COPY TEXT: Invalid Oid");
|
||||
}
|
||||
@@ -747,8 +755,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
{
|
||||
values[i] = FunctionCall3(&in_functions[i],
|
||||
CStringGetDatum(string),
|
||||
ObjectIdGetDatum(elements[i]),
|
||||
Int32GetDatum(attr[i]->atttypmod));
|
||||
ObjectIdGetDatum(elements[i]),
|
||||
Int32GetDatum(attr[i]->atttypmod));
|
||||
nulls[i] = ' ';
|
||||
}
|
||||
}
|
||||
@@ -757,8 +765,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
}
|
||||
else
|
||||
{ /* binary */
|
||||
int16 fld_count,
|
||||
fld_size;
|
||||
int16 fld_count,
|
||||
fld_size;
|
||||
|
||||
CopyGetData(&fld_count, sizeof(int16), fp);
|
||||
if (CopyGetEof(fp) ||
|
||||
@@ -791,15 +799,15 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
if (CopyGetEof(fp))
|
||||
elog(ERROR, "COPY BINARY: unexpected EOF");
|
||||
if (fld_size == 0)
|
||||
continue; /* it's NULL; nulls[i] already set */
|
||||
continue; /* it's NULL; nulls[i] already set */
|
||||
if (fld_size != attr[i]->attlen)
|
||||
elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d",
|
||||
i+1, (int) fld_size, (int) attr[i]->attlen);
|
||||
i + 1, (int) fld_size, (int) attr[i]->attlen);
|
||||
if (fld_size == -1)
|
||||
{
|
||||
/* varlena field */
|
||||
int32 varlena_size;
|
||||
Pointer varlena_ptr;
|
||||
int32 varlena_size;
|
||||
Pointer varlena_ptr;
|
||||
|
||||
CopyGetData(&varlena_size, sizeof(int32), fp);
|
||||
if (CopyGetEof(fp))
|
||||
@@ -818,7 +826,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
else if (!attr[i]->attbyval)
|
||||
{
|
||||
/* fixed-length pass-by-reference */
|
||||
Pointer refval_ptr;
|
||||
Pointer refval_ptr;
|
||||
|
||||
Assert(fld_size > 0);
|
||||
refval_ptr = (Pointer) palloc(fld_size);
|
||||
@@ -833,8 +841,9 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
|
||||
Datum datumBuf;
|
||||
|
||||
/*
|
||||
* We need this horsing around because we don't know
|
||||
* how shorter data values are aligned within a Datum.
|
||||
* We need this horsing around because we don't
|
||||
* know how shorter data values are aligned within
|
||||
* a Datum.
|
||||
*/
|
||||
Assert(fld_size > 0 && fld_size <= sizeof(Datum));
|
||||
CopyGetData(&datumBuf, fld_size, fp);
|
||||
@@ -1163,6 +1172,7 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
|
||||
char *string_start;
|
||||
int mblen;
|
||||
int i;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
@@ -1182,7 +1192,7 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
|
||||
#endif
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
for (; (mblen = (server_encoding == client_encoding? 1 : pg_encoding_mblen(client_encoding, string))) &&
|
||||
for (; (mblen = (server_encoding == client_encoding ? 1 : pg_encoding_mblen(client_encoding, string))) &&
|
||||
((c = *string) != '\0'); string += mblen)
|
||||
#else
|
||||
for (; (c = *string) != '\0'; string++)
|
||||
@@ -1199,7 +1209,7 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim)
|
||||
}
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
if (client_encoding != server_encoding)
|
||||
if (client_encoding != server_encoding)
|
||||
pfree(string_start); /* pfree pg_server_to_client result */
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.72 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.73 2001/03/22 03:59:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,7 +37,7 @@
|
||||
static int checkAttrExists(const char *attributeName,
|
||||
const char *attributeType, List *schema);
|
||||
static List *MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
List **supOids, List **supconstr);
|
||||
List **supOids, List **supconstr);
|
||||
static void StoreCatalogInheritance(Oid relationId, List *supers);
|
||||
static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass);
|
||||
|
||||
@@ -150,10 +150,10 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* Open the new relation and acquire exclusive lock on it. This isn't
|
||||
* Open the new relation and acquire exclusive lock on it. This isn't
|
||||
* really necessary for locking out other backends (since they can't
|
||||
* see the new rel anyway until we commit), but it keeps the lock manager
|
||||
* from complaining about deadlock risks.
|
||||
* see the new rel anyway until we commit), but it keeps the lock
|
||||
* manager from complaining about deadlock risks.
|
||||
*/
|
||||
rel = heap_openr(relname, AccessExclusiveLock);
|
||||
|
||||
@@ -242,7 +242,7 @@ TruncateRelation(char *name)
|
||||
* Varattnos of pg_relcheck.rcbin should be rewritten when
|
||||
* subclasses inherit the constraints from the super class.
|
||||
* Note that these functions rewrite varattnos while walking
|
||||
* through a node tree.
|
||||
* through a node tree.
|
||||
*/
|
||||
static bool
|
||||
change_varattnos_walker(Node *node, const AttrNumber *newattno)
|
||||
@@ -251,15 +251,15 @@ change_varattnos_walker(Node *node, const AttrNumber *newattno)
|
||||
return false;
|
||||
if (IsA(node, Var))
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
Var *var = (Var *) node;
|
||||
|
||||
if (var->varlevelsup == 0 && var->varno == 1)
|
||||
{
|
||||
|
||||
/*
|
||||
* ??? the following may be a problem when the
|
||||
* node is multiply referenced though
|
||||
* stringToNode() doesn't create such a node
|
||||
* currently.
|
||||
* ??? the following may be a problem when the node is
|
||||
* multiply referenced though stringToNode() doesn't create
|
||||
* such a node currently.
|
||||
*/
|
||||
Assert(newattno[var->varattno - 1] > 0);
|
||||
var->varattno = newattno[var->varattno - 1];
|
||||
@@ -373,9 +373,12 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
AttrNumber attrno;
|
||||
TupleDesc tupleDesc;
|
||||
TupleConstr *constr;
|
||||
AttrNumber *newattno, *partialAttidx;
|
||||
Node *expr;
|
||||
int i, attidx, attno_exist;
|
||||
AttrNumber *newattno,
|
||||
*partialAttidx;
|
||||
Node *expr;
|
||||
int i,
|
||||
attidx,
|
||||
attno_exist;
|
||||
|
||||
relation = heap_openr(name, AccessShareLock);
|
||||
|
||||
@@ -385,7 +388,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
if (!istemp && is_temp_rel_name(name))
|
||||
elog(ERROR, "CREATE TABLE: cannot inherit from temp relation \"%s\"", name);
|
||||
|
||||
/* We should have an UNDER permission flag for this, but for now,
|
||||
/*
|
||||
* We should have an UNDER permission flag for this, but for now,
|
||||
* demand that creator of a child table own the parent.
|
||||
*/
|
||||
if (!pg_ownercheck(GetUserId(), name, RELNAME))
|
||||
@@ -397,14 +401,15 @@ MergeAttributes(List *schema, List *supers, bool istemp,
|
||||
/* allocate a new attribute number table and initialize */
|
||||
newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
|
||||
for (i = 0; i < tupleDesc->natts; i++)
|
||||
newattno [i] = 0;
|
||||
newattno[i] = 0;
|
||||
|
||||
/*
|
||||
* searching and storing order are different.
|
||||
* another table is needed.
|
||||
*/
|
||||
* searching and storing order are different. another table is
|
||||
* needed.
|
||||
*/
|
||||
partialAttidx = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber));
|
||||
for (i = 0; i < tupleDesc->natts; i++)
|
||||
partialAttidx [i] = 0;
|
||||
partialAttidx[i] = 0;
|
||||
constr = tupleDesc->constr;
|
||||
|
||||
attidx = 0;
|
||||
@@ -577,9 +582,9 @@ StoreCatalogInheritance(Oid relationId, List *supers)
|
||||
Datum datum[Natts_pg_inherits];
|
||||
char nullarr[Natts_pg_inherits];
|
||||
|
||||
datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
|
||||
datum[1] = ObjectIdGetDatum(entryOid); /* inhparent */
|
||||
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
|
||||
datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
|
||||
datum[1] = ObjectIdGetDatum(entryOid); /* inhparent */
|
||||
datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
|
||||
|
||||
nullarr[0] = ' ';
|
||||
nullarr[1] = ' ';
|
||||
@@ -730,7 +735,7 @@ checkAttrExists(const char *attributeName, const char *attributeType,
|
||||
List *schema)
|
||||
{
|
||||
List *s;
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
|
||||
foreach(s, schema)
|
||||
{
|
||||
@@ -756,9 +761,9 @@ checkAttrExists(const char *attributeName, const char *attributeType,
|
||||
static void
|
||||
setRelhassubclassInRelation(Oid relationId, bool relhassubclass)
|
||||
{
|
||||
Relation relationRelation;
|
||||
HeapTuple tuple;
|
||||
Relation idescs[Num_pg_class_indices];
|
||||
Relation relationRelation;
|
||||
HeapTuple tuple;
|
||||
Relation idescs[Num_pg_class_indices];
|
||||
|
||||
/*
|
||||
* Fetch a modifiable copy of the tuple, modify it, update pg_class.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.73 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.74 2001/03/22 03:59:22 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,8 +36,8 @@
|
||||
|
||||
/* non-export function prototypes */
|
||||
static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
int *encodingP, bool *dbIsTemplateP,
|
||||
Oid *dbLastSysOidP, char *dbpath);
|
||||
int *encodingP, bool *dbIsTemplateP,
|
||||
Oid *dbLastSysOidP, char *dbpath);
|
||||
static bool get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb);
|
||||
static char *resolve_alt_dbpath(const char *dbpath, Oid dboid);
|
||||
static bool remove_dbdirs(const char *real_loc, const char *altloc);
|
||||
@@ -82,12 +82,12 @@ createdb(const char *dbname, const char *dbpath,
|
||||
elog(ERROR, "CREATE DATABASE: may not be called in a transaction block");
|
||||
|
||||
/*
|
||||
* Check for db name conflict. There is a race condition here, since
|
||||
* Check for db name conflict. There is a race condition here, since
|
||||
* another backend could create the same DB name before we commit.
|
||||
* However, holding an exclusive lock on pg_database for the whole time
|
||||
* we are copying the source database doesn't seem like a good idea,
|
||||
* so accept possibility of race to create. We will check again after
|
||||
* we grab the exclusive lock.
|
||||
* However, holding an exclusive lock on pg_database for the whole
|
||||
* time we are copying the source database doesn't seem like a good
|
||||
* idea, so accept possibility of race to create. We will check again
|
||||
* after we grab the exclusive lock.
|
||||
*/
|
||||
if (get_db_info(dbname, NULL, NULL, NULL, NULL, NULL, NULL))
|
||||
elog(ERROR, "CREATE DATABASE: database \"%s\" already exists", dbname);
|
||||
@@ -96,15 +96,16 @@ createdb(const char *dbname, const char *dbpath,
|
||||
* Lookup database (template) to be cloned.
|
||||
*/
|
||||
if (!dbtemplate)
|
||||
dbtemplate = "template1"; /* Default template database name */
|
||||
dbtemplate = "template1"; /* Default template database name */
|
||||
|
||||
if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
|
||||
&src_istemplate, &src_lastsysoid, src_dbpath))
|
||||
elog(ERROR, "CREATE DATABASE: template \"%s\" does not exist",
|
||||
dbtemplate);
|
||||
|
||||
/*
|
||||
* Permission check: to copy a DB that's not marked datistemplate,
|
||||
* you must be superuser or the owner thereof.
|
||||
* Permission check: to copy a DB that's not marked datistemplate, you
|
||||
* must be superuser or the owner thereof.
|
||||
*/
|
||||
if (!src_istemplate)
|
||||
{
|
||||
@@ -112,6 +113,7 @@ createdb(const char *dbname, const char *dbpath,
|
||||
elog(ERROR, "CREATE DATABASE: permission to copy \"%s\" denied",
|
||||
dbtemplate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine physical path of source database
|
||||
*/
|
||||
@@ -133,14 +135,16 @@ createdb(const char *dbname, const char *dbpath,
|
||||
if (encoding < 0)
|
||||
encoding = src_encoding;
|
||||
|
||||
/*
|
||||
* Preassign OID for pg_database tuple, so that we can compute db path.
|
||||
/*
|
||||
* Preassign OID for pg_database tuple, so that we can compute db
|
||||
* path.
|
||||
*/
|
||||
dboid = newoid();
|
||||
|
||||
/*
|
||||
* Compute nominal location (where we will try to access the database),
|
||||
* and resolve alternate physical location if one is specified.
|
||||
* Compute nominal location (where we will try to access the
|
||||
* database), and resolve alternate physical location if one is
|
||||
* specified.
|
||||
*/
|
||||
nominal_loc = GetDatabasePath(dboid);
|
||||
alt_loc = resolve_alt_dbpath(dbpath, dboid);
|
||||
@@ -155,8 +159,8 @@ createdb(const char *dbname, const char *dbpath,
|
||||
|
||||
/*
|
||||
* Force dirty buffers out to disk, to ensure source database is
|
||||
* up-to-date for the copy. (We really only need to flush buffers
|
||||
* for the source database...)
|
||||
* up-to-date for the copy. (We really only need to flush buffers for
|
||||
* the source database...)
|
||||
*/
|
||||
BufferSync();
|
||||
|
||||
@@ -231,7 +235,8 @@ createdb(const char *dbname, const char *dbpath,
|
||||
|
||||
tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
|
||||
|
||||
tuple->t_data->t_oid = dboid; /* override heap_insert's OID selection */
|
||||
tuple->t_data->t_oid = dboid; /* override heap_insert's OID
|
||||
* selection */
|
||||
|
||||
heap_insert(pg_database_rel, tuple);
|
||||
|
||||
@@ -273,9 +278,9 @@ dropdb(const char *dbname)
|
||||
bool db_istemplate;
|
||||
bool use_super;
|
||||
Oid db_id;
|
||||
char *alt_loc;
|
||||
char *nominal_loc;
|
||||
char dbpath[MAXPGPATH];
|
||||
char *alt_loc;
|
||||
char *nominal_loc;
|
||||
char dbpath[MAXPGPATH];
|
||||
Relation pgdbrel;
|
||||
HeapScanDesc pgdbscan;
|
||||
ScanKeyData key;
|
||||
@@ -311,8 +316,8 @@ dropdb(const char *dbname)
|
||||
elog(ERROR, "DROP DATABASE: permission denied");
|
||||
|
||||
/*
|
||||
* Disallow dropping a DB that is marked istemplate. This is just
|
||||
* to prevent people from accidentally dropping template0 or template1;
|
||||
* Disallow dropping a DB that is marked istemplate. This is just to
|
||||
* prevent people from accidentally dropping template0 or template1;
|
||||
* they can do so if they're really determined ...
|
||||
*/
|
||||
if (db_istemplate)
|
||||
@@ -338,6 +343,7 @@ dropdb(const char *dbname)
|
||||
tup = heap_getnext(pgdbscan, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
|
||||
/*
|
||||
* This error should never come up since the existence of the
|
||||
* database is checked earlier
|
||||
@@ -437,7 +443,7 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
|
||||
{
|
||||
tmptext = DatumGetTextP(heap_getattr(tuple,
|
||||
Anum_pg_database_datpath,
|
||||
RelationGetDescr(relation),
|
||||
RelationGetDescr(relation),
|
||||
&isnull));
|
||||
if (!isnull)
|
||||
{
|
||||
@@ -481,11 +487,11 @@ get_user_info(Oid use_sysid, bool *use_super, bool *use_createdb)
|
||||
|
||||
|
||||
static char *
|
||||
resolve_alt_dbpath(const char * dbpath, Oid dboid)
|
||||
resolve_alt_dbpath(const char *dbpath, Oid dboid)
|
||||
{
|
||||
const char * prefix;
|
||||
char * ret;
|
||||
size_t len;
|
||||
const char *prefix;
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
if (dbpath == NULL || dbpath[0] == '\0')
|
||||
return NULL;
|
||||
@@ -502,7 +508,8 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
|
||||
else
|
||||
{
|
||||
/* must be environment variable */
|
||||
char * var = getenv(dbpath);
|
||||
char *var = getenv(dbpath);
|
||||
|
||||
if (!var)
|
||||
elog(ERROR, "Postmaster environment variable '%s' not set", dbpath);
|
||||
if (var[0] != '/')
|
||||
@@ -519,11 +526,11 @@ resolve_alt_dbpath(const char * dbpath, Oid dboid)
|
||||
|
||||
|
||||
static bool
|
||||
remove_dbdirs(const char * nominal_loc, const char * alt_loc)
|
||||
remove_dbdirs(const char *nominal_loc, const char *alt_loc)
|
||||
{
|
||||
const char *target_dir;
|
||||
char buf[MAXPGPATH + 100];
|
||||
bool success = true;
|
||||
const char *target_dir;
|
||||
char buf[MAXPGPATH + 100];
|
||||
bool success = true;
|
||||
|
||||
target_dir = alt_loc ? alt_loc : nominal_loc;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.52 2001/02/12 20:07:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.53 2001/03/22 03:59:22 momjian Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@@ -70,7 +70,7 @@ case_translate_language_name(const char *input, char *output)
|
||||
--------------------------------------------------------------------------*/
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NAMEDATALEN-1 && input[i]; ++i)
|
||||
for (i = 0; i < NAMEDATALEN - 1 && input[i]; ++i)
|
||||
output[i] = tolower((unsigned char) input[i]);
|
||||
|
||||
output[i] = '\0';
|
||||
@@ -110,12 +110,12 @@ compute_full_attributes(List *parameters,
|
||||
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.
|
||||
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.
|
||||
inputs are present; instead a NULL result value should be assumed.
|
||||
|
||||
The other four parameters are not used anywhere. They used to be
|
||||
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.
|
||||
|
||||
@@ -217,21 +217,26 @@ void
|
||||
CreateFunction(ProcedureStmt *stmt, CommandDest dest)
|
||||
{
|
||||
char *probin_str;
|
||||
|
||||
/* pathname of executable file that executes this function, if any */
|
||||
|
||||
char *prosrc_str;
|
||||
|
||||
/* SQL that executes this function, if any */
|
||||
|
||||
char *prorettype;
|
||||
|
||||
/* Type of return value (or member of set of values) from function */
|
||||
|
||||
char languageName[NAMEDATALEN];
|
||||
|
||||
/*
|
||||
* name of language of function, with case adjusted: "C",
|
||||
* "internal", "sql", etc.
|
||||
* name of language of function, with case adjusted: "C", "internal",
|
||||
* "sql", etc.
|
||||
*/
|
||||
|
||||
bool returnsSet;
|
||||
|
||||
/* The function returns a set of values, as opposed to a singleton. */
|
||||
|
||||
/*
|
||||
@@ -257,7 +262,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
|
||||
if (!superuser())
|
||||
elog(ERROR,
|
||||
"Only users with Postgres superuser privilege are "
|
||||
"permitted to create a function in the '%s' language.\n\t"
|
||||
"permitted to create a function in the '%s' language.\n\t"
|
||||
"Others may use the 'sql' language "
|
||||
"or the created procedural languages.",
|
||||
languageName);
|
||||
@@ -380,14 +385,14 @@ DefineOperator(char *oprName,
|
||||
{
|
||||
typeName1 = defGetString(defel);
|
||||
if (IsA(defel->arg, TypeName)
|
||||
&& ((TypeName *) defel->arg)->setof)
|
||||
&&((TypeName *) defel->arg)->setof)
|
||||
elog(ERROR, "setof type not implemented for leftarg");
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "rightarg") == 0)
|
||||
{
|
||||
typeName2 = defGetString(defel);
|
||||
if (IsA(defel->arg, TypeName)
|
||||
&& ((TypeName *) defel->arg)->setof)
|
||||
&&((TypeName *) defel->arg)->setof)
|
||||
elog(ERROR, "setof type not implemented for rightarg");
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "procedure") == 0)
|
||||
@@ -478,8 +483,8 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
DefElem *defel = (DefElem *) lfirst(pl);
|
||||
|
||||
/*
|
||||
* sfunc1, stype1, and initcond1 are accepted as obsolete spellings
|
||||
* for sfunc, stype, initcond.
|
||||
* sfunc1, stype1, and initcond1 are accepted as obsolete
|
||||
* spellings for sfunc, stype, initcond.
|
||||
*/
|
||||
if (strcasecmp(defel->defname, "sfunc") == 0)
|
||||
transfuncName = defGetString(defel);
|
||||
@@ -515,12 +520,12 @@ DefineAggregate(char *aggName, List *parameters)
|
||||
/*
|
||||
* Most of the argument-checking is done inside of AggregateCreate
|
||||
*/
|
||||
AggregateCreate(aggName, /* aggregate name */
|
||||
transfuncName, /* step function name */
|
||||
finalfuncName, /* final function name */
|
||||
baseType, /* type of data being aggregated */
|
||||
transType, /* transition data type */
|
||||
initval); /* initial condition */
|
||||
AggregateCreate(aggName, /* aggregate name */
|
||||
transfuncName, /* step function name */
|
||||
finalfuncName, /* final function name */
|
||||
baseType, /* type of data being aggregated */
|
||||
transType, /* transition data type */
|
||||
initval); /* initial condition */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -543,13 +548,13 @@ 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 storage in TOAST */
|
||||
|
||||
/*
|
||||
* Type names must be one character shorter than other names,
|
||||
* allowing room to create the corresponding array type name with
|
||||
* prepended "_".
|
||||
* Type names must be one character shorter than other names, allowing
|
||||
* room to create the corresponding array type name with prepended
|
||||
* "_".
|
||||
*/
|
||||
if (strlen(typeName) > (NAMEDATALEN - 2))
|
||||
{
|
||||
@@ -692,14 +697,16 @@ defGetString(DefElem *def)
|
||||
switch (nodeTag(def->arg))
|
||||
{
|
||||
case T_Integer:
|
||||
{
|
||||
char *str = palloc(32);
|
||||
{
|
||||
char *str = palloc(32);
|
||||
|
||||
snprintf(str, 32, "%ld", (long) intVal(def->arg));
|
||||
return str;
|
||||
}
|
||||
snprintf(str, 32, "%ld", (long) intVal(def->arg));
|
||||
return str;
|
||||
}
|
||||
case T_Float:
|
||||
/* T_Float values are kept in string form, so this type cheat
|
||||
|
||||
/*
|
||||
* T_Float values are kept in string form, so this type cheat
|
||||
* works (and doesn't risk losing precision)
|
||||
*/
|
||||
return strVal(def->arg);
|
||||
|
||||
@@ -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.64 2001/01/27 01:41:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.65 2001/03/22 03:59:22 momjian Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -271,7 +271,7 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
||||
stringStringInfo(rte->relname));
|
||||
if (strcmp(rte->eref->relname, rte->relname) != 0)
|
||||
appendStringInfo(str, " %s",
|
||||
stringStringInfo(rte->eref->relname));
|
||||
stringStringInfo(rte->eref->relname));
|
||||
}
|
||||
break;
|
||||
case T_SubqueryScan:
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.45 2001/02/23 09:26:14 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.46 2001/03/22 03:59:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -49,15 +49,15 @@ static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
|
||||
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
|
||||
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
|
||||
static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
|
||||
IndexElem *funcIndex,
|
||||
Oid relId,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
IndexElem *funcIndex,
|
||||
Oid relId,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
|
||||
List *attList,
|
||||
Oid relId,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
List *attList,
|
||||
Oid relId,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
char *accessMethodName, Oid accessMethodId);
|
||||
static char *GetDefaultOpClass(Oid atttypid);
|
||||
|
||||
/*
|
||||
@@ -118,9 +118,9 @@ DefineIndex(char *heapRelationName,
|
||||
accessMethodName);
|
||||
|
||||
/*
|
||||
* XXX Hardwired hacks to check for limitations on supported index types.
|
||||
* We really ought to be learning this info from entries in the pg_am
|
||||
* table, instead of having it wired in here!
|
||||
* XXX Hardwired hacks to check for limitations on supported index
|
||||
* types. We really ought to be learning this info from entries in the
|
||||
* pg_am table, instead of having it wired in here!
|
||||
*/
|
||||
if (unique && accessMethodId != BTREE_AM_OID)
|
||||
elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
|
||||
@@ -161,7 +161,8 @@ DefineIndex(char *heapRelationName,
|
||||
elog(ERROR, "Existing indexes are inactive. REINDEX first");
|
||||
|
||||
/*
|
||||
* Prepare arguments for index_create, primarily an IndexInfo structure
|
||||
* Prepare arguments for index_create, primarily an IndexInfo
|
||||
* structure
|
||||
*/
|
||||
indexInfo = makeNode(IndexInfo);
|
||||
indexInfo->ii_Predicate = (Node *) cnfPred;
|
||||
@@ -207,7 +208,7 @@ DefineIndex(char *heapRelationName,
|
||||
|
||||
/*
|
||||
* We update the relation's pg_class tuple even if it already has
|
||||
* relhasindex = true. This is needed to cause a shared-cache-inval
|
||||
* relhasindex = true. This is needed to cause a shared-cache-inval
|
||||
* message to be sent for the pg_class tuple, which will cause other
|
||||
* backends to flush their relcache entries and in particular their
|
||||
* cached lists of the indexes for this relation.
|
||||
@@ -415,8 +416,8 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
||||
* has exact-match or binary-compatible input types.
|
||||
* ----------------
|
||||
*/
|
||||
if (! func_get_detail(funcIndex->name, nargs, argTypes,
|
||||
&funcid, &rettype, &retset, &true_typeids))
|
||||
if (!func_get_detail(funcIndex->name, nargs, argTypes,
|
||||
&funcid, &rettype, &retset, &true_typeids))
|
||||
func_error("DefineIndex", funcIndex->name, nargs, argTypes, NULL);
|
||||
|
||||
if (retset)
|
||||
@@ -425,7 +426,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
if (argTypes[i] != true_typeids[i] &&
|
||||
! IS_BINARY_COMPATIBLE(argTypes[i], true_typeids[i]))
|
||||
!IS_BINARY_COMPATIBLE(argTypes[i], true_typeids[i]))
|
||||
func_error("DefineIndex", funcIndex->name, nargs, argTypes,
|
||||
"Index function must be binary-compatible with table datatype");
|
||||
}
|
||||
@@ -439,7 +440,7 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
||||
|
||||
indexInfo->ii_FuncOid = funcid;
|
||||
/* Need to do the fmgr function lookup now, too */
|
||||
fmgr_info(funcid, & indexInfo->ii_FuncInfo);
|
||||
fmgr_info(funcid, &indexInfo->ii_FuncInfo);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -477,7 +478,7 @@ NormIndexAttrs(IndexInfo *indexInfo,
|
||||
indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
|
||||
|
||||
classOidP[attn] = GetAttrOpClass(attribute, attform->atttypid,
|
||||
accessMethodName, accessMethodId);
|
||||
accessMethodName, accessMethodId);
|
||||
|
||||
ReleaseSysCache(atttuple);
|
||||
attn++;
|
||||
@@ -515,8 +516,8 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
attribute->class);
|
||||
|
||||
/*
|
||||
* Assume the opclass is supported by this index access method
|
||||
* if we can find at least one relevant entry in pg_amop.
|
||||
* Assume the opclass is supported by this index access method if we
|
||||
* can find at least one relevant entry in pg_amop.
|
||||
*/
|
||||
ScanKeyEntryInitialize(&entry[0], 0,
|
||||
Anum_pg_amop_amopid,
|
||||
@@ -530,7 +531,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
|
||||
scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
|
||||
|
||||
if (! HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
if (!HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||
elog(ERROR, "DefineIndex: opclass \"%s\" not supported by access method \"%s\"",
|
||||
attribute->class, accessMethodName);
|
||||
|
||||
@@ -540,17 +541,18 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Make sure the operators associated with this opclass actually accept
|
||||
* the column data type. This prevents possible coredumps caused by
|
||||
* user errors like applying text_ops to an int4 column. We will accept
|
||||
* an opclass as OK if the operator's input datatype is binary-compatible
|
||||
* with the actual column datatype. Note we assume that all the operators
|
||||
* associated with an opclass accept the same datatypes, so checking the
|
||||
* first one we happened to find in the table is sufficient.
|
||||
* Make sure the operators associated with this opclass actually
|
||||
* accept the column data type. This prevents possible coredumps
|
||||
* caused by user errors like applying text_ops to an int4 column. We
|
||||
* will accept an opclass as OK if the operator's input datatype is
|
||||
* binary-compatible with the actual column datatype. Note we assume
|
||||
* that all the operators associated with an opclass accept the same
|
||||
* datatypes, so checking the first one we happened to find in the
|
||||
* table is sufficient.
|
||||
*
|
||||
* If the opclass was the default for the datatype, assume we can skip
|
||||
* this check --- that saves a few cycles in the most common case.
|
||||
* If pg_opclass is wrong then we're probably screwed anyway...
|
||||
* this check --- that saves a few cycles in the most common case. If
|
||||
* pg_opclass is wrong then we're probably screwed anyway...
|
||||
*/
|
||||
if (doTypeCheck)
|
||||
{
|
||||
@@ -560,11 +562,11 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tuple);
|
||||
Oid opInputType = (optup->oprkind == 'l') ?
|
||||
optup->oprright : optup->oprleft;
|
||||
Oid opInputType = (optup->oprkind == 'l') ?
|
||||
optup->oprright : optup->oprleft;
|
||||
|
||||
if (attrType != opInputType &&
|
||||
! IS_BINARY_COMPATIBLE(attrType, opInputType))
|
||||
!IS_BINARY_COMPATIBLE(attrType, opInputType))
|
||||
elog(ERROR, "DefineIndex: opclass \"%s\" does not accept datatype \"%s\"",
|
||||
attribute->class, typeidTypeName(attrType));
|
||||
ReleaseSysCache(tuple);
|
||||
@@ -660,7 +662,7 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
|
||||
if (IsIgnoringSystemIndexes())
|
||||
overwrite = true;
|
||||
if (!reindex_index(tuple->t_data->t_oid, force, overwrite))
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
#endif /* OLD_FILE_NAMING */
|
||||
elog(NOTICE, "index \"%s\" wasn't reindexed", name);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
@@ -752,18 +754,18 @@ ReindexDatabase(const char *dbname, bool force, bool all)
|
||||
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
|
||||
|
||||
/*
|
||||
* We cannot run inside a user transaction block; if we were
|
||||
* inside a transaction, then our commit- and
|
||||
* start-transaction-command calls would not have the intended effect!
|
||||
* We cannot run inside a user transaction block; if we were inside a
|
||||
* transaction, then our commit- and start-transaction-command calls
|
||||
* would not have the intended effect!
|
||||
*/
|
||||
if (IsTransactionBlock())
|
||||
elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
|
||||
|
||||
/*
|
||||
* Create a memory context that will survive forced transaction commits
|
||||
* we do below. Since it is a child of QueryContext, it will go away
|
||||
* eventually even if we suffer an error; there's no need for special
|
||||
* abort cleanup logic.
|
||||
* Create a memory context that will survive forced transaction
|
||||
* commits we do below. Since it is a child of QueryContext, it will
|
||||
* go away eventually even if we suffer an error; there's no need for
|
||||
* special abort cleanup logic.
|
||||
*/
|
||||
private_context = AllocSetContextCreate(QueryContext,
|
||||
"ReindexDatabase",
|
||||
|
||||
@@ -111,7 +111,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
||||
|
||||
i = 0;
|
||||
values[i++] = PointerGetDatum(languageName);
|
||||
values[i++] = BoolGetDatum(true); /* lanispl */
|
||||
values[i++] = BoolGetDatum(true); /* lanispl */
|
||||
values[i++] = BoolGetDatum(stmt->pltrusted);
|
||||
values[i++] = ObjectIdGetDatum(procTup->t_data->t_oid);
|
||||
values[i++] = DirectFunctionCall1(textin,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.59 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.60 2001/03/22 03:59:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -40,8 +40,8 @@
|
||||
*/
|
||||
void
|
||||
RemoveOperator(char *operatorName, /* operator name */
|
||||
char *typeName1, /* left argument type name */
|
||||
char *typeName2) /* right argument type name */
|
||||
char *typeName1, /* left argument type name */
|
||||
char *typeName2) /* right argument type name */
|
||||
{
|
||||
Relation relation;
|
||||
HeapTuple tup;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.55 2001/01/24 19:42:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.56 2001/03/22 03:59:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -189,15 +189,15 @@ renamerel(const char *oldrelname, const char *newrelname)
|
||||
newrelname);
|
||||
|
||||
/*
|
||||
* Check for renaming a temp table, which only requires altering
|
||||
* the temp-table mapping, not the underlying table.
|
||||
* Check for renaming a temp table, which only requires altering the
|
||||
* temp-table mapping, not the underlying table.
|
||||
*/
|
||||
if (rename_temp_relation(oldrelname, newrelname))
|
||||
return; /* all done... */
|
||||
|
||||
/*
|
||||
* Instead of using heap_openr(), do it the hard way, so that we
|
||||
* can rename indexes as well as regular relations.
|
||||
* Instead of using heap_openr(), do it the hard way, so that we can
|
||||
* rename indexes as well as regular relations.
|
||||
*/
|
||||
targetrelation = RelationNameGetRelation(oldrelname);
|
||||
|
||||
@@ -219,8 +219,9 @@ renamerel(const char *oldrelname, const char *newrelname)
|
||||
heap_close(targetrelation, NoLock);
|
||||
|
||||
/*
|
||||
* Flush the relcache entry (easier than trying to change it at exactly
|
||||
* the right instant). It'll get rebuilt on next access to relation.
|
||||
* Flush the relcache entry (easier than trying to change it at
|
||||
* exactly the right instant). It'll get rebuilt on next access to
|
||||
* relation.
|
||||
*
|
||||
* XXX What if relation is myxactonly?
|
||||
*
|
||||
@@ -244,8 +245,8 @@ renamerel(const char *oldrelname, const char *newrelname)
|
||||
elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
|
||||
|
||||
/*
|
||||
* Update pg_class tuple with new relname. (Scribbling on reltup
|
||||
* is OK because it's a copy...)
|
||||
* Update pg_class tuple with new relname. (Scribbling on reltup is
|
||||
* OK because it's a copy...)
|
||||
*/
|
||||
StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(reltup))->relname),
|
||||
newrelname, NAMEDATALEN);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.51 2001/03/07 21:20:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.52 2001/03/22 03:59:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -33,7 +33,7 @@
|
||||
* so we pre-log a few fetches in advance. In the event of
|
||||
* crash we can lose as much as we pre-logged.
|
||||
*/
|
||||
#define SEQ_LOG_VALS 32
|
||||
#define SEQ_LOG_VALS 32
|
||||
|
||||
typedef struct sequence_magic
|
||||
{
|
||||
@@ -140,7 +140,7 @@ DefineSequence(CreateSeqStmt *seq)
|
||||
case SEQ_COL_LOG:
|
||||
typnam->name = "int4";
|
||||
coldef->colname = "log_cnt";
|
||||
value[i - 1] = Int32GetDatum((int32)1);
|
||||
value[i - 1] = Int32GetDatum((int32) 1);
|
||||
break;
|
||||
case SEQ_COL_CYCLE:
|
||||
typnam->name = "char";
|
||||
@@ -247,7 +247,7 @@ nextval(PG_FUNCTION_ARGS)
|
||||
logit = true;
|
||||
}
|
||||
|
||||
while (fetch) /* try to fetch cache [+ log ] numbers */
|
||||
while (fetch) /* try to fetch cache [+ log ] numbers */
|
||||
{
|
||||
|
||||
/*
|
||||
@@ -292,8 +292,8 @@ nextval(PG_FUNCTION_ARGS)
|
||||
log--;
|
||||
rescnt++;
|
||||
last = next;
|
||||
if (rescnt == 1) /* if it's first result - */
|
||||
result = next; /* it's what to return */
|
||||
if (rescnt == 1) /* if it's first result - */
|
||||
result = next; /* it's what to return */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,12 +306,12 @@ nextval(PG_FUNCTION_ARGS)
|
||||
{
|
||||
xl_seq_rec xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
XLogRecData rdata[2];
|
||||
Page page = BufferGetPage(buf);
|
||||
|
||||
xlrec.node = elm->rel->rd_node;
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = sizeof(xl_seq_rec);
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
@@ -319,17 +319,17 @@ nextval(PG_FUNCTION_ARGS)
|
||||
seq->is_called = 't';
|
||||
seq->log_cnt = 0;
|
||||
rdata[1].buffer = InvalidBuffer;
|
||||
rdata[1].data = (char*)page + ((PageHeader) page)->pd_upper;
|
||||
rdata[1].len = ((PageHeader)page)->pd_special -
|
||||
((PageHeader)page)->pd_upper;
|
||||
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
|
||||
rdata[1].len = ((PageHeader) page)->pd_special -
|
||||
((PageHeader) page)->pd_upper;
|
||||
rdata[1].next = NULL;
|
||||
|
||||
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG|XLOG_NO_TRAN, rdata);
|
||||
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
|
||||
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
|
||||
if (fetch) /* not all numbers were fetched */
|
||||
if (fetch) /* not all numbers were fetched */
|
||||
log -= fetch;
|
||||
}
|
||||
|
||||
@@ -374,15 +374,15 @@ currval(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_INT32(result);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* Main internal procedure that handles 2 & 3 arg forms of SETVAL.
|
||||
*
|
||||
* Note that the 3 arg version (which sets the is_called flag) is
|
||||
* only for use in pg_dump, and setting the is_called flag may not
|
||||
* work if multiple users are attached to the database and referencing
|
||||
* work if multiple users are attached to the database and referencing
|
||||
* the sequence (unlikely if pg_dump is restoring it).
|
||||
*
|
||||
* It is necessary to have the 3 arg version so that pg_dump can
|
||||
* It is necessary to have the 3 arg version so that pg_dump can
|
||||
* restore the state of a sequence exactly during data-only restores -
|
||||
* it is the only way to clear the is_called flag in an existing
|
||||
* sequence.
|
||||
@@ -409,18 +409,19 @@ do_setval(char *seqname, int32 next, bool iscalled)
|
||||
|
||||
/* save info in local cache */
|
||||
elm->last = next; /* last returned number */
|
||||
elm->cached = next; /* last cached number (forget cached values) */
|
||||
elm->cached = next; /* last cached number (forget cached
|
||||
* values) */
|
||||
|
||||
START_CRIT_SECTION();
|
||||
{
|
||||
xl_seq_rec xlrec;
|
||||
XLogRecPtr recptr;
|
||||
XLogRecData rdata[2];
|
||||
XLogRecData rdata[2];
|
||||
Page page = BufferGetPage(buf);
|
||||
|
||||
xlrec.node = elm->rel->rd_node;
|
||||
rdata[0].buffer = InvalidBuffer;
|
||||
rdata[0].data = (char*)&xlrec;
|
||||
rdata[0].data = (char *) &xlrec;
|
||||
rdata[0].len = sizeof(xl_seq_rec);
|
||||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
@@ -428,12 +429,12 @@ do_setval(char *seqname, int32 next, bool iscalled)
|
||||
seq->is_called = 't';
|
||||
seq->log_cnt = 0;
|
||||
rdata[1].buffer = InvalidBuffer;
|
||||
rdata[1].data = (char*)page + ((PageHeader) page)->pd_upper;
|
||||
rdata[1].len = ((PageHeader)page)->pd_special -
|
||||
((PageHeader)page)->pd_upper;
|
||||
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
|
||||
rdata[1].len = ((PageHeader) page)->pd_special -
|
||||
((PageHeader) page)->pd_upper;
|
||||
rdata[1].next = NULL;
|
||||
|
||||
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG|XLOG_NO_TRAN, rdata);
|
||||
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
|
||||
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
@@ -496,7 +497,7 @@ static char *
|
||||
get_seq_name(text *seqin)
|
||||
{
|
||||
char *rawname = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(seqin)));
|
||||
PointerGetDatum(seqin)));
|
||||
int rawlen = strlen(rawname);
|
||||
char *seqname;
|
||||
|
||||
@@ -511,6 +512,7 @@ get_seq_name(text *seqin)
|
||||
else
|
||||
{
|
||||
seqname = rawname;
|
||||
|
||||
/*
|
||||
* It's important that this match the identifier downcasing code
|
||||
* used by backend/parser/scan.l.
|
||||
@@ -752,15 +754,16 @@ get_param(DefElem *def)
|
||||
return -1;
|
||||
}
|
||||
|
||||
void seq_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
seq_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
char *item;
|
||||
Size itemsz;
|
||||
xl_seq_rec *xlrec = (xl_seq_rec*) XLogRecGetData(record);
|
||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||
Relation reln;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
char *item;
|
||||
Size itemsz;
|
||||
xl_seq_rec *xlrec = (xl_seq_rec *) XLogRecGetData(record);
|
||||
sequence_magic *sm;
|
||||
|
||||
if (info != XLOG_SEQ_LOG)
|
||||
@@ -772,8 +775,8 @@ void seq_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
|
||||
buffer = XLogReadBuffer(true, reln, 0);
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(STOP, "seq_redo: can't read block of %u/%u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode);
|
||||
elog(STOP, "seq_redo: can't read block of %u/%u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode);
|
||||
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
@@ -781,10 +784,10 @@ void seq_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
sm = (sequence_magic *) PageGetSpecialPointer(page);
|
||||
sm->magic = SEQ_MAGIC;
|
||||
|
||||
item = (char*)xlrec + sizeof(xl_seq_rec);
|
||||
item = (char *) xlrec + sizeof(xl_seq_rec);
|
||||
itemsz = record->xl_len - sizeof(xl_seq_rec);
|
||||
itemsz = MAXALIGN(itemsz);
|
||||
if (PageAddItem(page, (Item)item, itemsz,
|
||||
if (PageAddItem(page, (Item) item, itemsz,
|
||||
FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
|
||||
elog(STOP, "seq_redo: failed to add item to page");
|
||||
|
||||
@@ -795,14 +798,16 @@ void seq_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
return;
|
||||
}
|
||||
|
||||
void seq_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
void
|
||||
seq_undo(XLogRecPtr lsn, XLogRecord *record)
|
||||
{
|
||||
}
|
||||
|
||||
void seq_desc(char *buf, uint8 xl_info, char* rec)
|
||||
void
|
||||
seq_desc(char *buf, uint8 xl_info, char *rec)
|
||||
{
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
xl_seq_rec *xlrec = (xl_seq_rec*) rec;
|
||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||
xl_seq_rec *xlrec = (xl_seq_rec *) rec;
|
||||
|
||||
if (info == XLOG_SEQ_LOG)
|
||||
strcat(buf, "log: ");
|
||||
@@ -813,5 +818,5 @@ void seq_desc(char *buf, uint8 xl_info, char* rec)
|
||||
}
|
||||
|
||||
sprintf(buf + strlen(buf), "node %u/%u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode);
|
||||
xlrec->node.tblNode, xlrec->node.relNode);
|
||||
}
|
||||
|
||||
@@ -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.88 2001/03/14 21:50:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.89 2001/03/22 03:59:23 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,8 +36,8 @@ static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger);
|
||||
static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid,
|
||||
TupleTableSlot **newSlot);
|
||||
static HeapTuple ExecCallTriggerFunc(Trigger *trigger,
|
||||
TriggerData *trigdata,
|
||||
MemoryContext per_tuple_context);
|
||||
TriggerData *trigdata,
|
||||
MemoryContext per_tuple_context);
|
||||
static void DeferredTriggerSaveEvent(Relation rel, int event,
|
||||
HeapTuple oldtup, HeapTuple newtup);
|
||||
|
||||
@@ -87,7 +87,9 @@ CreateTrigger(CreateTrigStmt *stmt)
|
||||
constrrelid = InvalidOid;
|
||||
else
|
||||
{
|
||||
/* NoLock is probably sufficient here, since we're only
|
||||
|
||||
/*
|
||||
* NoLock is probably sufficient here, since we're only
|
||||
* interested in getting the relation's OID...
|
||||
*/
|
||||
rel = heap_openr(stmt->constrrelname, NoLock);
|
||||
@@ -192,7 +194,7 @@ CreateTrigger(CreateTrigStmt *stmt)
|
||||
|
||||
values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(RelationGetRelid(rel));
|
||||
values[Anum_pg_trigger_tgname - 1] = DirectFunctionCall1(namein,
|
||||
CStringGetDatum(stmt->trigname));
|
||||
CStringGetDatum(stmt->trigname));
|
||||
values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(funcoid);
|
||||
values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
|
||||
values[Anum_pg_trigger_tgenabled - 1] = BoolGetDatum(true);
|
||||
@@ -211,7 +213,7 @@ CreateTrigger(CreateTrigStmt *stmt)
|
||||
|
||||
foreach(le, stmt->args)
|
||||
{
|
||||
char *ar = ((Value*) lfirst(le))->val.str;
|
||||
char *ar = ((Value *) lfirst(le))->val.str;
|
||||
|
||||
len += strlen(ar) + 4;
|
||||
for (; *ar; ar++)
|
||||
@@ -224,7 +226,7 @@ CreateTrigger(CreateTrigStmt *stmt)
|
||||
args[0] = '\0';
|
||||
foreach(le, stmt->args)
|
||||
{
|
||||
char *s = ((Value*) lfirst(le))->val.str;
|
||||
char *s = ((Value *) lfirst(le))->val.str;
|
||||
char *d = args + strlen(args);
|
||||
|
||||
while (*s)
|
||||
@@ -237,7 +239,7 @@ CreateTrigger(CreateTrigStmt *stmt)
|
||||
}
|
||||
values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
|
||||
values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain,
|
||||
CStringGetDatum(args));
|
||||
CStringGetDatum(args));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -569,15 +571,16 @@ RelationBuildTriggers(Relation relation)
|
||||
sizeof(Trigger));
|
||||
else
|
||||
triggers = (Trigger *) repalloc(triggers,
|
||||
(found + 1) * sizeof(Trigger));
|
||||
(found + 1) * sizeof(Trigger));
|
||||
build = &(triggers[found]);
|
||||
|
||||
build->tgoid = htup->t_data->t_oid;
|
||||
build->tgname = MemoryContextStrdup(CacheMemoryContext,
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&pg_trigger->tgname))));
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&pg_trigger->tgname))));
|
||||
build->tgfoid = pg_trigger->tgfoid;
|
||||
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as uninitialized */
|
||||
build->tgfunc.fn_oid = InvalidOid; /* mark FmgrInfo as
|
||||
* uninitialized */
|
||||
build->tgtype = pg_trigger->tgtype;
|
||||
build->tgenabled = pg_trigger->tgenabled;
|
||||
build->tgisconstraint = pg_trigger->tgisconstraint;
|
||||
@@ -836,22 +839,22 @@ ExecCallTriggerFunc(Trigger *trigger,
|
||||
TriggerData *trigdata,
|
||||
MemoryContext per_tuple_context)
|
||||
{
|
||||
FunctionCallInfoData fcinfo;
|
||||
Datum result;
|
||||
MemoryContext oldContext;
|
||||
FunctionCallInfoData fcinfo;
|
||||
Datum result;
|
||||
MemoryContext oldContext;
|
||||
|
||||
/*
|
||||
* Fmgr lookup info is cached in the Trigger structure,
|
||||
* so that we need not repeat the lookup on every call.
|
||||
* Fmgr lookup info is cached in the Trigger structure, so that we
|
||||
* need not repeat the lookup on every call.
|
||||
*/
|
||||
if (trigger->tgfunc.fn_oid == InvalidOid)
|
||||
fmgr_info(trigger->tgfoid, &trigger->tgfunc);
|
||||
|
||||
/*
|
||||
* Do the function evaluation in the per-tuple memory context,
|
||||
* so that leaked memory will be reclaimed once per tuple.
|
||||
* Note in particular that any new tuple created by the trigger function
|
||||
* will live till the end of the tuple cycle.
|
||||
* Do the function evaluation in the per-tuple memory context, so that
|
||||
* leaked memory will be reclaimed once per tuple. Note in particular
|
||||
* that any new tuple created by the trigger function will live till
|
||||
* the end of the tuple cycle.
|
||||
*/
|
||||
oldContext = MemoryContextSwitchTo(per_tuple_context);
|
||||
|
||||
@@ -868,8 +871,8 @@ ExecCallTriggerFunc(Trigger *trigger,
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
|
||||
/*
|
||||
* Trigger protocol allows function to return a null pointer,
|
||||
* but NOT to set the isnull result flag.
|
||||
* Trigger protocol allows function to return a null pointer, but NOT
|
||||
* to set the isnull result flag.
|
||||
*/
|
||||
if (fcinfo.isnull)
|
||||
elog(ERROR, "ExecCallTriggerFunc: function %u returned NULL",
|
||||
@@ -885,7 +888,7 @@ ExecBRInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
|
||||
Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
|
||||
HeapTuple newtuple = trigtuple;
|
||||
HeapTuple oldtuple;
|
||||
TriggerData LocTriggerData;
|
||||
TriggerData LocTriggerData;
|
||||
int i;
|
||||
|
||||
LocTriggerData.type = T_TriggerData;
|
||||
@@ -915,9 +918,7 @@ ExecARInsertTriggers(EState *estate, Relation rel, HeapTuple trigtuple)
|
||||
if (rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 ||
|
||||
rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0 ||
|
||||
rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0)
|
||||
{
|
||||
DeferredTriggerSaveEvent(rel, TRIGGER_EVENT_INSERT, NULL, trigtuple);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -1240,10 +1241,11 @@ 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 "lappend".
|
||||
* This avoids O(N^2) behavior for large numbers of events.
|
||||
* list tail and append there, rather than just doing a stupid
|
||||
* "lappend". This avoids O(N^2) behavior for large numbers of events.
|
||||
*/
|
||||
event->dte_next = NULL;
|
||||
if (deftrig_event_tail == NULL)
|
||||
@@ -1291,7 +1293,7 @@ deferredTriggerGetPreviousEvent(Oid relid, ItemPointer ctid)
|
||||
|
||||
if (previous == NULL)
|
||||
elog(ERROR,
|
||||
"deferredTriggerGetPreviousEvent: event for tuple %s not found",
|
||||
"deferredTriggerGetPreviousEvent: event for tuple %s not found",
|
||||
DatumGetCString(DirectFunctionCall1(tidout,
|
||||
PointerGetDatum(ctid))));
|
||||
return previous;
|
||||
@@ -1528,7 +1530,7 @@ DeferredTriggerBeginXact(void)
|
||||
|
||||
if (deftrig_cxt != NULL)
|
||||
elog(ERROR,
|
||||
"DeferredTriggerBeginXact() called while inside transaction");
|
||||
"DeferredTriggerBeginXact() called while inside transaction");
|
||||
|
||||
/* ----------
|
||||
* Create the per transaction memory context and copy all states
|
||||
@@ -1671,7 +1673,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
||||
l = deftrig_dfl_trigstates;
|
||||
while (l != NIL)
|
||||
{
|
||||
List *next = lnext(l);
|
||||
List *next = lnext(l);
|
||||
|
||||
pfree(lfirst(l));
|
||||
pfree(l);
|
||||
@@ -1700,7 +1702,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
||||
l = deftrig_trigstates;
|
||||
while (l != NIL)
|
||||
{
|
||||
List *next = lnext(l);
|
||||
List *next = lnext(l);
|
||||
|
||||
pfree(lfirst(l));
|
||||
pfree(l);
|
||||
@@ -1912,7 +1914,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
|
||||
* Called by ExecAR...Triggers() to add the event to the queue.
|
||||
*
|
||||
* NOTE: should be called only if we've determined that an event must
|
||||
* be added to the queue. We must save *all* events if there is either
|
||||
* be added to the queue. We must save *all* events if there is either
|
||||
* an UPDATE or a DELETE deferred trigger; see uses of
|
||||
* deferredTriggerGetPreviousEvent.
|
||||
* ----------
|
||||
@@ -2099,15 +2101,15 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
||||
TRIGGER_DEFERRED_ROW_INSERTED)
|
||||
elog(ERROR, "triggered data change violation "
|
||||
"on relation \"%s\"",
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||
|
||||
if (prev_event->dte_item[i].dti_state &
|
||||
TRIGGER_DEFERRED_KEY_CHANGED)
|
||||
elog(ERROR, "triggered data change violation "
|
||||
"on relation \"%s\"",
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||
}
|
||||
|
||||
/* ----------
|
||||
@@ -2142,7 +2144,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
|
||||
elog(ERROR, "triggered data change violation "
|
||||
"on relation \"%s\"",
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||
NameGetDatum(&(rel->rd_rel->relname)))));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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.73 2001/01/24 19:42:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.74 2001/03/22 03:59:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -122,7 +122,7 @@ write_password_file(Relation rel)
|
||||
CRYPT_PWD_FILE_SEPSTR
|
||||
"%s\n",
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(DatumGetName(datum_n)))),
|
||||
NameGetDatum(DatumGetName(datum_n)))),
|
||||
null_p ? "" :
|
||||
DatumGetCString(DirectFunctionCall1(textout, datum_p)),
|
||||
null_v ? "\\N" :
|
||||
@@ -248,7 +248,7 @@ CreateUser(CreateUserStmt *stmt)
|
||||
* Build a tuple to insert
|
||||
*/
|
||||
new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein,
|
||||
CStringGetDatum(stmt->user));
|
||||
CStringGetDatum(stmt->user));
|
||||
new_record[Anum_pg_shadow_usesysid - 1] = Int32GetDatum(havesysid ? stmt->sysid : max_id + 1);
|
||||
|
||||
AssertState(BoolIsValid(stmt->createdb));
|
||||
@@ -312,7 +312,7 @@ CreateUser(CreateUserStmt *stmt)
|
||||
* this in */
|
||||
ags.action = +1;
|
||||
ags.listUsers = makeList1(makeInteger(havesysid ?
|
||||
stmt->sysid : max_id + 1));
|
||||
stmt->sysid : max_id + 1));
|
||||
AlterGroup(&ags, "CREATE USER");
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ AlterUser(AlterUserStmt *stmt)
|
||||
* Build a tuple to update, perusing the information just obtained
|
||||
*/
|
||||
new_record[Anum_pg_shadow_usename - 1] = DirectFunctionCall1(namein,
|
||||
CStringGetDatum(stmt->user));
|
||||
CStringGetDatum(stmt->user));
|
||||
new_record_nulls[Anum_pg_shadow_usename - 1] = ' ';
|
||||
|
||||
/* sysid - leave as is */
|
||||
@@ -561,7 +561,7 @@ DropUser(DropUserStmt *stmt)
|
||||
elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s",
|
||||
user,
|
||||
DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(DatumGetName(datum)))),
|
||||
NameGetDatum(DatumGetName(datum)))),
|
||||
(length(stmt->users) > 1) ? " (no users removed)" : ""
|
||||
);
|
||||
}
|
||||
@@ -603,6 +603,7 @@ DropUser(DropUserStmt *stmt)
|
||||
}
|
||||
heap_endscan(scan);
|
||||
heap_close(pg_rel, AccessExclusiveLock);
|
||||
|
||||
/*
|
||||
* Advance command counter so that later iterations of this loop
|
||||
* will see the changes already made. This is essential if, for
|
||||
@@ -873,7 +874,7 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
|
||||
{
|
||||
/* Get the uid of the proposed user to add. */
|
||||
tuple = SearchSysCache(SHADOWNAME,
|
||||
PointerGetDatum(strVal(lfirst(item))),
|
||||
PointerGetDatum(strVal(lfirst(item))),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "%s: user \"%s\" does not exist",
|
||||
@@ -995,7 +996,7 @@ AlterGroup(AlterGroupStmt *stmt, const char *tag)
|
||||
{
|
||||
/* Get the uid of the proposed user to drop. */
|
||||
tuple = SearchSysCache(SHADOWNAME,
|
||||
PointerGetDatum(strVal(lfirst(item))),
|
||||
PointerGetDatum(strVal(lfirst(item))),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "ALTER GROUP: user \"%s\" does not exist", strVal(lfirst(item)));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.187 2001/03/14 08:40:57 inoue Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.188 2001/03/22 03:59:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -47,11 +47,11 @@
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/temprel.h"
|
||||
|
||||
extern XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
|
||||
char *unused, int unlen);
|
||||
extern XLogRecPtr log_heap_move(Relation reln,
|
||||
Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup);
|
||||
extern XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
|
||||
char *unused, int unlen);
|
||||
extern XLogRecPtr log_heap_move(Relation reln,
|
||||
Buffer oldbuf, ItemPointerData from,
|
||||
Buffer newbuf, HeapTuple newtup);
|
||||
|
||||
static MemoryContext vac_context = NULL;
|
||||
|
||||
@@ -78,9 +78,9 @@ static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
|
||||
static void get_indices(Relation relation, int *nindices, Relation **Irel);
|
||||
static void close_indices(int nindices, Relation *Irel);
|
||||
static IndexInfo **get_index_desc(Relation onerel, int nindices,
|
||||
Relation *Irel);
|
||||
Relation *Irel);
|
||||
static void *vac_find_eq(void *bot, int nelem, int size, void *elm,
|
||||
int (*compar) (const void *, const void *));
|
||||
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);
|
||||
@@ -120,9 +120,9 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
|
||||
/*
|
||||
* Create special memory context for cross-transaction storage.
|
||||
*
|
||||
* Since it is a child of QueryContext, it will go away eventually
|
||||
* even if we suffer an error; there's no need for special abort
|
||||
* cleanup logic.
|
||||
* Since it is a child of QueryContext, it will go away eventually even
|
||||
* if we suffer an error; there's no need for special abort cleanup
|
||||
* logic.
|
||||
*/
|
||||
vac_context = AllocSetContextCreate(QueryContext,
|
||||
"Vacuum",
|
||||
@@ -215,8 +215,8 @@ vacuum_shutdown()
|
||||
|
||||
/*
|
||||
* Clean up working storage --- note we must do this after
|
||||
* StartTransactionCommand, else we might be trying to delete
|
||||
* the active context!
|
||||
* StartTransactionCommand, else we might be trying to delete the
|
||||
* active context!
|
||||
*/
|
||||
MemoryContextDelete(vac_context);
|
||||
vac_context = NULL;
|
||||
@@ -360,10 +360,10 @@ vacuum_rel(Oid relid)
|
||||
{
|
||||
Relation onerel;
|
||||
LockRelId onerelid;
|
||||
VacPageListData vacuum_pages; /* List of pages to vacuum and/or clean
|
||||
* indices */
|
||||
VacPageListData fraged_pages; /* List of pages with space enough for
|
||||
* re-using */
|
||||
VacPageListData vacuum_pages; /* List of pages to vacuum and/or
|
||||
* clean indices */
|
||||
VacPageListData fraged_pages; /* List of pages with space enough
|
||||
* for re-using */
|
||||
Relation *Irel;
|
||||
int32 nindices,
|
||||
i;
|
||||
@@ -411,10 +411,10 @@ vacuum_rel(Oid relid)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a session-level exclusive lock too. This will protect our
|
||||
* exclusive access to the relation across multiple transactions,
|
||||
* so that we can vacuum the relation's TOAST table (if any) secure
|
||||
* in the knowledge that no one is diddling the parent relation.
|
||||
* Get a session-level exclusive lock too. This will protect our
|
||||
* exclusive access to the relation across multiple transactions, so
|
||||
* that we can vacuum the relation's TOAST table (if any) secure in
|
||||
* the knowledge that no one is diddling the parent relation.
|
||||
*
|
||||
* NOTE: this cannot block, even if someone else is waiting for access,
|
||||
* because the lock manager knows that both lock requests are from the
|
||||
@@ -458,10 +458,11 @@ vacuum_rel(Oid relid)
|
||||
vacrelstats->hasindex = true;
|
||||
else
|
||||
vacrelstats->hasindex = false;
|
||||
#ifdef NOT_USED
|
||||
#ifdef NOT_USED
|
||||
|
||||
/*
|
||||
* reindex in VACUUM is dangerous under WAL.
|
||||
* ifdef out until it becomes safe.
|
||||
* reindex in VACUUM is dangerous under WAL. ifdef out until it
|
||||
* becomes safe.
|
||||
*/
|
||||
if (reindex)
|
||||
{
|
||||
@@ -470,7 +471,7 @@ vacuum_rel(Oid relid)
|
||||
Irel = (Relation *) NULL;
|
||||
activate_indexes_of_a_table(relid, false);
|
||||
}
|
||||
#endif /* NOT_USED */
|
||||
#endif /* NOT_USED */
|
||||
|
||||
/* Clean/scan index relation(s) */
|
||||
if (Irel != (Relation *) NULL)
|
||||
@@ -506,6 +507,7 @@ vacuum_rel(Oid relid)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Flush dirty pages out to disk. We must do this even if we
|
||||
* didn't do anything else, because we want to ensure that all
|
||||
@@ -518,10 +520,10 @@ vacuum_rel(Oid relid)
|
||||
i);
|
||||
}
|
||||
}
|
||||
#ifdef NOT_USED
|
||||
#ifdef NOT_USED
|
||||
if (reindex)
|
||||
activate_indexes_of_a_table(relid, true);
|
||||
#endif /* NOT_USED */
|
||||
#endif /* NOT_USED */
|
||||
|
||||
/* all done with this class, but hold lock until commit */
|
||||
heap_close(onerel, NoLock);
|
||||
@@ -537,11 +539,11 @@ vacuum_rel(Oid relid)
|
||||
CommitTransactionCommand();
|
||||
|
||||
/*
|
||||
* If the relation has a secondary toast one, vacuum that too
|
||||
* while we still hold the session lock on the master table.
|
||||
* We don't need to propagate "analyze" to it, because the toaster
|
||||
* always uses hardcoded index access and statistics are
|
||||
* totally unimportant for toast relations
|
||||
* If the relation has a secondary toast one, vacuum that too while we
|
||||
* still hold the session lock on the master table. We don't need to
|
||||
* propagate "analyze" to it, because the toaster always uses
|
||||
* hardcoded index access and statistics are totally unimportant for
|
||||
* toast relations
|
||||
*/
|
||||
if (toast_relid != InvalidOid)
|
||||
vacuum_rel(toast_relid);
|
||||
@@ -563,7 +565,7 @@ vacuum_rel(Oid relid)
|
||||
*/
|
||||
static void
|
||||
scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages)
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages)
|
||||
{
|
||||
BlockNumber nblocks,
|
||||
blkno;
|
||||
@@ -845,7 +847,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
|
||||
* dead tuples removed. Below we will apply
|
||||
* PageRepairFragmentation to the copy, so that we can
|
||||
* determine how much space will be available after
|
||||
* removal of dead tuples. But note we are NOT changing
|
||||
* removal of dead tuples. But note we are NOT changing
|
||||
* the real page yet...
|
||||
*/
|
||||
if (tempPage == (Page) NULL)
|
||||
@@ -964,8 +966,8 @@ Re-using: Free/Avail. Space %lu/%lu; EndEmpty/Avail. Pages %u/%u. %s",
|
||||
nblocks, changed_pages, vacuum_pages->num_pages, empty_pages,
|
||||
new_pages, num_tuples, tups_vacuumed,
|
||||
nkeep, vacrelstats->num_vtlinks, ncrash,
|
||||
nunused, (unsigned long)min_tlen, (unsigned long)max_tlen,
|
||||
(unsigned long)free_size, (unsigned long)usable_free_size,
|
||||
nunused, (unsigned long) min_tlen, (unsigned long) max_tlen,
|
||||
(unsigned long) free_size, (unsigned long) usable_free_size,
|
||||
empty_end_pages, fraged_pages->num_pages,
|
||||
show_rusage(&ru0));
|
||||
|
||||
@@ -984,8 +986,8 @@ Re-using: Free/Avail. Space %lu/%lu; EndEmpty/Avail. Pages %u/%u. %s",
|
||||
*/
|
||||
static void
|
||||
repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages,
|
||||
int nindices, Relation *Irel)
|
||||
VacPageList vacuum_pages, VacPageList fraged_pages,
|
||||
int nindices, Relation *Irel)
|
||||
{
|
||||
TransactionId myXID;
|
||||
CommandId myCID;
|
||||
@@ -1077,7 +1079,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
dowrite = false;
|
||||
if (blkno == last_vacuum_block) /* it's reaped page */
|
||||
{
|
||||
if (last_vacuum_page->offsets_free > 0) /* there are dead tuples */
|
||||
if (last_vacuum_page->offsets_free > 0) /* there are dead tuples */
|
||||
{ /* on this page - clean */
|
||||
Assert(!isempty);
|
||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||
@@ -1100,7 +1102,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
last_vacuum_block = -1;
|
||||
}
|
||||
if (num_fraged_pages > 0 &&
|
||||
fraged_pages->pagedesc[num_fraged_pages - 1]->blkno ==
|
||||
fraged_pages->pagedesc[num_fraged_pages - 1]->blkno ==
|
||||
(BlockNumber) blkno)
|
||||
{
|
||||
/* page is in fraged_pages too; remove it */
|
||||
@@ -1142,8 +1144,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
/*
|
||||
* If this (chain) tuple is moved by me already then I
|
||||
* have to check is it in vacpage or not - i.e. is it moved
|
||||
* while cleaning this page or some previous one.
|
||||
* have to check is it in vacpage or not - i.e. is it
|
||||
* moved while cleaning this page or some previous one.
|
||||
*/
|
||||
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
|
||||
{
|
||||
@@ -1232,8 +1234,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
* xaction and this tuple is already deleted by
|
||||
* me. Actually, upper part of chain should be
|
||||
* removed and seems that this should be handled
|
||||
* in scan_heap(), but it's not implemented at
|
||||
* the moment and so we just stop shrinking here.
|
||||
* in scan_heap(), but it's not implemented at the
|
||||
* moment and so we just stop shrinking here.
|
||||
*/
|
||||
ReleaseBuffer(Cbuf);
|
||||
pfree(vtmove);
|
||||
@@ -1256,15 +1258,15 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
{
|
||||
|
||||
/*
|
||||
* if to_vacpage no longer has enough free space to be
|
||||
* useful, remove it from fraged_pages list
|
||||
* if to_vacpage no longer has enough free space
|
||||
* to be useful, remove it from fraged_pages list
|
||||
*/
|
||||
if (to_vacpage != NULL &&
|
||||
!enough_space(to_vacpage, vacrelstats->min_tlen))
|
||||
!enough_space(to_vacpage, vacrelstats->min_tlen))
|
||||
{
|
||||
Assert(num_fraged_pages > to_item);
|
||||
memmove(fraged_pages->pagedesc + to_item,
|
||||
fraged_pages->pagedesc + to_item + 1,
|
||||
fraged_pages->pagedesc + to_item + 1,
|
||||
sizeof(VacPage) * (num_fraged_pages - to_item - 1));
|
||||
num_fraged_pages--;
|
||||
}
|
||||
@@ -1326,10 +1328,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
vtld.new_tid = tp.t_self;
|
||||
vtlp = (VTupleLink)
|
||||
vac_find_eq((void *) (vacrelstats->vtlinks),
|
||||
vacrelstats->num_vtlinks,
|
||||
sizeof(VTupleLinkData),
|
||||
(void *) &vtld,
|
||||
vac_cmp_vtlinks);
|
||||
vacrelstats->num_vtlinks,
|
||||
sizeof(VTupleLinkData),
|
||||
(void *) &vtld,
|
||||
vac_cmp_vtlinks);
|
||||
if (vtlp == NULL)
|
||||
elog(ERROR, "Parent tuple was not found");
|
||||
tp.t_self = vtlp->this_tid;
|
||||
@@ -1416,7 +1418,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
ItemPointerSetInvalid(&Ctid);
|
||||
for (ti = 0; ti < num_vtmove; ti++)
|
||||
{
|
||||
VacPage destvacpage = vtmove[ti].vacpage;
|
||||
VacPage destvacpage = vtmove[ti].vacpage;
|
||||
|
||||
/* Get page to move from */
|
||||
tuple.t_self = vtmove[ti].tid;
|
||||
@@ -1460,21 +1462,22 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
*
|
||||
* NOTE: a nasty bug used to lurk here. It is possible
|
||||
* for the source and destination pages to be the same
|
||||
* (since this tuple-chain member can be on a page lower
|
||||
* than the one we're currently processing in the outer
|
||||
* loop). If that's true, then after vacuum_page() the
|
||||
* source tuple will have been moved, and tuple.t_data
|
||||
* will be pointing at garbage. Therefore we must do
|
||||
* everything that uses tuple.t_data BEFORE this step!!
|
||||
* (since this tuple-chain member can be on a page
|
||||
* lower than the one we're currently processing in
|
||||
* the outer loop). If that's true, then after
|
||||
* vacuum_page() the source tuple will have been
|
||||
* moved, and tuple.t_data will be pointing at
|
||||
* garbage. Therefore we must do everything that uses
|
||||
* tuple.t_data BEFORE this step!!
|
||||
*
|
||||
* This path is different from the other callers of
|
||||
* vacuum_page, because we have already incremented the
|
||||
* vacpage's offsets_used field to account for the
|
||||
* vacuum_page, because we have already incremented
|
||||
* the vacpage's offsets_used field to account for the
|
||||
* tuple(s) we expect to move onto the page. Therefore
|
||||
* vacuum_page's check for offsets_used == 0 is
|
||||
* wrong. But since that's a good debugging check for
|
||||
* all other callers, we work around it here rather
|
||||
* than remove it.
|
||||
* vacuum_page's check for offsets_used == 0 is wrong.
|
||||
* But since that's a good debugging check for all
|
||||
* other callers, we work around it here rather than
|
||||
* remove it.
|
||||
*/
|
||||
if (!PageIsEmpty(ToPage) && vtmove[ti].cleanVpd)
|
||||
{
|
||||
@@ -1498,7 +1501,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
if (newoff == InvalidOffsetNumber)
|
||||
{
|
||||
elog(STOP, "moving chain: failed to add item with len = %lu to page %u",
|
||||
(unsigned long)tuple_len, destvacpage->blkno);
|
||||
(unsigned long) tuple_len, destvacpage->blkno);
|
||||
}
|
||||
newitemid = PageGetItemId(ToPage, newoff);
|
||||
pfree(newtup.t_data);
|
||||
@@ -1507,9 +1510,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
ItemPointerSet(&(newtup.t_self), destvacpage->blkno, newoff);
|
||||
|
||||
{
|
||||
XLogRecPtr recptr =
|
||||
log_heap_move(onerel, Cbuf, tuple.t_self,
|
||||
cur_buffer, &newtup);
|
||||
XLogRecPtr recptr =
|
||||
log_heap_move(onerel, Cbuf, tuple.t_self,
|
||||
cur_buffer, &newtup);
|
||||
|
||||
if (Cbuf != cur_buffer)
|
||||
{
|
||||
@@ -1526,7 +1529,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
/*
|
||||
* Set new tuple's t_ctid pointing to itself for last
|
||||
* tuple in chain, and to next tuple in chain otherwise.
|
||||
* tuple in chain, and to next tuple in chain
|
||||
* otherwise.
|
||||
*/
|
||||
if (!ItemPointerIsValid(&Ctid))
|
||||
newtup.t_data->t_ctid = newtup.t_self;
|
||||
@@ -1552,13 +1556,15 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
|
||||
if (Irel != (Relation *) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX using CurrentMemoryContext here means
|
||||
* intra-vacuum memory leak for functional indexes.
|
||||
* Should fix someday.
|
||||
* intra-vacuum memory leak for functional
|
||||
* indexes. Should fix someday.
|
||||
*
|
||||
* XXX This code fails to handle partial indexes!
|
||||
* Probably should change it to use ExecOpenIndices.
|
||||
* Probably should change it to use
|
||||
* ExecOpenIndices.
|
||||
*/
|
||||
for (i = 0; i < nindices; i++)
|
||||
{
|
||||
@@ -1653,8 +1659,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
||||
{
|
||||
elog(STOP, "\
|
||||
failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)",
|
||||
(unsigned long)tuple_len, cur_page->blkno, (unsigned long)cur_page->free,
|
||||
cur_page->offsets_used, cur_page->offsets_free);
|
||||
(unsigned long) tuple_len, cur_page->blkno, (unsigned long) cur_page->free,
|
||||
cur_page->offsets_used, cur_page->offsets_free);
|
||||
}
|
||||
newitemid = PageGetItemId(ToPage, newoff);
|
||||
pfree(newtup.t_data);
|
||||
@@ -1673,9 +1679,9 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
|
||||
|
||||
{
|
||||
XLogRecPtr recptr =
|
||||
log_heap_move(onerel, buf, tuple.t_self,
|
||||
cur_buffer, &newtup);
|
||||
XLogRecPtr recptr =
|
||||
log_heap_move(onerel, buf, tuple.t_self,
|
||||
cur_buffer, &newtup);
|
||||
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
@@ -1698,13 +1704,13 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
/* insert index' tuples if needed */
|
||||
if (Irel != (Relation *) NULL)
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX using CurrentMemoryContext here means
|
||||
* intra-vacuum memory leak for functional indexes.
|
||||
* Should fix someday.
|
||||
* XXX using CurrentMemoryContext here means intra-vacuum
|
||||
* memory leak for functional indexes. Should fix someday.
|
||||
*
|
||||
* XXX This code fails to handle partial indexes!
|
||||
* Probably should change it to use ExecOpenIndices.
|
||||
* XXX This code fails to handle partial indexes! Probably
|
||||
* should change it to use ExecOpenIndices.
|
||||
*/
|
||||
for (i = 0; i < nindices; i++)
|
||||
{
|
||||
@@ -1803,14 +1809,15 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
|
||||
if (num_moved > 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* We have to commit our tuple movings before we truncate the
|
||||
* relation. Ideally we should do Commit/StartTransactionCommand
|
||||
* here, relying on the session-level table lock to protect our
|
||||
* exclusive access to the relation. However, that would require
|
||||
* a lot of extra code to close and re-open the relation, indices,
|
||||
* etc. For now, a quick hack: record status of current transaction
|
||||
* as committed, and continue.
|
||||
* etc. For now, a quick hack: record status of current
|
||||
* transaction as committed, and continue.
|
||||
*/
|
||||
RecordTransactionCommit();
|
||||
}
|
||||
@@ -1873,7 +1880,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
nblocks, blkno, num_moved,
|
||||
show_rusage(&ru0));
|
||||
|
||||
/*
|
||||
/*
|
||||
* Reflect the motion of system tuples to catalog cache here.
|
||||
*/
|
||||
CommandCounterIncrement();
|
||||
@@ -1883,13 +1890,13 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
/* vacuum indices again if needed */
|
||||
if (Irel != (Relation *) NULL)
|
||||
{
|
||||
VacPage *vpleft,
|
||||
VacPage *vpleft,
|
||||
*vpright,
|
||||
vpsave;
|
||||
|
||||
/* re-sort Nvacpagelist.pagedesc */
|
||||
for (vpleft = Nvacpagelist.pagedesc,
|
||||
vpright = Nvacpagelist.pagedesc + Nvacpagelist.num_pages - 1;
|
||||
vpright = Nvacpagelist.pagedesc + Nvacpagelist.num_pages - 1;
|
||||
vpleft < vpright; vpleft++, vpright--)
|
||||
{
|
||||
vpsave = *vpleft;
|
||||
@@ -1906,9 +1913,9 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
if (vacpage->blkno == (BlockNumber) (blkno - 1) &&
|
||||
vacpage->offsets_free > 0)
|
||||
{
|
||||
char unbuf[BLCKSZ];
|
||||
OffsetNumber *unused = (OffsetNumber*)unbuf;
|
||||
int uncnt;
|
||||
char unbuf[BLCKSZ];
|
||||
OffsetNumber *unused = (OffsetNumber *) unbuf;
|
||||
int uncnt;
|
||||
|
||||
buf = ReadBuffer(onerel, vacpage->blkno);
|
||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||
@@ -1943,8 +1950,9 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
uncnt = PageRepairFragmentation(page, unused);
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
recptr = log_heap_clean(onerel, buf, (char*)unused,
|
||||
(char*)(&(unused[uncnt])) - (char*)unused);
|
||||
|
||||
recptr = log_heap_clean(onerel, buf, (char *) unused,
|
||||
(char *) (&(unused[uncnt])) - (char *) unused);
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
}
|
||||
@@ -1962,9 +1970,9 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)"
|
||||
|
||||
/*
|
||||
* Flush dirty pages out to disk. We do this unconditionally, even if
|
||||
* we don't need to truncate, because we want to ensure that all tuples
|
||||
* have correct on-row commit status on disk (see bufmgr.c's comments
|
||||
* for FlushRelationBuffers()).
|
||||
* we don't need to truncate, because we want to ensure that all
|
||||
* tuples have correct on-row commit status on disk (see bufmgr.c's
|
||||
* comments for FlushRelationBuffers()).
|
||||
*/
|
||||
i = FlushRelationBuffers(onerel, blkno);
|
||||
if (i < 0)
|
||||
@@ -2005,8 +2013,7 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
int i;
|
||||
|
||||
nblocks = vacuum_pages->num_pages;
|
||||
nblocks -= vacuum_pages->empty_end_pages; /* nothing to do with
|
||||
* them */
|
||||
nblocks -= vacuum_pages->empty_end_pages; /* nothing to do with them */
|
||||
|
||||
for (i = 0, vacpage = vacuum_pages->pagedesc; i < nblocks; i++, vacpage++)
|
||||
{
|
||||
@@ -2022,9 +2029,9 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
|
||||
/*
|
||||
* Flush dirty pages out to disk. We do this unconditionally, even if
|
||||
* we don't need to truncate, because we want to ensure that all tuples
|
||||
* have correct on-row commit status on disk (see bufmgr.c's comments
|
||||
* for FlushRelationBuffers()).
|
||||
* we don't need to truncate, because we want to ensure that all
|
||||
* tuples have correct on-row commit status on disk (see bufmgr.c's
|
||||
* comments for FlushRelationBuffers()).
|
||||
*/
|
||||
Assert(vacrelstats->num_pages >= vacuum_pages->empty_end_pages);
|
||||
nblocks = vacrelstats->num_pages - vacuum_pages->empty_end_pages;
|
||||
@@ -2042,7 +2049,8 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
vacrelstats->num_pages, nblocks);
|
||||
nblocks = smgrtruncate(DEFAULT_SMGR, onerel, nblocks);
|
||||
Assert(nblocks >= 0);
|
||||
vacrelstats->num_pages = nblocks; /* set new number of blocks */
|
||||
vacrelstats->num_pages = nblocks; /* set new number of
|
||||
* blocks */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2053,12 +2061,12 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
||||
static void
|
||||
vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
|
||||
{
|
||||
char unbuf[BLCKSZ];
|
||||
OffsetNumber *unused = (OffsetNumber*)unbuf;
|
||||
int uncnt;
|
||||
Page page = BufferGetPage(buffer);
|
||||
ItemId itemid;
|
||||
int i;
|
||||
char unbuf[BLCKSZ];
|
||||
OffsetNumber *unused = (OffsetNumber *) unbuf;
|
||||
int uncnt;
|
||||
Page page = BufferGetPage(buffer);
|
||||
ItemId itemid;
|
||||
int i;
|
||||
|
||||
/* There shouldn't be any tuples moved onto the page yet! */
|
||||
Assert(vacpage->offsets_used == 0);
|
||||
@@ -2072,8 +2080,9 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage)
|
||||
uncnt = PageRepairFragmentation(page, unused);
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
recptr = log_heap_clean(onerel, buffer, (char*)unused,
|
||||
(char*)(&(unused[uncnt])) - (char*)unused);
|
||||
|
||||
recptr = log_heap_clean(onerel, buffer, (char *) unused,
|
||||
(char *) (&(unused[uncnt])) - (char *) unused);
|
||||
PageSetLSN(page, recptr);
|
||||
PageSetSUI(page, ThisStartUpID);
|
||||
}
|
||||
@@ -2220,8 +2229,8 @@ tid_reaped(ItemPointer itemptr, VacPageList vacpagelist)
|
||||
|
||||
vp = &vacpage;
|
||||
vpp = (VacPage *) vac_find_eq((void *) (vacpagelist->pagedesc),
|
||||
vacpagelist->num_pages, sizeof(VacPage), (void *) &vp,
|
||||
vac_cmp_blk);
|
||||
vacpagelist->num_pages, sizeof(VacPage), (void *) &vp,
|
||||
vac_cmp_blk);
|
||||
|
||||
if (vpp == (VacPage *) NULL)
|
||||
return (VacPage) NULL;
|
||||
@@ -2235,8 +2244,8 @@ tid_reaped(ItemPointer itemptr, VacPageList vacpagelist)
|
||||
}
|
||||
|
||||
voff = (OffsetNumber *) vac_find_eq((void *) (vp->offsets),
|
||||
vp->offsets_free, sizeof(OffsetNumber), (void *) &ioffno,
|
||||
vac_cmp_offno);
|
||||
vp->offsets_free, sizeof(OffsetNumber), (void *) &ioffno,
|
||||
vac_cmp_offno);
|
||||
|
||||
if (voff == (OffsetNumber *) NULL)
|
||||
return (VacPage) NULL;
|
||||
@@ -2265,7 +2274,7 @@ tid_reaped(ItemPointer itemptr, VacPageList vacpagelist)
|
||||
*/
|
||||
static void
|
||||
update_relstats(Oid relid, int num_pages, int num_tuples, bool hasindex,
|
||||
VRelStats *vacrelstats)
|
||||
VRelStats *vacrelstats)
|
||||
{
|
||||
Relation rd;
|
||||
HeapTupleData rtup;
|
||||
@@ -2313,7 +2322,7 @@ update_relstats(Oid relid, int num_pages, int num_tuples, bool hasindex,
|
||||
static void
|
||||
reap_page(VacPageList vacpagelist, VacPage vacpage)
|
||||
{
|
||||
VacPage newvacpage;
|
||||
VacPage newvacpage;
|
||||
|
||||
/* allocate a VacPageData entry */
|
||||
newvacpage = (VacPage) palloc(sizeof(VacPageData) + vacpage->offsets_free * sizeof(OffsetNumber));
|
||||
@@ -2354,7 +2363,7 @@ vpage_insert(VacPageList vacpagelist, VacPage vpnew)
|
||||
|
||||
static void *
|
||||
vac_find_eq(void *bot, int nelem, int size, void *elm,
|
||||
int (*compar) (const void *, const void *))
|
||||
int (*compar) (const void *, const void *))
|
||||
{
|
||||
int res;
|
||||
int last = nelem - 1;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.45 2001/01/24 19:42:53 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.46 2001/03/22 03:59:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -453,6 +453,7 @@ parse_DefaultXactIsoLevel(char *value)
|
||||
{
|
||||
#if 0
|
||||
TransactionState s = CurrentTransactionState;
|
||||
|
||||
#endif
|
||||
|
||||
if (value == NULL)
|
||||
@@ -632,7 +633,7 @@ parse_client_encoding(char *value)
|
||||
}
|
||||
#else
|
||||
if (value &&
|
||||
strcasecmp(value, pg_encoding_to_char(pg_get_client_encoding())) != 0)
|
||||
strcasecmp(value, pg_encoding_to_char(pg_get_client_encoding())) != 0)
|
||||
elog(ERROR, "Client encoding %s is not supported", value);
|
||||
#endif
|
||||
return TRUE;
|
||||
@@ -701,28 +702,27 @@ reset_server_encoding(void)
|
||||
void
|
||||
SetPGVariable(const char *name, const char *value)
|
||||
{
|
||||
char *mvalue = value ? pstrdup(value) : ((char*) NULL);
|
||||
char *mvalue = value ? pstrdup(value) : ((char *) NULL);
|
||||
|
||||
/*
|
||||
* Special cases ought to be removed and handled separately
|
||||
* by TCOP
|
||||
*/
|
||||
if (strcasecmp(name, "datestyle")==0)
|
||||
parse_date(mvalue);
|
||||
else if (strcasecmp(name, "timezone")==0)
|
||||
parse_timezone(mvalue);
|
||||
else if (strcasecmp(name, "DefaultXactIsoLevel")==0)
|
||||
parse_DefaultXactIsoLevel(mvalue);
|
||||
else if (strcasecmp(name, "XactIsoLevel")==0)
|
||||
parse_XactIsoLevel(mvalue);
|
||||
else if (strcasecmp(name, "client_encoding")==0)
|
||||
parse_client_encoding(mvalue);
|
||||
else if (strcasecmp(name, "server_encoding")==0)
|
||||
parse_server_encoding(mvalue);
|
||||
else if (strcasecmp(name, "random_seed")==0)
|
||||
parse_random_seed(mvalue);
|
||||
else
|
||||
SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET);
|
||||
/*
|
||||
* Special cases ought to be removed and handled separately by TCOP
|
||||
*/
|
||||
if (strcasecmp(name, "datestyle") == 0)
|
||||
parse_date(mvalue);
|
||||
else if (strcasecmp(name, "timezone") == 0)
|
||||
parse_timezone(mvalue);
|
||||
else if (strcasecmp(name, "DefaultXactIsoLevel") == 0)
|
||||
parse_DefaultXactIsoLevel(mvalue);
|
||||
else if (strcasecmp(name, "XactIsoLevel") == 0)
|
||||
parse_XactIsoLevel(mvalue);
|
||||
else if (strcasecmp(name, "client_encoding") == 0)
|
||||
parse_client_encoding(mvalue);
|
||||
else if (strcasecmp(name, "server_encoding") == 0)
|
||||
parse_server_encoding(mvalue);
|
||||
else if (strcasecmp(name, "random_seed") == 0)
|
||||
parse_random_seed(mvalue);
|
||||
else
|
||||
SetConfigOption(name, value, superuser() ? PGC_SUSET : PGC_USERSET);
|
||||
|
||||
if (mvalue)
|
||||
pfree(mvalue);
|
||||
@@ -732,44 +732,45 @@ SetPGVariable(const char *name, const char *value)
|
||||
void
|
||||
GetPGVariable(const char *name)
|
||||
{
|
||||
if (strcasecmp(name, "datestyle")==0)
|
||||
show_date();
|
||||
else if (strcasecmp(name, "timezone")==0)
|
||||
show_timezone();
|
||||
else if (strcasecmp(name, "DefaultXactIsoLevel")==0)
|
||||
show_DefaultXactIsoLevel();
|
||||
else if (strcasecmp(name, "XactIsoLevel")==0)
|
||||
show_XactIsoLevel();
|
||||
else if (strcasecmp(name, "client_encoding")==0)
|
||||
show_client_encoding();
|
||||
else if (strcasecmp(name, "server_encoding")==0)
|
||||
show_server_encoding();
|
||||
else if (strcasecmp(name, "random_seed")==0)
|
||||
show_random_seed();
|
||||
else
|
||||
{
|
||||
const char * val = GetConfigOption(name);
|
||||
elog(NOTICE, "%s is %s", name, val);
|
||||
}
|
||||
}
|
||||
if (strcasecmp(name, "datestyle") == 0)
|
||||
show_date();
|
||||
else if (strcasecmp(name, "timezone") == 0)
|
||||
show_timezone();
|
||||
else if (strcasecmp(name, "DefaultXactIsoLevel") == 0)
|
||||
show_DefaultXactIsoLevel();
|
||||
else if (strcasecmp(name, "XactIsoLevel") == 0)
|
||||
show_XactIsoLevel();
|
||||
else if (strcasecmp(name, "client_encoding") == 0)
|
||||
show_client_encoding();
|
||||
else if (strcasecmp(name, "server_encoding") == 0)
|
||||
show_server_encoding();
|
||||
else if (strcasecmp(name, "random_seed") == 0)
|
||||
show_random_seed();
|
||||
else
|
||||
{
|
||||
const char *val = GetConfigOption(name);
|
||||
|
||||
elog(NOTICE, "%s is %s", name, val);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ResetPGVariable(const char *name)
|
||||
{
|
||||
if (strcasecmp(name, "datestyle")==0)
|
||||
reset_date();
|
||||
else if (strcasecmp(name, "timezone")==0)
|
||||
reset_timezone();
|
||||
else if (strcasecmp(name, "DefaultXactIsoLevel")==0)
|
||||
reset_DefaultXactIsoLevel();
|
||||
else if (strcasecmp(name, "XactIsoLevel")==0)
|
||||
reset_XactIsoLevel();
|
||||
else if (strcasecmp(name, "client_encoding")==0)
|
||||
reset_client_encoding();
|
||||
else if (strcasecmp(name, "server_encoding")==0)
|
||||
reset_server_encoding();
|
||||
else if (strcasecmp(name, "random_seed")==0)
|
||||
reset_random_seed();
|
||||
else
|
||||
SetConfigOption(name, NULL, superuser() ? PGC_SUSET : PGC_USERSET);
|
||||
}
|
||||
if (strcasecmp(name, "datestyle") == 0)
|
||||
reset_date();
|
||||
else if (strcasecmp(name, "timezone") == 0)
|
||||
reset_timezone();
|
||||
else if (strcasecmp(name, "DefaultXactIsoLevel") == 0)
|
||||
reset_DefaultXactIsoLevel();
|
||||
else if (strcasecmp(name, "XactIsoLevel") == 0)
|
||||
reset_XactIsoLevel();
|
||||
else if (strcasecmp(name, "client_encoding") == 0)
|
||||
reset_client_encoding();
|
||||
else if (strcasecmp(name, "server_encoding") == 0)
|
||||
reset_server_encoding();
|
||||
else if (strcasecmp(name, "random_seed") == 0)
|
||||
reset_random_seed();
|
||||
else
|
||||
SetConfigOption(name, NULL, superuser() ? PGC_SUSET : PGC_USERSET);
|
||||
}
|
||||
|
||||
@@ -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.53 2001/01/24 19:42:53 momjian Exp $
|
||||
* $Id: view.c,v 1.54 2001/03/22 03:59:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -57,7 +57,7 @@ DefineVirtualRelation(char *relname, List *tlist)
|
||||
TargetEntry *entry = lfirst(t);
|
||||
Resdom *res = entry->resdom;
|
||||
|
||||
if (! res->resjunk)
|
||||
if (!res->resjunk)
|
||||
{
|
||||
char *resname = res->resname;
|
||||
char *restypename = typeidTypeName(res->restype);
|
||||
@@ -118,9 +118,9 @@ MakeRetrieveViewRuleName(char *viewName)
|
||||
snprintf(buf, buflen, "_RET%s", viewName);
|
||||
/* clip to less than NAMEDATALEN bytes, if necessary */
|
||||
#ifdef MULTIBYTE
|
||||
maxlen = pg_mbcliplen(buf, strlen(buf), NAMEDATALEN-1);
|
||||
maxlen = pg_mbcliplen(buf, strlen(buf), NAMEDATALEN - 1);
|
||||
#else
|
||||
maxlen = NAMEDATALEN-1;
|
||||
maxlen = NAMEDATALEN - 1;
|
||||
#endif
|
||||
if (maxlen < buflen)
|
||||
buf[maxlen] = '\0';
|
||||
@@ -211,12 +211,12 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
|
||||
*rt_entry2;
|
||||
|
||||
/*
|
||||
* Make a copy of the given parsetree. It's not so much that we
|
||||
* don't want to scribble on our input, it's that the parser has
|
||||
* a bad habit of outputting multiple links to the same subtree
|
||||
* for constructs like BETWEEN, and we mustn't have OffsetVarNodes
|
||||
* increment the varno of a Var node twice. copyObject will expand
|
||||
* any multiply-referenced subtree into multiple copies.
|
||||
* Make a copy of the given parsetree. It's not so much that we don't
|
||||
* want to scribble on our input, it's that the parser has a bad habit
|
||||
* of outputting multiple links to the same subtree for constructs
|
||||
* like BETWEEN, and we mustn't have OffsetVarNodes increment the
|
||||
* varno of a Var node twice. copyObject will expand any
|
||||
* multiply-referenced subtree into multiple copies.
|
||||
*/
|
||||
viewParse = (Query *) copyObject(viewParse);
|
||||
|
||||
@@ -261,6 +261,7 @@ 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.
|
||||
@@ -295,9 +296,10 @@ DefineView(char *viewName, Query *viewParse)
|
||||
void
|
||||
RemoveView(char *viewName)
|
||||
{
|
||||
|
||||
/*
|
||||
* We just have to drop the relation; the associated rules will
|
||||
* be cleaned up automatically.
|
||||
* We just have to drop the relation; the associated rules will be
|
||||
* cleaned up automatically.
|
||||
*/
|
||||
heap_drop_with_catalog(viewName, allowSystemTableMods);
|
||||
}
|
||||
|
||||
@@ -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.56 2001/01/24 19:42:53 momjian Exp $
|
||||
* $Id: execAmi.c,v 1.57 2001/03/22 03:59:25 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -19,7 +19,7 @@
|
||||
* ExecInsert \ executor interface / aminsert
|
||||
* ExecReScanR / to access methods \ amrescan
|
||||
* ExecMarkPos / \ ammarkpos
|
||||
* ExecRestrPos / \ amrestpos
|
||||
* ExecRestrPos / \ amrestpos
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
@@ -91,7 +91,7 @@ ExecOpenScanR(Oid relOid,
|
||||
* on whether this is a heap relation or an index relation.
|
||||
*
|
||||
* For a table, acquire AccessShareLock for the duration of the query
|
||||
* execution. For indexes, acquire no lock here; the index machinery
|
||||
* execution. For indexes, acquire no lock here; the index machinery
|
||||
* does its own locks and unlocks. (We rely on having some kind of
|
||||
* lock on the parent table to ensure the index won't go away!)
|
||||
* ----------------
|
||||
@@ -413,7 +413,7 @@ ExecMarkPos(Plan *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
case T_SeqScan:
|
||||
ExecSeqMarkPos((SeqScan *) node);
|
||||
break;
|
||||
|
||||
@@ -455,7 +455,7 @@ ExecRestrPos(Plan *node)
|
||||
{
|
||||
switch (nodeTag(node))
|
||||
{
|
||||
case T_SeqScan:
|
||||
case T_SeqScan:
|
||||
ExecSeqRestrPos((SeqScan *) node);
|
||||
break;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.25 2001/01/29 00:39:17 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.26 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -265,6 +265,7 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType)
|
||||
void
|
||||
ExecFreeJunkFilter(JunkFilter *junkfilter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Since the junkfilter is inside its own context, we just have to
|
||||
* delete the context and we're set.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.138 2001/01/29 00:39:18 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.139 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -51,15 +51,15 @@ static TupleDesc InitPlan(CmdType operation,
|
||||
Plan *plan,
|
||||
EState *estate);
|
||||
static void initResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||
Index resultRelationIndex,
|
||||
List *rangeTable,
|
||||
CmdType operation);
|
||||
Index resultRelationIndex,
|
||||
List *rangeTable,
|
||||
CmdType operation);
|
||||
static void EndPlan(Plan *plan, EState *estate);
|
||||
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
|
||||
CmdType operation,
|
||||
long numberTuples,
|
||||
ScanDirection direction,
|
||||
DestReceiver *destfunc);
|
||||
CmdType operation,
|
||||
long numberTuples,
|
||||
ScanDirection direction,
|
||||
DestReceiver *destfunc);
|
||||
static void ExecRetrieve(TupleTableSlot *slot,
|
||||
DestReceiver *destfunc,
|
||||
EState *estate);
|
||||
@@ -72,9 +72,9 @@ static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
|
||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||
static void EndEvalPlanQual(EState *estate);
|
||||
static void ExecCheckQueryPerms(CmdType operation, Query *parseTree,
|
||||
Plan *plan);
|
||||
Plan *plan);
|
||||
static void ExecCheckPlanPerms(Plan *plan, List *rangeTable,
|
||||
CmdType operation);
|
||||
CmdType operation);
|
||||
static void ExecCheckRTPerms(List *rangeTable, CmdType operation);
|
||||
static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
||||
|
||||
@@ -91,7 +91,7 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
|
||||
* be returned by the query.
|
||||
*
|
||||
* NB: the CurrentMemoryContext when this is called must be the context
|
||||
* to be used as the per-query context for the query plan. ExecutorRun()
|
||||
* to be used as the per-query context for the query plan. ExecutorRun()
|
||||
* and ExecutorEnd() must be called in this same memory context.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
@@ -287,6 +287,7 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate)
|
||||
static void
|
||||
ExecCheckQueryPerms(CmdType operation, Query *parseTree, Plan *plan)
|
||||
{
|
||||
|
||||
/*
|
||||
* Check RTEs in the query's primary rangetable.
|
||||
*/
|
||||
@@ -339,7 +340,7 @@ ExecCheckPlanPerms(Plan *plan, List *rangeTable, CmdType operation)
|
||||
{
|
||||
case T_SubqueryScan:
|
||||
{
|
||||
SubqueryScan *scan = (SubqueryScan *) plan;
|
||||
SubqueryScan *scan = (SubqueryScan *) plan;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/* Recursively check the subquery */
|
||||
@@ -405,12 +406,13 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation)
|
||||
relName = rte->relname;
|
||||
|
||||
/*
|
||||
* userid to check as: current user unless we have a setuid indication.
|
||||
* userid to check as: current user unless we have a setuid
|
||||
* indication.
|
||||
*
|
||||
* Note: GetUserId() is presently fast enough that there's no harm
|
||||
* in calling it separately for each RTE. If that stops being true,
|
||||
* we could call it once in ExecCheckQueryPerms and pass the userid
|
||||
* down from there. But for now, no need for the extra clutter.
|
||||
* Note: GetUserId() is presently fast enough that there's no harm in
|
||||
* calling it separately for each RTE. If that stops being true, we
|
||||
* could call it once in ExecCheckQueryPerms and pass the userid down
|
||||
* from there. But for now, no need for the extra clutter.
|
||||
*/
|
||||
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
|
||||
|
||||
@@ -426,6 +428,7 @@ 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
|
||||
@@ -519,6 +522,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
|
||||
if (resultRelations != NIL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Multiple result relations (due to inheritance)
|
||||
* parseTree->resultRelations identifies them all
|
||||
@@ -541,8 +545,10 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Single result relation identified by parseTree->resultRelation
|
||||
* Single result relation identified by
|
||||
* parseTree->resultRelation
|
||||
*/
|
||||
numResultRelations = 1;
|
||||
resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
|
||||
@@ -559,6 +565,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* if no result relation, then set state appropriately
|
||||
*/
|
||||
@@ -616,10 +623,10 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
tupType = ExecGetTupType(plan); /* tuple descriptor */
|
||||
|
||||
/*
|
||||
* Initialize the junk filter if needed. SELECT and INSERT queries need
|
||||
* a filter if there are any junk attrs in the tlist. UPDATE and
|
||||
* DELETE always need one, since there's always a junk 'ctid' attribute
|
||||
* present --- no need to look first.
|
||||
* Initialize the junk filter if needed. SELECT and INSERT queries
|
||||
* need a filter if there are any junk attrs in the tlist. UPDATE and
|
||||
* DELETE always need one, since there's always a junk 'ctid'
|
||||
* attribute present --- no need to look first.
|
||||
*/
|
||||
{
|
||||
bool junk_filter_needed = false;
|
||||
@@ -650,11 +657,12 @@ 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
|
||||
* UPDATE/DELETE, so we can't be fooled by some needing
|
||||
* a filter and some not.
|
||||
* If there are multiple result relations, each one needs its
|
||||
* own junk filter. Note this is only possible for
|
||||
* UPDATE/DELETE, so we can't be fooled by some needing a
|
||||
* filter and some not.
|
||||
*/
|
||||
if (parseTree->resultRelations != NIL)
|
||||
{
|
||||
@@ -678,6 +686,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
resultRelInfo++;
|
||||
subplans = lnext(subplans);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set active junkfilter too; at this point ExecInitAppend
|
||||
* has already selected an active result relation...
|
||||
@@ -750,10 +759,10 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
|
||||
CommandCounterIncrement();
|
||||
|
||||
/*
|
||||
* If necessary, create a TOAST table for the into relation.
|
||||
* Note that AlterTableCreateToastTable ends with
|
||||
* CommandCounterIncrement(), so that the TOAST table will
|
||||
* be visible for insertion.
|
||||
* If necessary, create a TOAST table for the into
|
||||
* relation. Note that AlterTableCreateToastTable ends
|
||||
* with CommandCounterIncrement(), so that the TOAST table
|
||||
* will be visible for insertion.
|
||||
*/
|
||||
AlterTableCreateToastTable(intoName, true);
|
||||
|
||||
@@ -817,9 +826,8 @@ initResultRelInfo(ResultRelInfo *resultRelInfo,
|
||||
/*
|
||||
* If there are indices on the result relation, open them and save
|
||||
* descriptors in the result relation info, so that we can add new
|
||||
* index entries for the tuples we add/update. We need not do
|
||||
* this for a DELETE, however, since deletion doesn't affect
|
||||
* indexes.
|
||||
* index entries for the tuples we add/update. We need not do this
|
||||
* for a DELETE, however, since deletion doesn't affect indexes.
|
||||
*/
|
||||
if (resultRelationDesc->rd_rel->relhasindex &&
|
||||
operation != CMD_DELETE)
|
||||
@@ -857,8 +865,8 @@ EndPlan(Plan *plan, EState *estate)
|
||||
estate->es_tupleTable = NULL;
|
||||
|
||||
/*
|
||||
* close the result relation(s) if any, but hold locks
|
||||
* until xact commit. Also clean up junkfilters if present.
|
||||
* close the result relation(s) if any, but hold locks until xact
|
||||
* commit. Also clean up junkfilters if present.
|
||||
*/
|
||||
resultRelInfo = estate->es_result_relations;
|
||||
for (i = estate->es_num_result_relations; i > 0; i--)
|
||||
@@ -1033,7 +1041,7 @@ lnext: ;
|
||||
/*
|
||||
* Unlike the UPDATE/DELETE case, a null result is
|
||||
* possible here, when the referenced table is on the
|
||||
* nullable side of an outer join. Ignore nulls.
|
||||
* nullable side of an outer join. Ignore nulls.
|
||||
*/
|
||||
if (isNull)
|
||||
continue;
|
||||
@@ -1216,7 +1224,7 @@ ExecAppend(TupleTableSlot *slot,
|
||||
|
||||
/* BEFORE ROW INSERT Triggers */
|
||||
if (resultRelationDesc->trigdesc &&
|
||||
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
||||
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
|
||||
{
|
||||
HeapTuple newtuple;
|
||||
|
||||
@@ -1227,11 +1235,12 @@ 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
|
||||
* memory context, and therefore will go away by itself.
|
||||
* The tuple table slot should not try to clear it.
|
||||
* memory context, and therefore will go away by itself. The
|
||||
* tuple table slot should not try to clear it.
|
||||
*/
|
||||
ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
|
||||
tuple = newtuple;
|
||||
@@ -1294,7 +1303,7 @@ ExecDelete(TupleTableSlot *slot,
|
||||
|
||||
/* BEFORE ROW DELETE Triggers */
|
||||
if (resultRelationDesc->trigdesc &&
|
||||
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
|
||||
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)
|
||||
{
|
||||
bool dodelete;
|
||||
|
||||
@@ -1323,7 +1332,7 @@ ldelete:;
|
||||
else if (!(ItemPointerEquals(tupleid, &ctid)))
|
||||
{
|
||||
TupleTableSlot *epqslot = EvalPlanQual(estate,
|
||||
resultRelInfo->ri_RangeTableIndex, &ctid);
|
||||
resultRelInfo->ri_RangeTableIndex, &ctid);
|
||||
|
||||
if (!TupIsNull(epqslot))
|
||||
{
|
||||
@@ -1400,7 +1409,7 @@ ExecReplace(TupleTableSlot *slot,
|
||||
|
||||
/* BEFORE ROW UPDATE Triggers */
|
||||
if (resultRelationDesc->trigdesc &&
|
||||
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
||||
resultRelationDesc->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
|
||||
{
|
||||
HeapTuple newtuple;
|
||||
|
||||
@@ -1411,11 +1420,12 @@ 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
|
||||
* memory context, and therefore will go away by itself.
|
||||
* The tuple table slot should not try to clear it.
|
||||
* memory context, and therefore will go away by itself. The
|
||||
* tuple table slot should not try to clear it.
|
||||
*/
|
||||
ExecStoreTuple(newtuple, slot, InvalidBuffer, false);
|
||||
tuple = newtuple;
|
||||
@@ -1447,7 +1457,7 @@ lreplace:;
|
||||
else if (!(ItemPointerEquals(tupleid, &ctid)))
|
||||
{
|
||||
TupleTableSlot *epqslot = EvalPlanQual(estate,
|
||||
resultRelInfo->ri_RangeTableIndex, &ctid);
|
||||
resultRelInfo->ri_RangeTableIndex, &ctid);
|
||||
|
||||
if (!TupIsNull(epqslot))
|
||||
{
|
||||
@@ -1469,10 +1479,10 @@ lreplace:;
|
||||
|
||||
/*
|
||||
* Note: instead of having to update the old index tuples associated
|
||||
* with the heap tuple, all we do is form and insert new index
|
||||
* tuples. This is because replaces are actually deletes and inserts
|
||||
* and index tuple deletion is done automagically by the vacuum
|
||||
* daemon. All we do is insert new index tuples. -cim 9/27/89
|
||||
* with the heap tuple, all we do is form and insert new index tuples.
|
||||
* This is because replaces are actually deletes and inserts and index
|
||||
* tuple deletion is done automagically by the vacuum daemon. All we
|
||||
* do is insert new index tuples. -cim 9/27/89
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -1525,8 +1535,8 @@ ExecRelCheck(ResultRelInfo *resultRelInfo,
|
||||
}
|
||||
|
||||
/*
|
||||
* We will use the EState's per-tuple context for evaluating constraint
|
||||
* expressions (creating it if it's not already there).
|
||||
* We will use the EState's per-tuple context for evaluating
|
||||
* constraint expressions (creating it if it's not already there).
|
||||
*/
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
||||
@@ -1568,10 +1578,10 @@ ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
|
||||
|
||||
for (attrChk = 1; attrChk <= natts; attrChk++)
|
||||
{
|
||||
if (rel->rd_att->attrs[attrChk-1]->attnotnull &&
|
||||
if (rel->rd_att->attrs[attrChk - 1]->attnotnull &&
|
||||
heap_attisnull(tuple, attrChk))
|
||||
elog(ERROR, "%s: Fail to add null value in not null attribute %s",
|
||||
caller, NameStr(rel->rd_att->attrs[attrChk-1]->attname));
|
||||
caller, NameStr(rel->rd_att->attrs[attrChk - 1]->attname));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.83 2001/01/29 00:39:18 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.84 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -46,22 +46,22 @@
|
||||
|
||||
/* static function decls */
|
||||
static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext,
|
||||
bool *isNull);
|
||||
bool *isNull);
|
||||
static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
static ExprDoneCond ExecEvalFuncArgs(FunctionCachePtr fcache,
|
||||
List *argList,
|
||||
ExprContext *econtext);
|
||||
List *argList,
|
||||
ExprContext *econtext);
|
||||
static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
|
||||
static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
bool *isNull, ExprDoneCond *isDone);
|
||||
|
||||
|
||||
/*----------
|
||||
@@ -77,7 +77,7 @@ static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
|
||||
* done in versions up through 7.0) then an assignment like
|
||||
* UPDATE table SET arrayfield[4] = NULL
|
||||
* will result in setting the whole array to NULL, which is certainly not
|
||||
* very desirable. By returning the source array we make the assignment
|
||||
* very desirable. By returning the source array we make the assignment
|
||||
* into a no-op, instead. (Eventually we need to redesign arrays so that
|
||||
* individual elements can be NULL, but for now, let's try to protect users
|
||||
* from shooting themselves in the foot.)
|
||||
@@ -112,10 +112,11 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
econtext,
|
||||
isNull,
|
||||
isDone));
|
||||
|
||||
/*
|
||||
* If refexpr yields NULL, result is always NULL, for now anyway.
|
||||
* (This means you cannot assign to an element or slice of an array
|
||||
* that's NULL; it'll just stay NULL.)
|
||||
* (This means you cannot assign to an element or slice of an
|
||||
* array that's NULL; it'll just stay NULL.)
|
||||
*/
|
||||
if (*isNull)
|
||||
return (Datum) NULL;
|
||||
@@ -147,7 +148,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
/* If any index expr yields NULL, result is NULL or source array */
|
||||
if (*isNull)
|
||||
{
|
||||
if (! isAssignment || array_source == NULL)
|
||||
if (!isAssignment || array_source == NULL)
|
||||
return (Datum) NULL;
|
||||
*isNull = false;
|
||||
return PointerGetDatum(array_source);
|
||||
@@ -166,10 +167,14 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
econtext,
|
||||
isNull,
|
||||
NULL));
|
||||
/* If any index expr yields NULL, result is NULL or source array */
|
||||
|
||||
/*
|
||||
* If any index expr yields NULL, result is NULL or source
|
||||
* array
|
||||
*/
|
||||
if (*isNull)
|
||||
{
|
||||
if (! isAssignment || array_source == NULL)
|
||||
if (!isAssignment || array_source == NULL)
|
||||
return (Datum) NULL;
|
||||
*isNull = false;
|
||||
return PointerGetDatum(array_source);
|
||||
@@ -189,9 +194,10 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
econtext,
|
||||
isNull,
|
||||
NULL);
|
||||
|
||||
/*
|
||||
* For now, can't cope with inserting NULL into an array,
|
||||
* so make it a no-op per discussion above...
|
||||
* For now, can't cope with inserting NULL into an array, so make
|
||||
* it a no-op per discussion above...
|
||||
*/
|
||||
if (*isNull)
|
||||
{
|
||||
@@ -202,7 +208,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
}
|
||||
|
||||
if (array_source == NULL)
|
||||
return sourceData; /* XXX do something else? */
|
||||
return sourceData; /* XXX do something else? */
|
||||
|
||||
if (lIndex == NULL)
|
||||
resultArray = array_set(array_source, i,
|
||||
@@ -215,7 +221,7 @@ ExecEvalArrayRef(ArrayRef *arrayRef,
|
||||
else
|
||||
resultArray = array_set_slice(array_source, i,
|
||||
upper.indx, lower.indx,
|
||||
(ArrayType *) DatumGetPointer(sourceData),
|
||||
(ArrayType *) DatumGetPointer(sourceData),
|
||||
arrayRef->refelembyval,
|
||||
arrayRef->refelemlength,
|
||||
arrayRef->refattrlength,
|
||||
@@ -587,12 +593,12 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
|
||||
int i;
|
||||
List *arg;
|
||||
|
||||
argIsDone = ExprSingleResult; /* default assumption */
|
||||
argIsDone = ExprSingleResult; /* default assumption */
|
||||
|
||||
i = 0;
|
||||
foreach(arg, argList)
|
||||
{
|
||||
ExprDoneCond thisArgIsDone;
|
||||
ExprDoneCond thisArgIsDone;
|
||||
|
||||
fcache->fcinfo.arg[i] = ExecEvalExpr((Node *) lfirst(arg),
|
||||
econtext,
|
||||
@@ -601,10 +607,12 @@ ExecEvalFuncArgs(FunctionCachePtr fcache,
|
||||
|
||||
if (thisArgIsDone != ExprSingleResult)
|
||||
{
|
||||
|
||||
/*
|
||||
* We allow only one argument to have a set value; we'd need
|
||||
* much more complexity to keep track of multiple set arguments
|
||||
* (cf. ExecTargetList) and it doesn't seem worth it.
|
||||
* much more complexity to keep track of multiple set
|
||||
* arguments (cf. ExecTargetList) and it doesn't seem worth
|
||||
* it.
|
||||
*/
|
||||
if (argIsDone != ExprSingleResult)
|
||||
elog(ERROR, "Functions and operators can take only one set argument");
|
||||
@@ -632,15 +640,15 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
|
||||
bool *isNull,
|
||||
ExprDoneCond *isDone)
|
||||
{
|
||||
Datum result;
|
||||
ExprDoneCond argDone;
|
||||
int i;
|
||||
Datum result;
|
||||
ExprDoneCond argDone;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* arguments is a list of expressions to evaluate before passing to
|
||||
* the function manager. We skip the evaluation if it was already
|
||||
* done in the previous call (ie, we are continuing the evaluation
|
||||
* of a set-valued function). Otherwise, collect the current argument
|
||||
* done in the previous call (ie, we are continuing the evaluation of
|
||||
* a set-valued function). Otherwise, collect the current argument
|
||||
* values into fcache->fcinfo.
|
||||
*/
|
||||
if (fcache->fcinfo.nargs > 0 && !fcache->argsValid)
|
||||
@@ -664,28 +672,30 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
|
||||
*/
|
||||
if (fcache->func.fn_retset || fcache->hasSetArg)
|
||||
{
|
||||
|
||||
/*
|
||||
* We need to return a set result. Complain if caller not ready
|
||||
* We need to return a set result. Complain if caller not ready
|
||||
* to accept one.
|
||||
*/
|
||||
if (isDone == NULL)
|
||||
elog(ERROR, "Set-valued function called in context that cannot accept a set");
|
||||
|
||||
/*
|
||||
* This loop handles the situation where we have both a set argument
|
||||
* and a set-valued function. Once we have exhausted the function's
|
||||
* value(s) for a particular argument value, we have to get the next
|
||||
* argument value and start the function over again. We might have
|
||||
* to do it more than once, if the function produces an empty result
|
||||
* set for a particular input value.
|
||||
* This loop handles the situation where we have both a set
|
||||
* argument and a set-valued function. Once we have exhausted the
|
||||
* function's value(s) for a particular argument value, we have to
|
||||
* get the next argument value and start the function over again.
|
||||
* We might have to do it more than once, if the function produces
|
||||
* an empty result set for a particular input value.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* If function is strict, and there are any NULL arguments,
|
||||
* skip calling the function (at least for this set of args).
|
||||
*/
|
||||
bool callit = true;
|
||||
bool callit = true;
|
||||
|
||||
if (fcache->func.fn_strict)
|
||||
{
|
||||
@@ -716,13 +726,15 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
|
||||
|
||||
if (*isDone != ExprEndResult)
|
||||
{
|
||||
|
||||
/*
|
||||
* Got a result from current argument. If function itself
|
||||
* returns set, flag that we want to reuse current argument
|
||||
* values on next call.
|
||||
* Got a result from current argument. If function itself
|
||||
* returns set, flag that we want to reuse current
|
||||
* argument values on next call.
|
||||
*/
|
||||
if (fcache->func.fn_retset)
|
||||
fcache->argsValid = true;
|
||||
|
||||
/*
|
||||
* Make sure we say we are returning a set, even if the
|
||||
* function itself doesn't return sets.
|
||||
@@ -762,11 +774,12 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Non-set case: much easier.
|
||||
*
|
||||
* If function is strict, and there are any NULL arguments,
|
||||
* skip calling the function and return NULL.
|
||||
* If function is strict, and there are any NULL arguments, skip
|
||||
* calling the function and return NULL.
|
||||
*/
|
||||
if (fcache->func.fn_strict)
|
||||
{
|
||||
@@ -852,9 +865,9 @@ ExecEvalFunc(Expr *funcClause,
|
||||
FunctionCachePtr fcache;
|
||||
|
||||
/*
|
||||
* we extract the oid of the function associated with the func node and
|
||||
* then pass the work onto ExecMakeFunctionResult which evaluates the
|
||||
* arguments and returns the result of calling the function on the
|
||||
* we extract the oid of the function associated with the func node
|
||||
* and then pass the work onto ExecMakeFunctionResult which evaluates
|
||||
* the arguments and returns the result of calling the function on the
|
||||
* evaluated arguments.
|
||||
*
|
||||
* this is nearly identical to the ExecEvalOper code.
|
||||
@@ -915,7 +928,7 @@ ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull)
|
||||
* evaluation of 'not' is simple.. expr is false, then return 'true'
|
||||
* and vice versa.
|
||||
*/
|
||||
return BoolGetDatum(! DatumGetBool(expr_value));
|
||||
return BoolGetDatum(!DatumGetBool(expr_value));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -999,7 +1012,7 @@ ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull)
|
||||
*/
|
||||
if (*isNull)
|
||||
AnyNull = true; /* remember we got a null */
|
||||
else if (! DatumGetBool(clause_value))
|
||||
else if (!DatumGetBool(clause_value))
|
||||
return clause_value;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1092,7 @@ ExecEvalFieldSelect(FieldSelect *fselect,
|
||||
bool *isNull,
|
||||
ExprDoneCond *isDone)
|
||||
{
|
||||
Datum result;
|
||||
Datum result;
|
||||
TupleTableSlot *resSlot;
|
||||
|
||||
result = ExecEvalExpr(fselect->arg, econtext, isNull, isDone);
|
||||
@@ -1111,7 +1124,7 @@ ExecEvalFieldSelect(FieldSelect *fselect,
|
||||
*
|
||||
* A caller that can only accept a singleton (non-set) result should pass
|
||||
* NULL for isDone; if the expression computes a set result then an elog()
|
||||
* error will be reported. If the caller does pass an isDone pointer then
|
||||
* error will be reported. If the caller does pass an isDone pointer then
|
||||
* *isDone is set to one of these three states:
|
||||
* ExprSingleResult singleton result (not a set)
|
||||
* ExprMultipleResult return value is one element of a set
|
||||
@@ -1127,7 +1140,7 @@ ExecEvalFieldSelect(FieldSelect *fselect,
|
||||
* The caller should already have switched into the temporary memory
|
||||
* context econtext->ecxt_per_tuple_memory. The convenience entry point
|
||||
* ExecEvalExprSwitchContext() is provided for callers who don't prefer to
|
||||
* do the switch in an outer loop. We do not do the switch here because
|
||||
* do the switch in an outer loop. We do not do the switch here because
|
||||
* it'd be a waste of cycles during recursive entries to ExecEvalExpr().
|
||||
*
|
||||
* This routine is an inner loop routine and must be as fast as possible.
|
||||
@@ -1353,15 +1366,15 @@ ExecQual(List *qual, ExprContext *econtext, bool resultForNull)
|
||||
{
|
||||
if (resultForNull == false)
|
||||
{
|
||||
result = false; /* treat NULL as FALSE */
|
||||
result = false; /* treat NULL as FALSE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! DatumGetBool(expr_value))
|
||||
if (!DatumGetBool(expr_value))
|
||||
{
|
||||
result = false; /* definitely FALSE */
|
||||
result = false; /* definitely FALSE */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1383,7 +1396,7 @@ ExecTargetListLength(List *targetlist)
|
||||
|
||||
foreach(tl, targetlist)
|
||||
{
|
||||
TargetEntry *curTle = (TargetEntry *) lfirst(tl);
|
||||
TargetEntry *curTle = (TargetEntry *) lfirst(tl);
|
||||
|
||||
if (curTle->resdom != NULL)
|
||||
len++;
|
||||
@@ -1404,17 +1417,15 @@ ExecCleanTargetListLength(List *targetlist)
|
||||
|
||||
foreach(tl, targetlist)
|
||||
{
|
||||
TargetEntry *curTle = (TargetEntry *) lfirst(tl);
|
||||
TargetEntry *curTle = (TargetEntry *) lfirst(tl);
|
||||
|
||||
if (curTle->resdom != NULL)
|
||||
{
|
||||
if (! curTle->resdom->resjunk)
|
||||
if (!curTle->resdom->resjunk)
|
||||
len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
len += curTle->fjoin->fj_nNodes;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
@@ -1440,6 +1451,7 @@ ExecTargetList(List *targetlist,
|
||||
ExprDoneCond *isDone)
|
||||
{
|
||||
MemoryContext oldContext;
|
||||
|
||||
#define NPREALLOCDOMAINS 64
|
||||
char nullsArray[NPREALLOCDOMAINS];
|
||||
bool fjIsNullArray[NPREALLOCDOMAINS];
|
||||
@@ -1484,10 +1496,11 @@ ExecTargetList(List *targetlist,
|
||||
* we have a really large targetlist. otherwise we use the stack.
|
||||
*
|
||||
* We also allocate a bool array that is used to hold fjoin result state,
|
||||
* and another array that holds the isDone status for each targetlist item.
|
||||
* The isDone status is needed so that we can iterate, generating multiple
|
||||
* tuples, when one or more tlist items return sets. (We expect the caller
|
||||
* to call us again if we return *isDone = ExprMultipleResult.)
|
||||
* and another array that holds the isDone status for each targetlist
|
||||
* item. The isDone status is needed so that we can iterate,
|
||||
* generating multiple tuples, when one or more tlist items return
|
||||
* sets. (We expect the caller to call us again if we return *isDone
|
||||
* = ExprMultipleResult.)
|
||||
*/
|
||||
if (nodomains > NPREALLOCDOMAINS)
|
||||
{
|
||||
@@ -1507,7 +1520,7 @@ ExecTargetList(List *targetlist,
|
||||
*/
|
||||
|
||||
if (isDone)
|
||||
*isDone = ExprSingleResult; /* until proven otherwise */
|
||||
*isDone = ExprSingleResult; /* until proven otherwise */
|
||||
|
||||
haveDoneSets = false; /* any exhausted set exprs in tlist? */
|
||||
|
||||
@@ -1554,8 +1567,10 @@ ExecTargetList(List *targetlist,
|
||||
|
||||
ExecEvalFjoin(tle, econtext, fjIsNull, isDone);
|
||||
|
||||
/* XXX this is wrong, but since fjoin code is completely broken
|
||||
* anyway, I'm not going to worry about it now --- tgl 8/23/00
|
||||
/*
|
||||
* XXX this is wrong, but since fjoin code is completely
|
||||
* broken anyway, I'm not going to worry about it now --- tgl
|
||||
* 8/23/00
|
||||
*/
|
||||
if (isDone && *isDone == ExprEndResult)
|
||||
{
|
||||
@@ -1594,6 +1609,7 @@ ExecTargetList(List *targetlist,
|
||||
|
||||
if (haveDoneSets)
|
||||
{
|
||||
|
||||
/*
|
||||
* note: can't get here unless we verified isDone != NULL
|
||||
*/
|
||||
@@ -1601,7 +1617,8 @@ ExecTargetList(List *targetlist,
|
||||
{
|
||||
|
||||
/*
|
||||
* all sets are done, so report that tlist expansion is complete.
|
||||
* all sets are done, so report that tlist expansion is
|
||||
* complete.
|
||||
*/
|
||||
*isDone = ExprEndResult;
|
||||
MemoryContextSwitchTo(oldContext);
|
||||
@@ -1612,7 +1629,7 @@ ExecTargetList(List *targetlist,
|
||||
{
|
||||
|
||||
/*
|
||||
* We have some done and some undone sets. Restart the done
|
||||
* We have some done and some undone sets. Restart the done
|
||||
* ones so that we can deliver a tuple (if possible).
|
||||
*/
|
||||
foreach(tl, targetlist)
|
||||
@@ -1628,7 +1645,7 @@ ExecTargetList(List *targetlist,
|
||||
values[resind] = ExecEvalExpr(tle->expr,
|
||||
econtext,
|
||||
&isNull,
|
||||
&itemIsDone[resind]);
|
||||
&itemIsDone[resind]);
|
||||
nulls[resind] = isNull ? 'n' : ' ';
|
||||
|
||||
if (itemIsDone[resind] == ExprEndResult)
|
||||
@@ -1644,10 +1661,11 @@ ExecTargetList(List *targetlist,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we cannot make a tuple because some sets are empty,
|
||||
* we still have to cycle the nonempty sets to completion,
|
||||
* else resources will not be released from subplans etc.
|
||||
* If we cannot make a tuple because some sets are empty, we
|
||||
* still have to cycle the nonempty sets to completion, else
|
||||
* resources will not be released from subplans etc.
|
||||
*/
|
||||
if (*isDone == ExprEndResult)
|
||||
{
|
||||
@@ -1752,8 +1770,8 @@ ExecProject(ProjectionInfo *projInfo, ExprDoneCond *isDone)
|
||||
/*
|
||||
* store the tuple in the projection slot and return the slot.
|
||||
*/
|
||||
return ExecStoreTuple(newTuple, /* tuple to store */
|
||||
slot, /* slot to store in */
|
||||
InvalidBuffer, /* tuple has no buffer */
|
||||
return ExecStoreTuple(newTuple, /* tuple to store */
|
||||
slot, /* slot to store in */
|
||||
InvalidBuffer, /* tuple has no buffer */
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.15 2001/01/24 19:42:54 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.16 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -46,7 +46,7 @@
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecScan(Scan *node,
|
||||
ExecScanAccessMtd accessMtd) /* function returning a tuple */
|
||||
ExecScanAccessMtd accessMtd) /* function returning a tuple */
|
||||
{
|
||||
CommonScanState *scanstate;
|
||||
EState *estate;
|
||||
@@ -81,7 +81,7 @@ ExecScan(Scan *node,
|
||||
|
||||
/* ----------------
|
||||
* Reset per-tuple memory context to free any expression evaluation
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* happen until we're done projecting out tuples from a scan tuple.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.46 2001/01/29 00:39:18 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.47 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -40,7 +40,7 @@
|
||||
* TupIsNull - true when slot contains no tuple(Macro)
|
||||
*
|
||||
* CONVENIENCE INITIALIZATION ROUTINES
|
||||
* ExecInitResultTupleSlot \ convenience routines to initialize
|
||||
* ExecInitResultTupleSlot \ convenience routines to initialize
|
||||
* ExecInitScanTupleSlot \ the various tuple slots for nodes
|
||||
* ExecInitExtraTupleSlot / which store copies of tuples.
|
||||
* ExecInitNullTupleSlot /
|
||||
@@ -422,7 +422,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.
|
||||
@@ -446,7 +446,7 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
||||
void
|
||||
ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
|
||||
TupleDesc tupdesc, /* new tuple descriptor */
|
||||
bool shouldFree) /* is desc owned by slot? */
|
||||
bool shouldFree) /* is desc owned by slot? */
|
||||
{
|
||||
if (slot->ttc_shouldFreeDesc &&
|
||||
slot->ttc_tupleDescriptor != NULL)
|
||||
@@ -482,7 +482,7 @@ ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */
|
||||
* ExecInit{Result,Scan,Extra}TupleSlot
|
||||
*
|
||||
* These are convenience routines to initialize the specified slot
|
||||
* in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
|
||||
* in nodes inheriting the appropriate state. ExecInitExtraTupleSlot
|
||||
* is used for initializing special-purpose slots.
|
||||
* --------------------------------
|
||||
*/
|
||||
@@ -541,11 +541,13 @@ ExecInitExtraTupleSlot(EState *estate)
|
||||
TupleTableSlot *
|
||||
ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
|
||||
{
|
||||
TupleTableSlot* slot = ExecInitExtraTupleSlot(estate);
|
||||
TupleTableSlot *slot = ExecInitExtraTupleSlot(estate);
|
||||
|
||||
/*
|
||||
* Since heap_getattr() will treat attributes beyond a tuple's t_natts
|
||||
* as being NULL, we can make an all-nulls tuple just by making it be of
|
||||
* zero length. However, the slot descriptor must match the real tupType.
|
||||
* as being NULL, we can make an all-nulls tuple just by making it be
|
||||
* of zero length. However, the slot descriptor must match the real
|
||||
* tupType.
|
||||
*/
|
||||
HeapTuple nullTuple;
|
||||
Datum values[1];
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.73 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.74 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -148,6 +148,7 @@ ExecAssignExprContext(EState *estate, CommonState *commonstate)
|
||||
econtext->ecxt_innertuple = NULL;
|
||||
econtext->ecxt_outertuple = NULL;
|
||||
econtext->ecxt_per_query_memory = CurrentMemoryContext;
|
||||
|
||||
/*
|
||||
* Create working memory for expression evaluation in this context.
|
||||
*/
|
||||
@@ -184,14 +185,16 @@ MakeExprContext(TupleTableSlot *slot,
|
||||
econtext->ecxt_innertuple = NULL;
|
||||
econtext->ecxt_outertuple = NULL;
|
||||
econtext->ecxt_per_query_memory = queryContext;
|
||||
|
||||
/*
|
||||
* We make the temporary context a child of current working context,
|
||||
* not of the specified queryContext. This seems reasonable but I'm
|
||||
* not totally sure about it...
|
||||
*
|
||||
* Expression contexts made via this routine typically don't live long
|
||||
* enough to get reset, so specify a minsize of 0. That avoids alloc'ing
|
||||
* any memory in the common case where expr eval doesn't use any.
|
||||
* enough to get reset, so specify a minsize of 0. That avoids
|
||||
* alloc'ing any memory in the common case where expr eval doesn't use
|
||||
* any.
|
||||
*/
|
||||
econtext->ecxt_per_tuple_memory =
|
||||
AllocSetContextCreate(CurrentMemoryContext,
|
||||
@@ -209,7 +212,7 @@ MakeExprContext(TupleTableSlot *slot,
|
||||
|
||||
/*
|
||||
* Free an ExprContext made by MakeExprContext, including the temporary
|
||||
* context used for expression evaluation. Note this will cause any
|
||||
* context used for expression evaluation. Note this will cause any
|
||||
* pass-by-reference expression result to go away!
|
||||
*/
|
||||
void
|
||||
@@ -447,7 +450,7 @@ ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate)
|
||||
* resultRelInfo->ri_RelationDesc.
|
||||
*
|
||||
* This used to be horribly ugly code, and slow too because it
|
||||
* did a sequential scan of pg_index. Now we rely on the relcache
|
||||
* did a sequential scan of pg_index. Now we rely on the relcache
|
||||
* to cache a list of the OIDs of the indices associated with any
|
||||
* specific relation, and we use the pg_index syscache to get the
|
||||
* entries we need from pg_index.
|
||||
@@ -467,7 +470,7 @@ ExecOpenIndices(ResultRelInfo *resultRelInfo)
|
||||
resultRelInfo->ri_NumIndices = 0;
|
||||
|
||||
/* checks for disabled indexes */
|
||||
if (! RelationGetForm(resultRelation)->relhasindex)
|
||||
if (!RelationGetForm(resultRelation)->relhasindex)
|
||||
return;
|
||||
if (IsIgnoringSystemIndexes() &&
|
||||
IsSystemRelationName(RelationGetRelationName(resultRelation)))
|
||||
@@ -635,8 +638,9 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
|
||||
heapDescriptor = RelationGetDescr(heapRelation);
|
||||
|
||||
/*
|
||||
* We will use the EState's per-tuple context for evaluating predicates
|
||||
* and functional-index functions (creating it if it's not already there).
|
||||
* We will use the EState's per-tuple context for evaluating
|
||||
* predicates and functional-index functions (creating it if it's not
|
||||
* already there).
|
||||
*/
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.43 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.44 2001/03/22 03:59:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -70,15 +70,15 @@ typedef SQLFunctionCache *SQLFunctionCachePtr;
|
||||
|
||||
/* non-export function prototypes */
|
||||
static execution_state *init_execution_state(char *src,
|
||||
Oid *argOidVect, int nargs);
|
||||
Oid *argOidVect, int nargs);
|
||||
static void init_sql_fcache(FmgrInfo *finfo);
|
||||
static void postquel_start(execution_state *es);
|
||||
static TupleTableSlot *postquel_getnext(execution_state *es);
|
||||
static void postquel_end(execution_state *es);
|
||||
static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo);
|
||||
static Datum postquel_execute(execution_state *es,
|
||||
FunctionCallInfo fcinfo,
|
||||
SQLFunctionCachePtr fcache);
|
||||
FunctionCallInfo fcinfo,
|
||||
SQLFunctionCachePtr fcache);
|
||||
|
||||
|
||||
static execution_state *
|
||||
@@ -180,7 +180,7 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||
* ----------------
|
||||
*/
|
||||
typeTuple = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(procedureStruct->prorettype),
|
||||
ObjectIdGetDatum(procedureStruct->prorettype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(typeTuple))
|
||||
elog(ERROR, "init_sql_fcache: Cache lookup failed for type %u",
|
||||
@@ -235,9 +235,7 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||
nargs * sizeof(Oid));
|
||||
}
|
||||
else
|
||||
{
|
||||
argOidVect = (Oid *) NULL;
|
||||
}
|
||||
|
||||
tmp = SysCacheGetAttr(PROCOID,
|
||||
procedureTuple,
|
||||
@@ -346,8 +344,8 @@ copy_function_result(SQLFunctionCachePtr fcache,
|
||||
return resultSlot; /* no need to copy result */
|
||||
|
||||
/*
|
||||
* If first time through, we have to initialize the funcSlot's
|
||||
* tuple descriptor.
|
||||
* If first time through, we have to initialize the funcSlot's tuple
|
||||
* descriptor.
|
||||
*/
|
||||
if (funcSlot->ttc_tupleDescriptor == NULL)
|
||||
{
|
||||
@@ -415,12 +413,14 @@ postquel_execute(execution_state *es,
|
||||
|
||||
/*
|
||||
* If we are supposed to return a tuple, we return the tuple slot
|
||||
* pointer converted to Datum. If we are supposed to return a simple
|
||||
* value, then project out the first attribute of the result tuple
|
||||
* (ie, take the first result column of the final SELECT).
|
||||
* pointer converted to Datum. If we are supposed to return a
|
||||
* simple value, then project out the first attribute of the
|
||||
* result tuple (ie, take the first result column of the final
|
||||
* SELECT).
|
||||
*/
|
||||
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.
|
||||
@@ -434,6 +434,7 @@ postquel_execute(execution_state *es,
|
||||
1,
|
||||
resSlot->ttc_tupleDescriptor,
|
||||
&(fcinfo->isnull));
|
||||
|
||||
/*
|
||||
* Note: if result type is pass-by-reference then we are
|
||||
* returning a pointer into the tuple copied by
|
||||
@@ -546,7 +547,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
||||
*/
|
||||
if (fcinfo->flinfo->fn_retset)
|
||||
{
|
||||
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
|
||||
if (rsi && IsA(rsi, ReturnSetInfo))
|
||||
rsi->isDone = ExprEndResult;
|
||||
@@ -572,7 +573,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
|
||||
*/
|
||||
if (fcinfo->flinfo->fn_retset)
|
||||
{
|
||||
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
|
||||
if (rsi && IsA(rsi, ReturnSetInfo))
|
||||
rsi->isDone = ExprMultipleResult;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* The agg's input type and transtype must be the same in this case!
|
||||
*
|
||||
* If transfunc is marked "strict" then NULL input_values are skipped,
|
||||
* keeping the previous transvalue. If transfunc is not strict then it
|
||||
* keeping the previous transvalue. If transfunc is not strict then it
|
||||
* is called for every input tuple and must deal with NULL initcond
|
||||
* or NULL input_value for itself.
|
||||
*
|
||||
@@ -34,7 +34,7 @@
|
||||
* are not allowed to accumulate until end of query. We do this by
|
||||
* "ping-ponging" between two memory contexts; successive calls to the
|
||||
* transfunc are executed in alternate contexts, passing the previous
|
||||
* transvalue that is in the other context. At the beginning of each
|
||||
* transvalue that is in the other context. At the beginning of each
|
||||
* tuple cycle we can reset the current output context to avoid memory
|
||||
* usage growth. Note: we must use MemoryContextContains() to check
|
||||
* whether the transfunc has perhaps handed us back one of its input
|
||||
@@ -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.75 2001/02/16 03:16:57 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.76 2001/03/22 03:59:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -130,8 +130,8 @@ typedef struct AggStatePerAggData
|
||||
* an input tuple group and updated for each input tuple.
|
||||
*
|
||||
* For a simple (non DISTINCT) aggregate, we just feed the input values
|
||||
* straight to the transition function. If it's DISTINCT, we pass
|
||||
* the input values into a Tuplesort object; then at completion of the
|
||||
* straight to the transition function. If it's DISTINCT, we pass the
|
||||
* input values into a Tuplesort object; then at completion of the
|
||||
* input tuple group, we scan the sorted values, eliminate duplicates,
|
||||
* and run the transition function on the rest.
|
||||
*/
|
||||
@@ -144,20 +144,21 @@ typedef struct AggStatePerAggData
|
||||
bool noTransValue; /* true if transValue not set yet */
|
||||
|
||||
/*
|
||||
* Note: noTransValue initially has the same value as transValueIsNull,
|
||||
* and if true both are cleared to false at the same time. They are
|
||||
* not the same though: if transfn later returns a NULL, we want to
|
||||
* keep that NULL and not auto-replace it with a later input value.
|
||||
* Only the first non-NULL input will be auto-substituted.
|
||||
* Note: noTransValue initially has the same value as
|
||||
* transValueIsNull, and if true both are cleared to false at the same
|
||||
* time. They are not the same though: if transfn later returns a
|
||||
* NULL, we want to keep that NULL and not auto-replace it with a
|
||||
* later input value. Only the first non-NULL input will be
|
||||
* auto-substituted.
|
||||
*/
|
||||
} AggStatePerAggData;
|
||||
|
||||
|
||||
static void initialize_aggregate(AggStatePerAgg peraggstate);
|
||||
static void advance_transition_function(AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull);
|
||||
Datum newVal, bool isNull);
|
||||
static void process_sorted_aggregate(AggState *aggstate,
|
||||
AggStatePerAgg peraggstate);
|
||||
AggStatePerAgg peraggstate);
|
||||
static void finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
|
||||
@@ -195,8 +196,8 @@ initialize_aggregate(AggStatePerAgg peraggstate)
|
||||
* (Re)set transValue to the initial value.
|
||||
*
|
||||
* Note that when the initial value is pass-by-ref, we just reuse it
|
||||
* without copying for each group. Hence, transition function
|
||||
* had better not scribble on its input, or it will fail for GROUP BY!
|
||||
* without copying for each group. Hence, transition function had
|
||||
* better not scribble on its input, or it will fail for GROUP BY!
|
||||
*/
|
||||
peraggstate->transValue = peraggstate->initValue;
|
||||
peraggstate->transValueIsNull = peraggstate->initValueIsNull;
|
||||
@@ -222,50 +223,55 @@ static void
|
||||
advance_transition_function(AggStatePerAgg peraggstate,
|
||||
Datum newVal, bool isNull)
|
||||
{
|
||||
FunctionCallInfoData fcinfo;
|
||||
FunctionCallInfoData fcinfo;
|
||||
|
||||
if (peraggstate->transfn.fn_strict)
|
||||
{
|
||||
if (isNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* For a strict transfn, nothing happens at a NULL input tuple;
|
||||
* we just keep the prior transValue. However, if the transtype
|
||||
* is pass-by-ref, we have to copy it into the new context
|
||||
* because the old one is going to get reset.
|
||||
* For a strict transfn, nothing happens at a NULL input
|
||||
* tuple; we just keep the prior transValue. However, if the
|
||||
* transtype is pass-by-ref, we have to copy it into the new
|
||||
* context because the old one is going to get reset.
|
||||
*/
|
||||
if (!peraggstate->transValueIsNull)
|
||||
peraggstate->transValue = datumCopy(peraggstate->transValue,
|
||||
peraggstate->transtypeByVal,
|
||||
peraggstate->transtypeLen);
|
||||
peraggstate->transtypeByVal,
|
||||
peraggstate->transtypeLen);
|
||||
return;
|
||||
}
|
||||
if (peraggstate->noTransValue)
|
||||
{
|
||||
|
||||
/*
|
||||
* transValue has not been initialized. This is the first non-NULL
|
||||
* input value. We use it as the initial value for transValue.
|
||||
* (We already checked that the agg's input type is binary-
|
||||
* compatible with its transtype, so straight copy here is OK.)
|
||||
* transValue has not been initialized. This is the first
|
||||
* non-NULL input value. We use it as the initial value for
|
||||
* transValue. (We already checked that the agg's input type
|
||||
* is binary- compatible with its transtype, so straight copy
|
||||
* here is OK.)
|
||||
*
|
||||
* We had better copy the datum if it is pass-by-ref, since
|
||||
* the given pointer may be pointing into a scan tuple that
|
||||
* will be freed on the next iteration of the scan.
|
||||
* We had better copy the datum if it is pass-by-ref, since the
|
||||
* given pointer may be pointing into a scan tuple that will
|
||||
* be freed on the next iteration of the scan.
|
||||
*/
|
||||
peraggstate->transValue = datumCopy(newVal,
|
||||
peraggstate->transtypeByVal,
|
||||
peraggstate->transtypeLen);
|
||||
peraggstate->transtypeByVal,
|
||||
peraggstate->transtypeLen);
|
||||
peraggstate->transValueIsNull = false;
|
||||
peraggstate->noTransValue = false;
|
||||
return;
|
||||
}
|
||||
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 transfn
|
||||
* is strict *and* returned a NULL on a prior cycle. If that
|
||||
* happens we will propagate the NULL all the way to the end.
|
||||
* possible to get here despite the above tests, if the
|
||||
* transfn is strict *and* returned a NULL on a prior cycle.
|
||||
* If that happens we will propagate the NULL all the way to
|
||||
* the end.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
@@ -283,14 +289,14 @@ advance_transition_function(AggStatePerAgg peraggstate,
|
||||
newVal = FunctionCallInvoke(&fcinfo);
|
||||
|
||||
/*
|
||||
* If the transition function was uncooperative, it may have
|
||||
* given us a pass-by-ref result that points at the scan tuple
|
||||
* or the prior-cycle working memory. Copy it into the active
|
||||
* context if it doesn't look right.
|
||||
* If the transition function was uncooperative, it may have given us
|
||||
* a pass-by-ref result that points at the scan tuple or the
|
||||
* prior-cycle working memory. Copy it into the active context if it
|
||||
* doesn't look right.
|
||||
*/
|
||||
if (!peraggstate->transtypeByVal && !fcinfo.isnull &&
|
||||
! MemoryContextContains(CurrentMemoryContext,
|
||||
DatumGetPointer(newVal)))
|
||||
!MemoryContextContains(CurrentMemoryContext,
|
||||
DatumGetPointer(newVal)))
|
||||
newVal = datumCopy(newVal,
|
||||
peraggstate->transtypeByVal,
|
||||
peraggstate->transtypeLen);
|
||||
@@ -302,7 +308,7 @@ advance_transition_function(AggStatePerAgg peraggstate,
|
||||
/*
|
||||
* Run the transition function for a DISTINCT aggregate. This is called
|
||||
* after we have completed entering all the input values into the sort
|
||||
* object. We complete the sort, read out the values in sorted order,
|
||||
* object. We complete the sort, read out the values in sorted order,
|
||||
* and run the transition function on each non-duplicate value.
|
||||
*
|
||||
* When called, CurrentMemoryContext should be the per-query context.
|
||||
@@ -321,19 +327,21 @@ process_sorted_aggregate(AggState *aggstate,
|
||||
|
||||
/*
|
||||
* Note: if input type is pass-by-ref, the datums returned by the sort
|
||||
* are freshly palloc'd in the per-query context, so we must be careful
|
||||
* to pfree them when they are no longer needed.
|
||||
* are freshly palloc'd in the per-query context, so we must be
|
||||
* careful to pfree them when they are no longer needed.
|
||||
*/
|
||||
|
||||
while (tuplesort_getdatum(peraggstate->sortstate, true,
|
||||
&newVal, &isNull))
|
||||
{
|
||||
|
||||
/*
|
||||
* DISTINCT always suppresses nulls, per SQL spec, regardless of
|
||||
* the transition function's strictness.
|
||||
*/
|
||||
if (isNull)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Clear and select the current working context for evaluation of
|
||||
* the equality function and transition function.
|
||||
@@ -349,6 +357,7 @@ process_sorted_aggregate(AggState *aggstate,
|
||||
/* equal to prior, so forget this one */
|
||||
if (!peraggstate->inputtypeByVal)
|
||||
pfree(DatumGetPointer(newVal));
|
||||
|
||||
/*
|
||||
* note we do NOT flip contexts in this case, so no need to
|
||||
* copy prior transValue to other context.
|
||||
@@ -357,6 +366,7 @@ process_sorted_aggregate(AggState *aggstate,
|
||||
else
|
||||
{
|
||||
advance_transition_function(peraggstate, newVal, false);
|
||||
|
||||
/*
|
||||
* Make the other context current so that this transition
|
||||
* result is preserved.
|
||||
@@ -389,12 +399,13 @@ static void
|
||||
finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull)
|
||||
{
|
||||
|
||||
/*
|
||||
* Apply the agg's finalfn if one is provided, else return transValue.
|
||||
*/
|
||||
if (OidIsValid(peraggstate->finalfn_oid))
|
||||
{
|
||||
FunctionCallInfoData fcinfo;
|
||||
FunctionCallInfoData fcinfo;
|
||||
|
||||
MemSet(&fcinfo, 0, sizeof(fcinfo));
|
||||
fcinfo.flinfo = &peraggstate->finalfn;
|
||||
@@ -422,9 +433,9 @@ finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
/*
|
||||
* If result is pass-by-ref, make sure it is in the right context.
|
||||
*/
|
||||
if (!peraggstate->resulttypeByVal && ! *resultIsNull &&
|
||||
! MemoryContextContains(CurrentMemoryContext,
|
||||
DatumGetPointer(*resultVal)))
|
||||
if (!peraggstate->resulttypeByVal && !*resultIsNull &&
|
||||
!MemoryContextContains(CurrentMemoryContext,
|
||||
DatumGetPointer(*resultVal)))
|
||||
*resultVal = datumCopy(*resultVal,
|
||||
peraggstate->resulttypeByVal,
|
||||
peraggstate->resulttypeLen);
|
||||
@@ -480,7 +491,8 @@ ExecAgg(Agg *node)
|
||||
peragg = aggstate->peragg;
|
||||
|
||||
/*
|
||||
* We loop retrieving groups until we find one matching node->plan.qual
|
||||
* We loop retrieving groups until we find one matching
|
||||
* node->plan.qual
|
||||
*/
|
||||
do
|
||||
{
|
||||
@@ -578,19 +590,19 @@ ExecAgg(Agg *node)
|
||||
* calculation, and stash results in the per-output-tuple context.
|
||||
*
|
||||
* This is a bit tricky when there are both DISTINCT and plain
|
||||
* aggregates: we must first finalize all the plain aggs and then all
|
||||
* the DISTINCT ones. This is needed because the last transition
|
||||
* values for the plain aggs are stored in the not-current working
|
||||
* context, and we have to evaluate those aggs (and stash the results
|
||||
* in the output tup_cxt!) before we start flipping contexts again
|
||||
* in process_sorted_aggregate.
|
||||
* aggregates: we must first finalize all the plain aggs and then
|
||||
* all the DISTINCT ones. This is needed because the last
|
||||
* transition values for the plain aggs are stored in the
|
||||
* not-current working context, and we have to evaluate those aggs
|
||||
* (and stash the results in the output tup_cxt!) before we start
|
||||
* flipping contexts again in process_sorted_aggregate.
|
||||
*/
|
||||
oldContext = MemoryContextSwitchTo(aggstate->tup_cxt);
|
||||
for (aggno = 0; aggno < aggstate->numaggs; aggno++)
|
||||
{
|
||||
AggStatePerAgg peraggstate = &peragg[aggno];
|
||||
|
||||
if (! peraggstate->aggref->aggdistinct)
|
||||
if (!peraggstate->aggref->aggdistinct)
|
||||
finalize_aggregate(peraggstate,
|
||||
&aggvalues[aggno], &aggnulls[aggno]);
|
||||
}
|
||||
@@ -766,21 +778,22 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
ExecAssignExprContext(estate, &aggstate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* We actually need three separate expression memory contexts: one
|
||||
* for calculating per-output-tuple values (ie, the finished aggregate
|
||||
* We actually need three separate expression memory contexts: one for
|
||||
* calculating per-output-tuple values (ie, the finished aggregate
|
||||
* results), and two that we ping-pong between for per-input-tuple
|
||||
* evaluation of input expressions and transition functions. The
|
||||
* context made by ExecAssignExprContext() is used as the output context.
|
||||
* context made by ExecAssignExprContext() is used as the output
|
||||
* context.
|
||||
*/
|
||||
aggstate->tup_cxt =
|
||||
aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory;
|
||||
aggstate->agg_cxt[0] =
|
||||
aggstate->agg_cxt[0] =
|
||||
AllocSetContextCreate(CurrentMemoryContext,
|
||||
"AggExprContext1",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
aggstate->agg_cxt[1] =
|
||||
aggstate->agg_cxt[1] =
|
||||
AllocSetContextCreate(CurrentMemoryContext,
|
||||
"AggExprContext2",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
@@ -882,30 +895,32 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
||||
/*
|
||||
* If the transfn is strict and the initval is NULL, make sure
|
||||
* input type and transtype are the same (or at least binary-
|
||||
* compatible), so that it's OK to use the first input value
|
||||
* as the initial transValue. This should have been checked at
|
||||
* agg definition time, but just in case...
|
||||
* compatible), so that it's OK to use the first input value as
|
||||
* the initial transValue. This should have been checked at agg
|
||||
* definition time, but just in case...
|
||||
*/
|
||||
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.
|
||||
* Note: use the type from the input expression here, not
|
||||
* aggform->aggbasetype, because the latter might be 0.
|
||||
* (Consider COUNT(*).)
|
||||
*/
|
||||
Oid inputType = exprType(aggref->target);
|
||||
|
||||
if (inputType != aggform->aggtranstype &&
|
||||
! IS_BINARY_COMPATIBLE(inputType, aggform->aggtranstype))
|
||||
!IS_BINARY_COMPATIBLE(inputType, aggform->aggtranstype))
|
||||
elog(ERROR, "Aggregate %s needs to have compatible input type and transition type",
|
||||
aggname);
|
||||
}
|
||||
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
|
||||
/*
|
||||
* Note: use the type from the input expression here,
|
||||
* not aggform->aggbasetype, because the latter might be 0.
|
||||
* Note: use the type from the input expression here, not
|
||||
* aggform->aggbasetype, because the latter might be 0.
|
||||
* (Consider COUNT(*).)
|
||||
*/
|
||||
Oid inputType = exprType(aggref->target);
|
||||
@@ -947,12 +962,14 @@ ExecEndAgg(Agg *node)
|
||||
Plan *outerPlan;
|
||||
|
||||
ExecFreeProjectionInfo(&aggstate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* Make sure ExecFreeExprContext() frees the right expr context...
|
||||
*/
|
||||
aggstate->csstate.cstate.cs_ExprContext->ecxt_per_tuple_memory =
|
||||
aggstate->tup_cxt;
|
||||
ExecFreeExprContext(&aggstate->csstate.cstate);
|
||||
|
||||
/*
|
||||
* ... and I free the others.
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* locate group boundaries.
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.41 2001/02/16 03:16:57 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeGroup.c,v 1.42 2001/03/22 03:59:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -88,8 +88,8 @@ ExecGroupEveryTuple(Group *node)
|
||||
tupdesc = ExecGetScanType(&grpstate->csstate);
|
||||
|
||||
/*
|
||||
* We need not call ResetExprContext here because execTuplesMatch
|
||||
* will reset the per-tuple memory context once per input tuple.
|
||||
* We need not call ResetExprContext here because execTuplesMatch will
|
||||
* reset the per-tuple memory context once per input tuple.
|
||||
*/
|
||||
|
||||
/* if we haven't returned first tuple of a new group yet ... */
|
||||
@@ -199,8 +199,8 @@ ExecGroupOneTuple(Group *node)
|
||||
tupdesc = ExecGetScanType(&grpstate->csstate);
|
||||
|
||||
/*
|
||||
* We need not call ResetExprContext here because execTuplesMatch
|
||||
* will reset the per-tuple memory context once per input tuple.
|
||||
* We need not call ResetExprContext here because execTuplesMatch will
|
||||
* reset the per-tuple memory context once per input tuple.
|
||||
*/
|
||||
|
||||
firsttuple = grpstate->grp_firstTuple;
|
||||
@@ -465,8 +465,8 @@ execTuplesMatch(HeapTuple tuple1,
|
||||
|
||||
/* Apply the type-specific equality function */
|
||||
|
||||
if (! DatumGetBool(FunctionCall2(&eqfunctions[i],
|
||||
attr1, attr2)))
|
||||
if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
|
||||
attr1, attr2)))
|
||||
{
|
||||
result = false; /* they aren't equal */
|
||||
break;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $Id: nodeHash.c,v 1.54 2001/01/24 19:42:54 momjian Exp $
|
||||
* $Id: nodeHash.c,v 1.55 2001/03/22 03:59:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -540,9 +540,7 @@ ExecHashGetBucket(HashJoinTable hashtable,
|
||||
* ------------------
|
||||
*/
|
||||
if (isNull)
|
||||
{
|
||||
bucketno = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bucketno = hashFunc(keyval,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.36 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.37 2001/03/22 03:59:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -105,7 +105,7 @@ ExecHashJoin(HashJoin *node)
|
||||
|
||||
/* ----------------
|
||||
* Reset per-tuple memory context to free any expression evaluation
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* happen until we're done projecting out tuples from a join tuple.
|
||||
* ----------------
|
||||
*/
|
||||
@@ -155,6 +155,7 @@ ExecHashJoin(HashJoin *node)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we don't have an outer tuple, get the next one
|
||||
*/
|
||||
@@ -276,14 +277,15 @@ ExecHashJoin(HashJoin *node)
|
||||
*/
|
||||
hjstate->hj_NeedNewOuter = true;
|
||||
|
||||
if (! hjstate->hj_MatchedOuter &&
|
||||
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
|
||||
* nulls for the inner tuple, and return it if it passes
|
||||
* the non-join quals.
|
||||
* nulls for the inner tuple, and return it if it passes the
|
||||
* non-join quals.
|
||||
*/
|
||||
econtext->ecxt_innertuple = hjstate->hj_NullInnerTupleSlot;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.57 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.58 2001/03/22 03:59:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -224,7 +224,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);
|
||||
}
|
||||
@@ -326,7 +326,8 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
|
||||
estate = node->scan.plan.state;
|
||||
indexstate = node->indxstate;
|
||||
econtext = indexstate->iss_RuntimeContext; /* context for runtime keys */
|
||||
econtext = indexstate->iss_RuntimeContext; /* context for runtime
|
||||
* keys */
|
||||
direction = estate->es_direction;
|
||||
numIndices = indexstate->iss_NumIndices;
|
||||
scanDescs = indexstate->iss_ScanDescs;
|
||||
@@ -340,16 +341,18 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
|
||||
if (econtext)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we are being passed an outer tuple,
|
||||
* save it for runtime key calc
|
||||
* If we are being passed an outer tuple, save it for runtime key
|
||||
* calc
|
||||
*/
|
||||
if (exprCtxt != NULL)
|
||||
econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
|
||||
|
||||
/*
|
||||
* Reset the runtime-key context so we don't leak memory as
|
||||
* each outer tuple is scanned. Note this assumes that we
|
||||
* will recalculate *all* runtime keys on each call.
|
||||
* Reset the runtime-key context so we don't leak memory as each
|
||||
* outer tuple is scanned. Note this assumes that we will
|
||||
* recalculate *all* runtime keys on each call.
|
||||
*/
|
||||
ResetExprContext(econtext);
|
||||
}
|
||||
@@ -385,8 +388,8 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent)
|
||||
* outer tuple. We then stick the result into the scan
|
||||
* key.
|
||||
*
|
||||
* Note: the result of the eval could be a pass-by-ref
|
||||
* value that's stored in the outer scan's tuple, not in
|
||||
* Note: the result of the eval could be a pass-by-ref value
|
||||
* that's stored in the outer scan's tuple, not in
|
||||
* econtext->ecxt_per_tuple_memory. We assume that the
|
||||
* outer tuple will stay put throughout our scan. If this
|
||||
* is wrong, we could copy the result into our context
|
||||
@@ -790,7 +793,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
|
||||
Assert(leftop != NULL);
|
||||
|
||||
if (IsA(leftop, Var) && var_is_rel((Var *) leftop))
|
||||
if (IsA(leftop, Var) &&var_is_rel((Var *) leftop))
|
||||
{
|
||||
/* ----------------
|
||||
* if the leftop is a "rel-var", then it means
|
||||
@@ -862,7 +865,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
|
||||
Assert(rightop != NULL);
|
||||
|
||||
if (IsA(rightop, Var) && var_is_rel((Var *) rightop))
|
||||
if (IsA(rightop, Var) &&var_is_rel((Var *) rightop))
|
||||
{
|
||||
/* ----------------
|
||||
* here we make sure only one op identifies the
|
||||
@@ -986,7 +989,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent)
|
||||
*/
|
||||
if (have_runtime_keys)
|
||||
{
|
||||
ExprContext *stdecontext = scanstate->cstate.cs_ExprContext;
|
||||
ExprContext *stdecontext = scanstate->cstate.cs_ExprContext;
|
||||
|
||||
ExecAssignExprContext(estate, &scanstate->cstate);
|
||||
indexstate->iss_RuntimeKeyInfo = runtimeKeyInfo;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.3 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.4 2001/03/22 03:59:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -59,7 +59,7 @@ ExecLimit(Limit *node)
|
||||
* may not be set until now.)
|
||||
* ----------------
|
||||
*/
|
||||
if (! limitstate->parmsSet)
|
||||
if (!limitstate->parmsSet)
|
||||
recompute_limits(node);
|
||||
netlimit = limitstate->offset + limitstate->count;
|
||||
|
||||
@@ -89,7 +89,7 @@ ExecLimit(Limit *node)
|
||||
{
|
||||
if (limitstate->atEnd)
|
||||
return NULL;
|
||||
if (! limitstate->noCount && limitstate->position > netlimit)
|
||||
if (!limitstate->noCount && limitstate->position > netlimit)
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
@@ -104,13 +104,14 @@ 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.
|
||||
*/
|
||||
if (ScanDirectionIsForward(direction))
|
||||
{
|
||||
Assert(! limitstate->atEnd);
|
||||
Assert(!limitstate->atEnd);
|
||||
/* must bump position to stay in sync for backwards fetch */
|
||||
limitstate->position++;
|
||||
limitstate->atEnd = true;
|
||||
@@ -122,6 +123,7 @@ ExecLimit(Limit *node)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We got the next subplan tuple successfully, so adjust state.
|
||||
*/
|
||||
@@ -135,7 +137,7 @@ ExecLimit(Limit *node)
|
||||
limitstate->atEnd = false;
|
||||
|
||||
/* ----------------
|
||||
* Now, is this a tuple we want? If not, loop around to fetch
|
||||
* Now, is this a tuple we want? If not, loop around to fetch
|
||||
* another tuple from the subplan.
|
||||
* ----------------
|
||||
*/
|
||||
@@ -185,9 +187,9 @@ recompute_limits(Limit *node)
|
||||
if (node->limitCount)
|
||||
{
|
||||
limitstate->count = DatumGetInt32(ExecEvalExpr(node->limitCount,
|
||||
econtext,
|
||||
&isNull,
|
||||
NULL));
|
||||
econtext,
|
||||
&isNull,
|
||||
NULL));
|
||||
/* Interpret NULL count as no count (LIMIT ALL) */
|
||||
if (isNull)
|
||||
limitstate->noCount = true;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.33 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.34 2001/03/22 03:59:28 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -31,7 +31,7 @@
|
||||
*
|
||||
* The first time this is called, ExecMaterial retrieves tuples
|
||||
* from this node's outer subplan and inserts them into a tuplestore
|
||||
* (a temporary tuple storage structure). The first tuple is then
|
||||
* (a temporary tuple storage structure). The first tuple is then
|
||||
* returned. Successive calls to ExecMaterial return successive
|
||||
* tuples from the tuplestore.
|
||||
*
|
||||
@@ -85,7 +85,7 @@ ExecMaterial(Material *node)
|
||||
* Initialize tuplestore module.
|
||||
* ----------------
|
||||
*/
|
||||
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
||||
tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
|
||||
SortMem);
|
||||
|
||||
matstate->tuplestorestate = (void *) tuplestorestate;
|
||||
@@ -250,7 +250,7 @@ ExecEndMaterial(Material *node)
|
||||
void
|
||||
ExecMaterialMarkPos(Material *node)
|
||||
{
|
||||
MaterialState *matstate = node->matstate;
|
||||
MaterialState *matstate = node->matstate;
|
||||
|
||||
/* ----------------
|
||||
* if we haven't materialized yet, just return.
|
||||
@@ -271,7 +271,7 @@ ExecMaterialMarkPos(Material *node)
|
||||
void
|
||||
ExecMaterialRestrPos(Material *node)
|
||||
{
|
||||
MaterialState *matstate = node->matstate;
|
||||
MaterialState *matstate = node->matstate;
|
||||
|
||||
/* ----------------
|
||||
* if we haven't materialized yet, just return.
|
||||
@@ -299,8 +299,8 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
||||
MaterialState *matstate = node->matstate;
|
||||
|
||||
/*
|
||||
* If we haven't materialized yet, just return. If outerplan' chgParam is
|
||||
* not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||
* If we haven't materialized yet, just return. If outerplan' chgParam
|
||||
* is not NULL then it will be re-scanned by ExecProcNode, else - no
|
||||
* reason to re-scan it at all.
|
||||
*/
|
||||
if (!matstate->tuplestorestate)
|
||||
@@ -309,8 +309,8 @@ ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
|
||||
ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
|
||||
|
||||
/*
|
||||
* If subnode is to be rescanned then we forget previous stored results;
|
||||
* we have to re-read the subplan and re-store.
|
||||
* If subnode is to be rescanned then we forget previous stored
|
||||
* results; we have to re-read the subplan and re-store.
|
||||
*
|
||||
* Otherwise we can just rewind and rescan the stored output.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.42 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.43 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -169,7 +169,7 @@ MJFormSkipQual(List *qualList, char *replaceopname)
|
||||
CharGetDatum('b'));
|
||||
if (!HeapTupleIsValid(optup))
|
||||
elog(ERROR,
|
||||
"MJFormSkipQual: mergejoin operator %u has no matching %s op",
|
||||
"MJFormSkipQual: mergejoin operator %u has no matching %s op",
|
||||
op->opno, replaceopname);
|
||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||
|
||||
@@ -258,7 +258,7 @@ MergeCompare(List *eqQual, List *compareQual, ExprContext *econtext)
|
||||
&isNull,
|
||||
NULL);
|
||||
|
||||
if (! DatumGetBool(const_value) || isNull)
|
||||
if (!DatumGetBool(const_value) || isNull)
|
||||
break; /* return false */
|
||||
|
||||
eqclause = lnext(eqclause);
|
||||
@@ -439,7 +439,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;
|
||||
}
|
||||
@@ -464,7 +464,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
if (mergestate->jstate.cs_TupFromTlist)
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
ExprDoneCond isDone;
|
||||
ExprDoneCond isDone;
|
||||
|
||||
result = ExecProject(mergestate->jstate.cs_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
@@ -475,7 +475,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
/* ----------------
|
||||
* Reset per-tuple memory context to free any expression evaluation
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* happen until we're done projecting out tuples from a join tuple.
|
||||
* ----------------
|
||||
*/
|
||||
@@ -500,9 +500,9 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
/*
|
||||
* EXEC_MJ_INITIALIZE means that this is the first time
|
||||
* ExecMergeJoin() has been called and so we have to
|
||||
* fetch the first tuple for both outer and inner subplans.
|
||||
* If we fail to get a tuple here, then that subplan is
|
||||
* ExecMergeJoin() has been called and so we have to fetch
|
||||
* the first tuple for both outer and inner subplans. If
|
||||
* we fail to get a tuple here, then that subplan is
|
||||
* empty, and we either end the join or go to one of the
|
||||
* fill-remaining-tuples states.
|
||||
*/
|
||||
@@ -516,6 +516,7 @@ 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
|
||||
@@ -536,11 +537,13 @@ 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 set
|
||||
* MatchedOuter = false to force the ENDINNER state
|
||||
* to emit this tuple before advancing outer.
|
||||
* Need to emit left-join tuples for all outer
|
||||
* tuples, including the one we just fetched. We
|
||||
* set MatchedOuter = false to force the ENDINNER
|
||||
* state to emit this tuple before advancing
|
||||
* outer.
|
||||
*/
|
||||
mergestate->mj_JoinState = EXEC_MJ_ENDINNER;
|
||||
mergestate->mj_MatchedOuter = false;
|
||||
@@ -614,17 +617,17 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
/*
|
||||
* Check the extra qual conditions to see if we actually
|
||||
* want to return this join tuple. If not, can proceed with
|
||||
* merge. We must distinguish the additional joinquals
|
||||
* (which must pass to consider the tuples "matched" for
|
||||
* outer-join logic) from the otherquals (which must pass
|
||||
* before we actually return the tuple).
|
||||
* want to return this join tuple. If not, can proceed
|
||||
* with merge. We must distinguish the additional
|
||||
* joinquals (which must pass to consider the tuples
|
||||
* "matched" for outer-join logic) from the otherquals
|
||||
* (which must pass before we actually return the tuple).
|
||||
*
|
||||
* We don't bother with a ResetExprContext here, on the
|
||||
* assumption that we just did one before checking the merge
|
||||
* qual. One per tuple should be sufficient. Also, the
|
||||
* econtext's tuple pointers were set up before checking
|
||||
* the merge qual, so we needn't do it again.
|
||||
* assumption that we just did one before checking the
|
||||
* merge qual. One per tuple should be sufficient. Also,
|
||||
* the econtext's tuple pointers were set up before
|
||||
* checking the merge qual, so we needn't do it again.
|
||||
*/
|
||||
qualResult = (joinqual == NIL ||
|
||||
ExecQual(joinqual, econtext, false));
|
||||
@@ -677,11 +680,13 @@ 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 quals.
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -753,11 +758,13 @@ 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 quals.
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -810,6 +817,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples.
|
||||
@@ -879,19 +887,20 @@ ExecMergeJoin(MergeJoin *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* the merge clause matched so now we restore the inner
|
||||
* scan position to the first mark, and loop back to
|
||||
* JOINTEST. Actually, since we know the mergeclause
|
||||
* matches, we can skip JOINTEST and go straight to
|
||||
* JOINTUPLES.
|
||||
* the merge clause matched so now we restore the
|
||||
* inner scan position to the first mark, and loop
|
||||
* back to JOINTEST. Actually, since we know the
|
||||
* mergeclause matches, we can skip JOINTEST and go
|
||||
* straight to JOINTUPLES.
|
||||
*
|
||||
* NOTE: we do not need to worry about the MatchedInner
|
||||
* state for the rescanned inner tuples. We know all
|
||||
* of them will match this new outer tuple and therefore
|
||||
* won't be emitted as fill tuples. This works *only*
|
||||
* because we require the extra joinquals to be nil when
|
||||
* doing a right or full join --- otherwise some of the
|
||||
* rescanned tuples might fail the extra joinquals.
|
||||
* of them will match this new outer tuple and
|
||||
* therefore won't be emitted as fill tuples. This
|
||||
* works *only* because we require the extra joinquals
|
||||
* to be nil when doing a right or full join ---
|
||||
* otherwise some of the rescanned tuples might fail
|
||||
* the extra joinquals.
|
||||
*/
|
||||
ExecRestrPos(innerPlan);
|
||||
mergestate->mj_JoinState = EXEC_MJ_JOINTUPLES;
|
||||
@@ -918,6 +927,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
{
|
||||
if (doFillOuter)
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit left-join tuples for remaining
|
||||
* outer tuples.
|
||||
@@ -1044,11 +1054,13 @@ 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 quals.
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -1101,6 +1113,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
innerTupleSlot = mergestate->mj_InnerTupleSlot;
|
||||
if (doFillInner && !TupIsNull(innerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit right-join tuples for remaining
|
||||
* inner tuples.
|
||||
@@ -1229,11 +1242,13 @@ 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 quals.
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -1286,6 +1301,7 @@ ExecMergeJoin(MergeJoin *node)
|
||||
outerTupleSlot = mergestate->mj_OuterTupleSlot;
|
||||
if (doFillOuter && !TupIsNull(outerTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* Need to emit left-join tuples for remaining
|
||||
* outer tuples.
|
||||
@@ -1306,8 +1322,8 @@ ExecMergeJoin(MergeJoin *node)
|
||||
|
||||
/*
|
||||
* EXEC_MJ_ENDOUTER means we have run out of outer tuples,
|
||||
* but are doing a right/full join and therefore must null-
|
||||
* fill any remaing unmatched inner tuples.
|
||||
* but are doing a right/full join and therefore must
|
||||
* null- fill any remaing unmatched inner tuples.
|
||||
*/
|
||||
case EXEC_MJ_ENDOUTER:
|
||||
MJ_printf("ExecMergeJoin: EXEC_MJ_ENDOUTER\n");
|
||||
@@ -1316,11 +1332,13 @@ 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 quals.
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
mergestate->mj_MatchedInner = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -1383,11 +1401,13 @@ 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 quals.
|
||||
* tuple, and return it if it passes the non-join
|
||||
* quals.
|
||||
*/
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
mergestate->mj_MatchedOuter = true; /* do it only once */
|
||||
|
||||
ResetExprContext(econtext);
|
||||
|
||||
@@ -1515,14 +1535,16 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
||||
case JOIN_LEFT:
|
||||
mergestate->mj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(innerPlan((Plan*) node)));
|
||||
ExecGetTupType(innerPlan((Plan *) node)));
|
||||
break;
|
||||
case JOIN_RIGHT:
|
||||
mergestate->mj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(outerPlan((Plan*) node)));
|
||||
ExecGetTupType(outerPlan((Plan *) node)));
|
||||
|
||||
/*
|
||||
* Can't handle right or full join with non-nil extra joinclauses.
|
||||
* Can't handle right or full join with non-nil extra
|
||||
* joinclauses.
|
||||
*/
|
||||
if (node->join.joinqual != NIL)
|
||||
elog(ERROR, "RIGHT JOIN is only supported with mergejoinable join conditions");
|
||||
@@ -1530,12 +1552,14 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent)
|
||||
case JOIN_FULL:
|
||||
mergestate->mj_NullOuterTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(outerPlan((Plan*) node)));
|
||||
ExecGetTupType(outerPlan((Plan *) node)));
|
||||
mergestate->mj_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(innerPlan((Plan*) node)));
|
||||
ExecGetTupType(innerPlan((Plan *) node)));
|
||||
|
||||
/*
|
||||
* Can't handle right or full join with non-nil extra joinclauses.
|
||||
* Can't handle right or full join with non-nil extra
|
||||
* joinclauses.
|
||||
*/
|
||||
if (node->join.joinqual != NIL)
|
||||
elog(ERROR, "FULL JOIN is only supported with mergejoinable join conditions");
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.22 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeNestloop.c,v 1.23 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -97,7 +97,7 @@ ExecNestLoop(NestLoop *node)
|
||||
if (nlstate->jstate.cs_TupFromTlist)
|
||||
{
|
||||
TupleTableSlot *result;
|
||||
ExprDoneCond isDone;
|
||||
ExprDoneCond isDone;
|
||||
|
||||
result = ExecProject(nlstate->jstate.cs_ProjInfo, &isDone);
|
||||
if (isDone == ExprMultipleResult)
|
||||
@@ -108,7 +108,7 @@ ExecNestLoop(NestLoop *node)
|
||||
|
||||
/* ----------------
|
||||
* Reset per-tuple memory context to free any expression evaluation
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* happen until we're done projecting out tuples from a join tuple.
|
||||
* ----------------
|
||||
*/
|
||||
@@ -179,14 +179,15 @@ ExecNestLoop(NestLoop *node)
|
||||
|
||||
nlstate->nl_NeedNewOuter = true;
|
||||
|
||||
if (! nlstate->nl_MatchedOuter &&
|
||||
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 tuple with
|
||||
* nulls for the inner tuple, and return it if it passes
|
||||
* the non-join quals.
|
||||
* We are doing an outer join and there were no join
|
||||
* matches for this outer tuple. Generate a fake join
|
||||
* tuple with nulls for the inner tuple, and return it if
|
||||
* it passes the non-join quals.
|
||||
*/
|
||||
econtext->ecxt_innertuple = nlstate->nl_NullInnerTupleSlot;
|
||||
|
||||
@@ -215,6 +216,7 @@ ExecNestLoop(NestLoop *node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise just return to top of loop for a new outer tuple.
|
||||
*/
|
||||
@@ -328,7 +330,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, Plan *parent)
|
||||
case JOIN_LEFT:
|
||||
nlstate->nl_NullInnerTupleSlot =
|
||||
ExecInitNullTupleSlot(estate,
|
||||
ExecGetTupType(innerPlan((Plan*) node)));
|
||||
ExecGetTupType(innerPlan((Plan *) node)));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "ExecInitNestLoop: unsupported join type %d",
|
||||
|
||||
@@ -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.17 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeResult.c,v 1.18 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -111,7 +111,7 @@ ExecResult(Result *node)
|
||||
|
||||
/* ----------------
|
||||
* Reset per-tuple memory context to free any expression evaluation
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* storage allocated in the previous tuple cycle. Note this can't
|
||||
* happen until we're done projecting out tuples from a scan tuple.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.27 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.28 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
static Oid InitScanRelation(SeqScan *node, EState *estate,
|
||||
CommonScanState *scanstate);
|
||||
CommonScanState *scanstate);
|
||||
static TupleTableSlot *SeqNext(SeqScan *node);
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
@@ -174,8 +174,8 @@ InitScanRelation(SeqScan *node, EState *estate,
|
||||
0, /* is index */
|
||||
direction, /* scan direction */
|
||||
estate->es_snapshot,
|
||||
¤tRelation, /* return: rel desc */
|
||||
(Pointer *) ¤tScanDesc); /* return: scan desc */
|
||||
¤tRelation, /* return: rel desc */
|
||||
(Pointer *) ¤tScanDesc); /* return: scan desc */
|
||||
|
||||
scanstate->css_currentRelation = currentRelation;
|
||||
scanstate->css_currentScanDesc = currentScanDesc;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* The input of a SetOp node consists of tuples from two relations,
|
||||
* which have been combined into one dataset and sorted on all the nonjunk
|
||||
* attributes. In addition there is a junk attribute that shows which
|
||||
* attributes. In addition there is a junk attribute that shows which
|
||||
* relation each tuple came from. The SetOp node scans each group of
|
||||
* identical tuples to determine how many came from each input relation.
|
||||
* Then it is a simple matter to emit the output demanded by the SQL spec
|
||||
@@ -21,7 +21,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.2 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSetOp.c,v 1.3 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -93,7 +93,7 @@ ExecSetOp(SetOp *node)
|
||||
* ----------------
|
||||
*/
|
||||
if (setopstate->cstate.cs_OuterTupleSlot == NULL &&
|
||||
! setopstate->subplan_done)
|
||||
!setopstate->subplan_done)
|
||||
{
|
||||
setopstate->cstate.cs_OuterTupleSlot =
|
||||
ExecProcNode(outerPlan, (Plan *) node);
|
||||
@@ -104,6 +104,7 @@ ExecSetOp(SetOp *node)
|
||||
|
||||
if (TupIsNull(resultTupleSlot))
|
||||
{
|
||||
|
||||
/*
|
||||
* First of group: save a copy in result slot, and reset
|
||||
* duplicate-counters for new group.
|
||||
@@ -113,13 +114,15 @@ ExecSetOp(SetOp *node)
|
||||
ExecStoreTuple(heap_copytuple(inputTupleSlot->val),
|
||||
resultTupleSlot,
|
||||
InvalidBuffer,
|
||||
true); /* free copied tuple at ExecClearTuple */
|
||||
true); /* free copied tuple at
|
||||
* ExecClearTuple */
|
||||
setopstate->numLeft = 0;
|
||||
setopstate->numRight = 0;
|
||||
endOfGroup = false;
|
||||
}
|
||||
else if (setopstate->subplan_done)
|
||||
{
|
||||
|
||||
/*
|
||||
* Reached end of input, so finish processing final group
|
||||
*/
|
||||
@@ -127,8 +130,10 @@ ExecSetOp(SetOp *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Else test if the new tuple and the previously saved tuple match.
|
||||
* Else test if the new tuple and the previously saved tuple
|
||||
* match.
|
||||
*/
|
||||
if (execTuplesMatch(inputTupleSlot->val,
|
||||
resultTupleSlot->val,
|
||||
@@ -143,6 +148,7 @@ 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
|
||||
@@ -185,12 +191,13 @@ ExecSetOp(SetOp *node)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Current tuple is member of same group as resultTuple.
|
||||
* Count it in the appropriate counter.
|
||||
* Current tuple is member of same group as resultTuple. Count
|
||||
* it in the appropriate counter.
|
||||
*/
|
||||
int flag;
|
||||
bool isNull;
|
||||
int flag;
|
||||
bool isNull;
|
||||
|
||||
flag = DatumGetInt32(heap_getattr(inputTupleSlot->val,
|
||||
node->flagColIdx,
|
||||
@@ -207,8 +214,8 @@ ExecSetOp(SetOp *node)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we fall out of loop, then we need to emit at least one copy
|
||||
* of resultTuple.
|
||||
* If we fall out of loop, then we need to emit at least one copy of
|
||||
* resultTuple.
|
||||
*/
|
||||
Assert(setopstate->numOutput > 0);
|
||||
setopstate->numOutput--;
|
||||
|
||||
@@ -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.29 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.30 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -102,7 +102,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
{
|
||||
HeapTuple tup = slot->val;
|
||||
TupleDesc tdesc = slot->ttc_tupleDescriptor;
|
||||
Datum rowresult = BoolGetDatum(! useor);
|
||||
Datum rowresult = BoolGetDatum(!useor);
|
||||
bool rownull = false;
|
||||
int col = 1;
|
||||
|
||||
@@ -213,7 +213,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
/* combine within row per AND semantics */
|
||||
if (expnull)
|
||||
rownull = true;
|
||||
else if (! DatumGetBool(expresult))
|
||||
else if (!DatumGetBool(expresult))
|
||||
{
|
||||
rowresult = BoolGetDatum(false);
|
||||
rownull = false;
|
||||
@@ -240,7 +240,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull)
|
||||
/* combine across rows per AND semantics */
|
||||
if (rownull)
|
||||
*isNull = true;
|
||||
else if (! DatumGetBool(rowresult))
|
||||
else if (!DatumGetBool(rowresult))
|
||||
{
|
||||
result = BoolGetDatum(false);
|
||||
*isNull = false;
|
||||
@@ -332,7 +332,7 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent)
|
||||
*
|
||||
* This is called from ExecEvalParam() when the value of a PARAM_EXEC
|
||||
* parameter is requested and the param's execPlan field is set (indicating
|
||||
* that the param has not yet been evaluated). This allows lazy evaluation
|
||||
* that the param has not yet been evaluated). This allows lazy evaluation
|
||||
* of initplans: we don't run the subplan until/unless we need its output.
|
||||
* Note that this routine MUST clear the execPlan fields of the plan's
|
||||
* output parameters after evaluating them!
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.4 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.5 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -67,8 +67,8 @@ SubqueryNext(SubqueryScan *node)
|
||||
/*
|
||||
* Check if we are evaluating PlanQual for tuple of this relation.
|
||||
* Additional checking is not good, but no other way for now. We could
|
||||
* introduce new nodes for this case and handle SubqueryScan --> NewNode
|
||||
* switching in Init/ReScan plan...
|
||||
* introduce new nodes for this case and handle SubqueryScan -->
|
||||
* NewNode switching in Init/ReScan plan...
|
||||
*/
|
||||
if (estate->es_evTuple != NULL &&
|
||||
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
|
||||
@@ -202,6 +202,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
|
||||
int
|
||||
ExecCountSlotsSubqueryScan(SubqueryScan *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* The subplan has its own tuple table and must not be counted here!
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.14 2001/01/29 00:39:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.15 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -371,6 +371,7 @@ ExecTidRestrPos(TidScan *node)
|
||||
tidstate = node->tidstate;
|
||||
tidstate->tss_TidPtr = tidstate->tss_MarkTidPtr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
* spi.c
|
||||
* Server Programming Interface
|
||||
*
|
||||
* $Id: spi.c,v 1.52 2001/02/19 19:49:52 tgl Exp $
|
||||
* $Id: spi.c,v 1.53 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "executor/spi_priv.h"
|
||||
#include "access/printtup.h"
|
||||
|
||||
uint32 SPI_processed = 0;
|
||||
Oid SPI_lastoid = InvalidOid;
|
||||
uint32 SPI_processed = 0;
|
||||
Oid SPI_lastoid = InvalidOid;
|
||||
SPITupleTable *SPI_tuptable = NULL;
|
||||
int SPI_result;
|
||||
int SPI_result;
|
||||
|
||||
static _SPI_connection *_SPI_stack = NULL;
|
||||
static _SPI_connection *_SPI_current = NULL;
|
||||
@@ -46,6 +46,7 @@ extern void ShowUsage(void);
|
||||
int
|
||||
SPI_connect()
|
||||
{
|
||||
|
||||
/*
|
||||
* When procedure called by Executor _SPI_curid expected to be equal
|
||||
* to _SPI_connected
|
||||
@@ -80,14 +81,14 @@ SPI_connect()
|
||||
/* Create memory contexts for this procedure */
|
||||
_SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
|
||||
"SPI Proc",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
_SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
|
||||
"SPI Exec",
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
ALLOCSET_DEFAULT_MINSIZE,
|
||||
ALLOCSET_DEFAULT_INITSIZE,
|
||||
ALLOCSET_DEFAULT_MAXSIZE);
|
||||
/* ... and switch to procedure's context */
|
||||
_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
|
||||
|
||||
@@ -146,6 +147,7 @@ SPI_finish()
|
||||
void
|
||||
AtEOXact_SPI(void)
|
||||
{
|
||||
|
||||
/*
|
||||
* Note that memory contexts belonging to SPI stack entries will be
|
||||
* freed automatically, so we can ignore them here. We just need to
|
||||
@@ -425,8 +427,8 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it here to avoid memory
|
||||
* leakage inside the type's output routine.
|
||||
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||
* memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (typisvarlena)
|
||||
val = PointerGetDatum(PG_DETOAST_DATUM(origval));
|
||||
@@ -436,7 +438,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
|
||||
result = OidFunctionCall3(foutoid,
|
||||
val,
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(tupdesc->attrs[fnumber - 1]->atttypmod));
|
||||
Int32GetDatum(tupdesc->attrs[fnumber - 1]->atttypmod));
|
||||
|
||||
/* Clean up detoasted copy, if any */
|
||||
if (val != origval)
|
||||
@@ -833,14 +835,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
#endif
|
||||
tupdesc = ExecutorStart(queryDesc, state);
|
||||
|
||||
/* Don't work currently --- need to rearrange callers so that
|
||||
* we prepare the portal before doing CreateExecutorState() etc.
|
||||
* See pquery.c for the correct order of operations.
|
||||
/*
|
||||
* Don't work currently --- need to rearrange callers so that we
|
||||
* prepare the portal before doing CreateExecutorState() etc. See
|
||||
* pquery.c for the correct order of operations.
|
||||
*/
|
||||
if (isRetrieveIntoPortal)
|
||||
{
|
||||
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
||||
}
|
||||
|
||||
ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount);
|
||||
|
||||
@@ -901,9 +902,7 @@ _SPI_begin_call(bool execmem)
|
||||
elog(FATAL, "SPI: stack corrupted");
|
||||
|
||||
if (execmem) /* switch to the Executor memory context */
|
||||
{
|
||||
_SPI_execmem();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/bit.c,v 1.12 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/lib/Attic/bit.c,v 1.13 2001/03/22 03:59:29 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -22,14 +22,14 @@ void
|
||||
BitArraySetBit(BitArray bitArray, BitIndex bitIndex)
|
||||
{
|
||||
bitArray[bitIndex / BITS_PER_BYTE] |=
|
||||
(1 << (BITS_PER_BYTE - 1 - (bitIndex % BITS_PER_BYTE)));
|
||||
(1 << (BITS_PER_BYTE - 1 - (bitIndex % BITS_PER_BYTE)));
|
||||
}
|
||||
|
||||
void
|
||||
BitArrayClearBit(BitArray bitArray, BitIndex bitIndex)
|
||||
{
|
||||
bitArray[bitIndex / BITS_PER_BYTE] &=
|
||||
~(1 << (BITS_PER_BYTE - 1 - (bitIndex % BITS_PER_BYTE)));
|
||||
~(1 << (BITS_PER_BYTE - 1 - (bitIndex % BITS_PER_BYTE)));
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -37,5 +37,5 @@ BitArrayBitIsSet(BitArray bitArray, BitIndex bitIndex)
|
||||
{
|
||||
return ((bitArray[bitIndex / BITS_PER_BYTE] &
|
||||
(1 << (BITS_PER_BYTE - 1 - (bitIndex % BITS_PER_BYTE)))
|
||||
) != 0);
|
||||
) != 0);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.51 2001/01/24 19:42:55 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.52 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -51,7 +51,7 @@ static int map_old_to_new(Port *port, UserAuth old, int status);
|
||||
static void auth_failed(Port *port);
|
||||
|
||||
|
||||
char * pg_krb_server_keyfile;
|
||||
char *pg_krb_server_keyfile;
|
||||
|
||||
|
||||
#ifdef KRB4
|
||||
@@ -177,7 +177,7 @@ pg_an_to_ln(char *aname)
|
||||
* Various krb5 state which is not connection specfic, and a flag to
|
||||
* indicate whether we have initialised it yet.
|
||||
*/
|
||||
static int pg_krb5_initialised;
|
||||
static int pg_krb5_initialised;
|
||||
static krb5_context pg_krb5_context;
|
||||
static krb5_keytab pg_krb5_keytab;
|
||||
static krb5_principal pg_krb5_server;
|
||||
@@ -192,7 +192,8 @@ pg_krb5_init(void)
|
||||
return STATUS_OK;
|
||||
|
||||
retval = krb5_init_context(&pg_krb5_context);
|
||||
if (retval) {
|
||||
if (retval)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"pg_krb5_init: krb5_init_context returned"
|
||||
" Kerberos error %d\n", retval);
|
||||
@@ -201,23 +202,25 @@ pg_krb5_init(void)
|
||||
}
|
||||
|
||||
retval = krb5_kt_resolve(pg_krb5_context, pg_krb_server_keyfile, &pg_krb5_keytab);
|
||||
if (retval) {
|
||||
if (retval)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"pg_krb5_init: krb5_kt_resolve returned"
|
||||
" Kerberos error %d\n", retval);
|
||||
com_err("postgres", retval, "while resolving keytab file %s",
|
||||
com_err("postgres", retval, "while resolving keytab file %s",
|
||||
pg_krb_server_keyfile);
|
||||
krb5_free_context(pg_krb5_context);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
retval = krb5_sname_to_principal(pg_krb5_context, NULL, PG_KRB_SRVNAM,
|
||||
retval = krb5_sname_to_principal(pg_krb5_context, NULL, PG_KRB_SRVNAM,
|
||||
KRB5_NT_SRV_HST, &pg_krb5_server);
|
||||
if (retval) {
|
||||
if (retval)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"pg_krb5_init: krb5_sname_to_principal returned"
|
||||
" Kerberos error %d\n", retval);
|
||||
com_err("postgres", retval,
|
||||
com_err("postgres", retval,
|
||||
"while getting server principal for service %s",
|
||||
pg_krb_server_keyfile);
|
||||
krb5_kt_close(pg_krb5_context, pg_krb5_keytab);
|
||||
@@ -245,25 +248,26 @@ static int
|
||||
pg_krb5_recvauth(Port *port)
|
||||
{
|
||||
krb5_error_code retval;
|
||||
int ret;
|
||||
int ret;
|
||||
krb5_auth_context auth_context = NULL;
|
||||
krb5_ticket *ticket;
|
||||
char *kusername;
|
||||
char *kusername;
|
||||
|
||||
ret = pg_krb5_init();
|
||||
if (ret != STATUS_OK)
|
||||
return ret;
|
||||
|
||||
retval = krb5_recvauth(pg_krb5_context, &auth_context,
|
||||
(krb5_pointer)&port->sock, PG_KRB_SRVNAM,
|
||||
(krb5_pointer) & port->sock, PG_KRB_SRVNAM,
|
||||
pg_krb5_server, 0, pg_krb5_keytab, &ticket);
|
||||
if (retval) {
|
||||
if (retval)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"pg_krb5_recvauth: krb5_recvauth returned"
|
||||
" Kerberos error %d\n", retval);
|
||||
com_err("postgres", retval, "from krb5_recvauth");
|
||||
com_err("postgres", retval, "from krb5_recvauth");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The "client" structure comes out of the ticket and is therefore
|
||||
@@ -272,13 +276,14 @@ pg_krb5_recvauth(Port *port)
|
||||
*
|
||||
* I have no idea why this is considered necessary.
|
||||
*/
|
||||
retval = krb5_unparse_name(pg_krb5_context,
|
||||
retval = krb5_unparse_name(pg_krb5_context,
|
||||
ticket->enc_part2->client, &kusername);
|
||||
if (retval) {
|
||||
if (retval)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"pg_krb5_recvauth: krb5_unparse_name returned"
|
||||
" Kerberos error %d\n", retval);
|
||||
com_err("postgres", retval, "while unparsing client name");
|
||||
com_err("postgres", retval, "while unparsing client name");
|
||||
krb5_free_ticket(pg_krb5_context, ticket);
|
||||
krb5_auth_con_free(pg_krb5_context, auth_context);
|
||||
return STATUS_ERROR;
|
||||
@@ -288,13 +293,13 @@ pg_krb5_recvauth(Port *port)
|
||||
if (strncmp(port->user, kusername, SM_USER))
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"\n",
|
||||
"pg_krb5_recvauth: user name \"%s\" != krb5 name \"%s\"\n",
|
||||
port->user, kusername);
|
||||
ret = STATUS_ERROR;
|
||||
}
|
||||
else
|
||||
ret = STATUS_OK;
|
||||
|
||||
|
||||
krb5_free_ticket(pg_krb5_context, ticket);
|
||||
krb5_auth_con_free(pg_krb5_context, auth_context);
|
||||
free(kusername);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.57 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.58 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This should be moved to a more appropriate place. It is here
|
||||
@@ -60,7 +60,7 @@
|
||||
* entries, of which any unused entries will be NULL.
|
||||
*/
|
||||
static LargeObjectDesc **cookies = NULL;
|
||||
static int cookies_size = 0;
|
||||
static int cookies_size = 0;
|
||||
|
||||
static MemoryContext fscxt = NULL;
|
||||
|
||||
@@ -329,10 +329,10 @@ loread(PG_FUNCTION_ARGS)
|
||||
Datum
|
||||
lowrite(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 fd = PG_GETARG_INT32(0);
|
||||
int32 fd = PG_GETARG_INT32(0);
|
||||
struct varlena *wbuf = PG_GETARG_VARLENA_P(1);
|
||||
int bytestowrite;
|
||||
int totalwritten;
|
||||
int bytestowrite;
|
||||
int totalwritten;
|
||||
|
||||
bytestowrite = VARSIZE(wbuf) - VARHDRSZ;
|
||||
totalwritten = lo_write(fd, VARDATA(wbuf), bytestowrite);
|
||||
@@ -371,7 +371,7 @@ lo_import(PG_FUNCTION_ARGS)
|
||||
*/
|
||||
nbytes = VARSIZE(filename) - VARHDRSZ;
|
||||
if (nbytes >= MAXPGPATH)
|
||||
nbytes = MAXPGPATH-1;
|
||||
nbytes = MAXPGPATH - 1;
|
||||
memcpy(fnamebuf, VARDATA(filename), nbytes);
|
||||
fnamebuf[nbytes] = '\0';
|
||||
fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666);
|
||||
@@ -445,7 +445,7 @@ lo_export(PG_FUNCTION_ARGS)
|
||||
*/
|
||||
nbytes = VARSIZE(filename) - VARHDRSZ;
|
||||
if (nbytes >= MAXPGPATH)
|
||||
nbytes = MAXPGPATH-1;
|
||||
nbytes = MAXPGPATH - 1;
|
||||
memcpy(fnamebuf, VARDATA(filename), nbytes);
|
||||
fnamebuf[nbytes] = '\0';
|
||||
oumask = umask((mode_t) 0022);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Dec 17, 1997 - Todd A. Brandys
|
||||
* Orignal Version Completed.
|
||||
*
|
||||
* $Id: crypt.c,v 1.30 2001/02/07 23:31:38 tgl Exp $
|
||||
* $Id: crypt.c,v 1.31 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -295,7 +295,7 @@ crypt_verify(const Port *port, const char *user, const char *pgpass)
|
||||
vuntil = INVALID_ABSTIME;
|
||||
else
|
||||
vuntil = DatumGetAbsoluteTime(DirectFunctionCall1(nabstimein,
|
||||
CStringGetDatum(valuntil)));
|
||||
CStringGetDatum(valuntil)));
|
||||
current = GetCurrentAbsoluteTime();
|
||||
if (vuntil != INVALID_ABSTIME && vuntil < current)
|
||||
retval = STATUS_ERROR;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: password.c,v 1.35 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Id: password.c,v 1.36 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -37,7 +37,7 @@ verify_password(const Port *port, const char *user, const char *password)
|
||||
if (!pw_file)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"verify_password: Unable to open password file \"%s\": %s\n",
|
||||
"verify_password: Unable to open password file \"%s\": %s\n",
|
||||
pw_file_fullname, strerror(errno));
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
@@ -77,12 +77,12 @@ verify_password(const Port *port, const char *user, const char *password)
|
||||
|
||||
/*
|
||||
* If the password is empty of "+" then we use the regular
|
||||
* pg_shadow passwords. If we use crypt then we have to
|
||||
* use pg_shadow passwords no matter what.
|
||||
* pg_shadow passwords. If we use crypt then we have to use
|
||||
* pg_shadow passwords no matter what.
|
||||
*/
|
||||
if (port->auth_method == uaCrypt
|
||||
|| test_pw == NULL || test_pw[0] == '\0'
|
||||
|| strcmp(test_pw, "+")==0)
|
||||
|| strcmp(test_pw, "+") == 0)
|
||||
return crypt_verify(port, user, password);
|
||||
|
||||
if (strcmp(crypt(password, test_pw), test_pw) == 0)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.c,v 1.116 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Id: pqcomm.c,v 1.117 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -71,7 +71,7 @@
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#ifdef HAVE_NETINET_TCP_H
|
||||
# include <netinet/tcp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/file.h>
|
||||
@@ -91,8 +91,8 @@ static void pq_close(void);
|
||||
/*
|
||||
* Configuration options
|
||||
*/
|
||||
int Unix_socket_permissions;
|
||||
char * Unix_socket_group;
|
||||
int Unix_socket_permissions;
|
||||
char *Unix_socket_group;
|
||||
|
||||
|
||||
/*
|
||||
@@ -223,47 +223,49 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
UNIXSOCK_PATH(saddr.un, portNumber, unixSocketName);
|
||||
len = UNIXSOCK_LEN(saddr.un);
|
||||
strcpy(sock_path, saddr.un.sun_path);
|
||||
|
||||
/*
|
||||
* Grab an interlock file associated with the socket file.
|
||||
*/
|
||||
if (! CreateSocketLockFile(sock_path, true))
|
||||
if (!CreateSocketLockFile(sock_path, true))
|
||||
return STATUS_ERROR;
|
||||
|
||||
/*
|
||||
* Once we have the interlock, we can safely delete any pre-existing
|
||||
* socket file to avoid failure at bind() time.
|
||||
* Once we have the interlock, we can safely delete any
|
||||
* pre-existing socket file to avoid failure at bind() time.
|
||||
*/
|
||||
unlink(sock_path);
|
||||
}
|
||||
#endif /* HAVE_UNIX_SOCKETS */
|
||||
#endif /* HAVE_UNIX_SOCKETS */
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
/* TCP/IP socket */
|
||||
if (hostName[0] == '\0')
|
||||
saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
{
|
||||
{
|
||||
struct hostent *hp;
|
||||
|
||||
|
||||
hp = gethostbyname(hostName);
|
||||
if ((hp == NULL) || (hp->h_addrtype != AF_INET))
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
"FATAL: StreamServerPort: gethostbyname(%s) failed\n",
|
||||
hostName);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
"FATAL: StreamServerPort: gethostbyname(%s) failed\n",
|
||||
hostName);
|
||||
fputs(PQerrormsg, stderr);
|
||||
pqdebug("%s", PQerrormsg);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
memmove((char *) &(saddr.in.sin_addr), (char *) hp->h_addr,
|
||||
hp->h_length);
|
||||
}
|
||||
|
||||
|
||||
saddr.in.sin_port = htons(portNumber);
|
||||
len = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
err = bind(fd, (struct sockaddr *)&saddr.sa, len);
|
||||
err = bind(fd, (struct sockaddr *) & saddr.sa, len);
|
||||
if (err < 0)
|
||||
{
|
||||
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
|
||||
@@ -291,16 +293,16 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
on_proc_exit(StreamDoUnlink, 0);
|
||||
|
||||
/*
|
||||
* Fix socket ownership/permission if requested. Note we must
|
||||
* do this before we listen() to avoid a window where unwanted
|
||||
* Fix socket ownership/permission if requested. Note we must do
|
||||
* this before we listen() to avoid a window where unwanted
|
||||
* connections could get accepted.
|
||||
*/
|
||||
Assert(Unix_socket_group);
|
||||
if (Unix_socket_group[0] != '\0')
|
||||
{
|
||||
char *endptr;
|
||||
char *endptr;
|
||||
unsigned long int val;
|
||||
gid_t gid;
|
||||
gid_t gid;
|
||||
|
||||
val = strtoul(Unix_socket_group, &endptr, 10);
|
||||
if (*endptr == '\0')
|
||||
@@ -346,7 +348,7 @@ StreamServerPort(int family, char *hostName, unsigned short portNumber,
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_UNIX_SOCKETS */
|
||||
#endif /* HAVE_UNIX_SOCKETS */
|
||||
|
||||
listen(fd, SOMAXCONN);
|
||||
|
||||
@@ -385,9 +387,10 @@ StreamConnection(int server_fd, Port *port)
|
||||
}
|
||||
|
||||
#ifdef SCO_ACCEPT_BUG
|
||||
|
||||
/*
|
||||
* UnixWare 7+ and OpenServer 5.0.4 are known to have this bug,
|
||||
* but it shouldn't hurt it catch if for all of them.
|
||||
* UnixWare 7+ and OpenServer 5.0.4 are known to have this bug, but it
|
||||
* shouldn't hurt it catch if for all of them.
|
||||
*/
|
||||
if (port->raddr.sa.sa_family == 0)
|
||||
port->raddr.sa.sa_family = AF_UNIX;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.28 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.29 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -64,8 +64,8 @@ PacketReceiveFragment(Port *port)
|
||||
#ifndef __BEOS__
|
||||
got = read(port->sock, pkt->ptr, pkt->nrtodo);
|
||||
#else
|
||||
got = recv(port->sock, pkt->ptr, pkt->nrtodo, 0);
|
||||
#endif /* __BEOS__ */
|
||||
got = recv(port->sock, pkt->ptr, pkt->nrtodo, 0);
|
||||
#endif /* __BEOS__ */
|
||||
if (got > 0)
|
||||
{
|
||||
pkt->nrtodo -= got;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.19 2001/02/10 02:31:26 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.20 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* This shouldn't be in libpq, but the monitor and some other
|
||||
@@ -61,10 +61,11 @@ pqinitmask(void)
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigemptyset(&UnBlockSig);
|
||||
sigfillset(&BlockSig);
|
||||
|
||||
/*
|
||||
* Unmark those signals that should never be blocked.
|
||||
* Some of these signal names don't exist on all platforms. Most do,
|
||||
* but might as well ifdef them all for consistency...
|
||||
* Unmark those signals that should never be blocked. Some of these
|
||||
* signal names don't exist on all platforms. Most do, but might as
|
||||
* well ifdef them all for consistency...
|
||||
*/
|
||||
#ifdef SIGTRAP
|
||||
sigdelset(&BlockSig, SIGTRAP);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.41 2001/02/06 17:00:01 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/main/main.c,v 1.42 2001/03/22 03:59:30 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -53,17 +53,17 @@ main(int argc, char *argv[])
|
||||
{
|
||||
int len;
|
||||
struct passwd *pw;
|
||||
char * pw_name_persist;
|
||||
char *pw_name_persist;
|
||||
|
||||
/*
|
||||
* Place platform-specific startup hacks here. This is the right
|
||||
* place to put code that must be executed early in launch of either
|
||||
* a postmaster, a standalone backend, or a standalone bootstrap run.
|
||||
* Place platform-specific startup hacks here. This is the right
|
||||
* place to put code that must be executed early in launch of either a
|
||||
* postmaster, a standalone backend, or a standalone bootstrap run.
|
||||
* Note that this code will NOT be executed when a backend or
|
||||
* sub-bootstrap run is forked by the postmaster.
|
||||
*
|
||||
* XXX The need for code here is proof that the platform in question
|
||||
* is too brain-dead to provide a standard C execution environment
|
||||
* XXX The need for code here is proof that the platform in question is
|
||||
* too brain-dead to provide a standard C execution environment
|
||||
* without help. Avoid adding more here, if you can.
|
||||
*/
|
||||
|
||||
@@ -76,7 +76,7 @@ main(int argc, char *argv[])
|
||||
int buffer[] = {SSIN_UACPROC, UAC_NOPRINT};
|
||||
|
||||
#endif /* NOPRINTADE */
|
||||
#endif /* __alpha */
|
||||
#endif /* __alpha */
|
||||
|
||||
#if defined(NOFIXADE) || defined(NOPRINTADE)
|
||||
|
||||
@@ -93,38 +93,39 @@ main(int argc, char *argv[])
|
||||
#endif /* NOFIXADE || NOPRINTADE */
|
||||
|
||||
#ifdef __BEOS__
|
||||
/* BeOS-specific actions on startup */
|
||||
beos_startup(argc,argv);
|
||||
/* BeOS-specific actions on startup */
|
||||
beos_startup(argc, argv);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Not-quite-so-platform-specific startup environment checks.
|
||||
* Still best to minimize these.
|
||||
* Not-quite-so-platform-specific startup environment checks. Still
|
||||
* best to minimize these.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Make sure we are not running as root.
|
||||
*
|
||||
* BeOS currently runs everything as root :-(, so this check must
|
||||
* be temporarily disabled there...
|
||||
*/
|
||||
* BeOS currently runs everything as root :-(, so this check must be
|
||||
* temporarily disabled there...
|
||||
*/
|
||||
#ifndef __BEOS__
|
||||
if (!(argc > 1
|
||||
&& ( strcmp(argv[1], "--help")==0 || strcmp(argv[1], "-?")==0
|
||||
|| strcmp(argv[1], "--version")==0 || strcmp(argv[1], "-V")==0 ))
|
||||
&& (geteuid() == 0) )
|
||||
&& (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0
|
||||
|| strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0))
|
||||
&& (geteuid() == 0))
|
||||
{
|
||||
fprintf(stderr, "%s", NOROOTEXEC);
|
||||
exit(1);
|
||||
}
|
||||
#endif /* __BEOS__ */
|
||||
#endif /* __BEOS__ */
|
||||
|
||||
/*
|
||||
* Set up locale information from environment, in only the categories
|
||||
* needed by Postgres; leave other categories set to default "C".
|
||||
* (Note that CTYPE and COLLATE will be overridden later from pg_control
|
||||
* if we are in an already-initialized database. We set them here so
|
||||
* that they will be available to fill pg_control during initdb.)
|
||||
* (Note that CTYPE and COLLATE will be overridden later from
|
||||
* pg_control if we are in an already-initialized database. We set
|
||||
* them here so that they will be available to fill pg_control during
|
||||
* initdb.)
|
||||
*/
|
||||
#ifdef USE_LOCALE
|
||||
setlocale(LC_CTYPE, "");
|
||||
@@ -133,9 +134,10 @@ main(int argc, char *argv[])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now dispatch to one of PostmasterMain, PostgresMain, or BootstrapMain
|
||||
* depending on the program name (and possibly first argument) we
|
||||
* were called with. The lack of consistency here is historical.
|
||||
* Now dispatch to one of PostmasterMain, PostgresMain, or
|
||||
* BootstrapMain depending on the program name (and possibly first
|
||||
* argument) we were called with. The lack of consistency here is
|
||||
* historical.
|
||||
*/
|
||||
len = strlen(argv[0]);
|
||||
|
||||
@@ -146,15 +148,16 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/*
|
||||
* If the first argument is "-boot", then invoke bootstrap mode.
|
||||
* Note we remove "-boot" from the arguments passed on to BootstrapMain.
|
||||
* If the first argument is "-boot", then invoke bootstrap mode. Note
|
||||
* we remove "-boot" from the arguments passed on to BootstrapMain.
|
||||
*/
|
||||
if (argc > 1 && strcmp(argv[1], "-boot") == 0)
|
||||
exit(BootstrapMain(argc - 1, argv + 1));
|
||||
|
||||
/*
|
||||
* Otherwise we're a standalone backend. Invoke PostgresMain,
|
||||
* specifying current userid as the "authenticated" Postgres user name.
|
||||
* specifying current userid as the "authenticated" Postgres user
|
||||
* name.
|
||||
*/
|
||||
pw = getpwuid(geteuid());
|
||||
if (pw == NULL)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* NOTE: a general convention when copying or comparing plan nodes is
|
||||
* that we ignore the executor state subnode. We do not need to look
|
||||
* at it because no current uses of copyObject() or equal() need to
|
||||
* deal with already-executing plan trees. By leaving the state subnodes
|
||||
* deal with already-executing plan trees. By leaving the state subnodes
|
||||
* out, we avoid needing to write copy/compare routines for all the
|
||||
* different executor state node types.
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.138 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.139 2001/03/22 03:59:31 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -305,7 +305,7 @@ _copyTidScan(TidScan *from)
|
||||
static SubqueryScan *
|
||||
_copySubqueryScan(SubqueryScan *from)
|
||||
{
|
||||
SubqueryScan *newnode = makeNode(SubqueryScan);
|
||||
SubqueryScan *newnode = makeNode(SubqueryScan);
|
||||
|
||||
/* ----------------
|
||||
* copy node superclass fields
|
||||
@@ -339,7 +339,7 @@ CopyJoinFields(Join *from, Join *newnode)
|
||||
/* subPlan list must point to subplans in the new subtree, not the old */
|
||||
if (from->plan.subPlan != NIL)
|
||||
newnode->plan.subPlan = nconc(newnode->plan.subPlan,
|
||||
pull_subplans((Node *) newnode->joinqual));
|
||||
pull_subplans((Node *) newnode->joinqual));
|
||||
}
|
||||
|
||||
|
||||
@@ -991,7 +991,7 @@ _copyRangeTblRef(RangeTblRef *from)
|
||||
static FromExpr *
|
||||
_copyFromExpr(FromExpr *from)
|
||||
{
|
||||
FromExpr *newnode = makeNode(FromExpr);
|
||||
FromExpr *newnode = makeNode(FromExpr);
|
||||
|
||||
Node_Copy(from, newnode, fromlist);
|
||||
Node_Copy(from, newnode, quals);
|
||||
@@ -1002,7 +1002,7 @@ _copyFromExpr(FromExpr *from)
|
||||
static JoinExpr *
|
||||
_copyJoinExpr(JoinExpr *from)
|
||||
{
|
||||
JoinExpr *newnode = makeNode(JoinExpr);
|
||||
JoinExpr *newnode = makeNode(JoinExpr);
|
||||
|
||||
newnode->jointype = from->jointype;
|
||||
newnode->isNatural = from->isNatural;
|
||||
@@ -1281,7 +1281,7 @@ _copyTidPath(TidPath *from)
|
||||
static AppendPath *
|
||||
_copyAppendPath(AppendPath *from)
|
||||
{
|
||||
AppendPath *newnode = makeNode(AppendPath);
|
||||
AppendPath *newnode = makeNode(AppendPath);
|
||||
|
||||
/* ----------------
|
||||
* copy the node superclass fields
|
||||
@@ -1424,7 +1424,11 @@ _copyRestrictInfo(RestrictInfo *from)
|
||||
newnode->mergejoinoperator = from->mergejoinoperator;
|
||||
newnode->left_sortop = from->left_sortop;
|
||||
newnode->right_sortop = from->right_sortop;
|
||||
/* Do not copy pathkeys, since they'd not be canonical in a copied query */
|
||||
|
||||
/*
|
||||
* Do not copy pathkeys, since they'd not be canonical in a copied
|
||||
* query
|
||||
*/
|
||||
newnode->left_pathkey = NIL;
|
||||
newnode->right_pathkey = NIL;
|
||||
newnode->hashjoinoperator = from->hashjoinoperator;
|
||||
@@ -1525,7 +1529,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
|
||||
static FkConstraint *
|
||||
_copyFkConstraint(FkConstraint *from)
|
||||
{
|
||||
FkConstraint *newnode = makeNode(FkConstraint);
|
||||
FkConstraint *newnode = makeNode(FkConstraint);
|
||||
|
||||
if (from->constr_name)
|
||||
newnode->constr_name = pstrdup(from->constr_name);
|
||||
@@ -1538,7 +1542,7 @@ _copyFkConstraint(FkConstraint *from)
|
||||
newnode->actions = from->actions;
|
||||
newnode->deferrable = from->deferrable;
|
||||
newnode->initdeferred = from->initdeferred;
|
||||
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
@@ -1556,7 +1560,7 @@ _copySortClause(SortClause *from)
|
||||
static A_Expr *
|
||||
_copyAExpr(A_Expr *from)
|
||||
{
|
||||
A_Expr *newnode = makeNode(A_Expr);
|
||||
A_Expr *newnode = makeNode(A_Expr);
|
||||
|
||||
newnode->oper = from->oper;
|
||||
if (from->opname)
|
||||
@@ -1593,7 +1597,7 @@ _copyParamNo(ParamNo *from)
|
||||
static Ident *
|
||||
_copyIdent(Ident *from)
|
||||
{
|
||||
Ident *newnode = makeNode(Ident);
|
||||
Ident *newnode = makeNode(Ident);
|
||||
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
@@ -1606,7 +1610,7 @@ _copyIdent(Ident *from)
|
||||
static FuncCall *
|
||||
_copyFuncCall(FuncCall *from)
|
||||
{
|
||||
FuncCall *newnode = makeNode(FuncCall);
|
||||
FuncCall *newnode = makeNode(FuncCall);
|
||||
|
||||
if (from->funcname)
|
||||
newnode->funcname = pstrdup(from->funcname);
|
||||
@@ -1620,7 +1624,7 @@ _copyFuncCall(FuncCall *from)
|
||||
static A_Indices *
|
||||
_copyAIndices(A_Indices *from)
|
||||
{
|
||||
A_Indices *newnode = makeNode(A_Indices);
|
||||
A_Indices *newnode = makeNode(A_Indices);
|
||||
|
||||
Node_Copy(from, newnode, lidx);
|
||||
Node_Copy(from, newnode, uidx);
|
||||
@@ -1631,7 +1635,7 @@ _copyAIndices(A_Indices *from)
|
||||
static ResTarget *
|
||||
_copyResTarget(ResTarget *from)
|
||||
{
|
||||
ResTarget *newnode = makeNode(ResTarget);
|
||||
ResTarget *newnode = makeNode(ResTarget);
|
||||
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
@@ -1659,7 +1663,7 @@ _copyTypeName(TypeName *from)
|
||||
static SortGroupBy *
|
||||
_copySortGroupBy(SortGroupBy *from)
|
||||
{
|
||||
SortGroupBy *newnode = makeNode(SortGroupBy);
|
||||
SortGroupBy *newnode = makeNode(SortGroupBy);
|
||||
|
||||
if (from->useOp)
|
||||
newnode->useOp = pstrdup(from->useOp);
|
||||
@@ -1684,7 +1688,7 @@ _copyRangeVar(RangeVar *from)
|
||||
static RangeSubselect *
|
||||
_copyRangeSubselect(RangeSubselect *from)
|
||||
{
|
||||
RangeSubselect *newnode = makeNode(RangeSubselect);
|
||||
RangeSubselect *newnode = makeNode(RangeSubselect);
|
||||
|
||||
Node_Copy(from, newnode, subquery);
|
||||
Node_Copy(from, newnode, name);
|
||||
@@ -1706,7 +1710,7 @@ _copyTypeCast(TypeCast *from)
|
||||
static IndexElem *
|
||||
_copyIndexElem(IndexElem *from)
|
||||
{
|
||||
IndexElem *newnode = makeNode(IndexElem);
|
||||
IndexElem *newnode = makeNode(IndexElem);
|
||||
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
@@ -1720,7 +1724,7 @@ _copyIndexElem(IndexElem *from)
|
||||
static ColumnDef *
|
||||
_copyColumnDef(ColumnDef *from)
|
||||
{
|
||||
ColumnDef *newnode = makeNode(ColumnDef);
|
||||
ColumnDef *newnode = makeNode(ColumnDef);
|
||||
|
||||
if (from->colname)
|
||||
newnode->colname = pstrdup(from->colname);
|
||||
@@ -1738,7 +1742,7 @@ _copyColumnDef(ColumnDef *from)
|
||||
static Constraint *
|
||||
_copyConstraint(Constraint *from)
|
||||
{
|
||||
Constraint *newnode = makeNode(Constraint);
|
||||
Constraint *newnode = makeNode(Constraint);
|
||||
|
||||
newnode->contype = from->contype;
|
||||
if (from->name)
|
||||
@@ -1754,7 +1758,7 @@ _copyConstraint(Constraint *from)
|
||||
static DefElem *
|
||||
_copyDefElem(DefElem *from)
|
||||
{
|
||||
DefElem *newnode = makeNode(DefElem);
|
||||
DefElem *newnode = makeNode(DefElem);
|
||||
|
||||
if (from->defname)
|
||||
newnode->defname = pstrdup(from->defname);
|
||||
@@ -1811,7 +1815,7 @@ static InsertStmt *
|
||||
_copyInsertStmt(InsertStmt *from)
|
||||
{
|
||||
InsertStmt *newnode = makeNode(InsertStmt);
|
||||
|
||||
|
||||
if (from->relname)
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
Node_Copy(from, newnode, cols);
|
||||
@@ -1825,7 +1829,7 @@ static DeleteStmt *
|
||||
_copyDeleteStmt(DeleteStmt *from)
|
||||
{
|
||||
DeleteStmt *newnode = makeNode(DeleteStmt);
|
||||
|
||||
|
||||
if (from->relname)
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
Node_Copy(from, newnode, whereClause);
|
||||
@@ -1838,7 +1842,7 @@ static UpdateStmt *
|
||||
_copyUpdateStmt(UpdateStmt *from)
|
||||
{
|
||||
UpdateStmt *newnode = makeNode(UpdateStmt);
|
||||
|
||||
|
||||
if (from->relname)
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
Node_Copy(from, newnode, targetList);
|
||||
@@ -1853,7 +1857,7 @@ static SelectStmt *
|
||||
_copySelectStmt(SelectStmt *from)
|
||||
{
|
||||
SelectStmt *newnode = makeNode(SelectStmt);
|
||||
|
||||
|
||||
Node_Copy(from, newnode, distinctClause);
|
||||
if (from->into)
|
||||
newnode->into = pstrdup(from->into);
|
||||
@@ -1882,7 +1886,7 @@ static SetOperationStmt *
|
||||
_copySetOperationStmt(SetOperationStmt *from)
|
||||
{
|
||||
SetOperationStmt *newnode = makeNode(SetOperationStmt);
|
||||
|
||||
|
||||
newnode->op = from->op;
|
||||
newnode->all = from->all;
|
||||
Node_Copy(from, newnode, larg);
|
||||
@@ -1896,7 +1900,7 @@ static AlterTableStmt *
|
||||
_copyAlterTableStmt(AlterTableStmt *from)
|
||||
{
|
||||
AlterTableStmt *newnode = makeNode(AlterTableStmt);
|
||||
|
||||
|
||||
newnode->subtype = from->subtype;
|
||||
if (from->relname)
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
@@ -1913,7 +1917,7 @@ static ChangeACLStmt *
|
||||
_copyChangeACLStmt(ChangeACLStmt *from)
|
||||
{
|
||||
ChangeACLStmt *newnode = makeNode(ChangeACLStmt);
|
||||
|
||||
|
||||
Node_Copy(from, newnode, relNames);
|
||||
if (from->aclString)
|
||||
newnode->aclString = pstrdup(from->aclString);
|
||||
@@ -1936,7 +1940,7 @@ static ClusterStmt *
|
||||
_copyClusterStmt(ClusterStmt *from)
|
||||
{
|
||||
ClusterStmt *newnode = makeNode(ClusterStmt);
|
||||
|
||||
|
||||
if (from->relname)
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
if (from->indexname)
|
||||
@@ -1948,8 +1952,8 @@ _copyClusterStmt(ClusterStmt *from)
|
||||
static CopyStmt *
|
||||
_copyCopyStmt(CopyStmt *from)
|
||||
{
|
||||
CopyStmt *newnode = makeNode(CopyStmt);
|
||||
|
||||
CopyStmt *newnode = makeNode(CopyStmt);
|
||||
|
||||
newnode->binary = from->binary;
|
||||
if (from->relname)
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
@@ -1969,7 +1973,7 @@ static CreateStmt *
|
||||
_copyCreateStmt(CreateStmt *from)
|
||||
{
|
||||
CreateStmt *newnode = makeNode(CreateStmt);
|
||||
|
||||
|
||||
newnode->istemp = from->istemp;
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
Node_Copy(from, newnode, tableElts);
|
||||
@@ -1983,7 +1987,7 @@ static VersionStmt *
|
||||
_copyVersionStmt(VersionStmt *from)
|
||||
{
|
||||
VersionStmt *newnode = makeNode(VersionStmt);
|
||||
|
||||
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
newnode->direction = from->direction;
|
||||
newnode->fromRelname = pstrdup(from->fromRelname);
|
||||
@@ -1996,7 +2000,7 @@ static DefineStmt *
|
||||
_copyDefineStmt(DefineStmt *from)
|
||||
{
|
||||
DefineStmt *newnode = makeNode(DefineStmt);
|
||||
|
||||
|
||||
newnode->defType = from->defType;
|
||||
newnode->defname = pstrdup(from->defname);
|
||||
Node_Copy(from, newnode, definition);
|
||||
@@ -2007,8 +2011,8 @@ _copyDefineStmt(DefineStmt *from)
|
||||
static DropStmt *
|
||||
_copyDropStmt(DropStmt *from)
|
||||
{
|
||||
DropStmt *newnode = makeNode(DropStmt);
|
||||
|
||||
DropStmt *newnode = makeNode(DropStmt);
|
||||
|
||||
Node_Copy(from, newnode, names);
|
||||
newnode->removeType = from->removeType;
|
||||
|
||||
@@ -2029,11 +2033,11 @@ static CommentStmt *
|
||||
_copyCommentStmt(CommentStmt *from)
|
||||
{
|
||||
CommentStmt *newnode = makeNode(CommentStmt);
|
||||
|
||||
|
||||
newnode->objtype = from->objtype;
|
||||
newnode->objname = pstrdup(from->objname);
|
||||
if (from->objproperty)
|
||||
newnode->objproperty = pstrdup(from->objproperty);
|
||||
newnode->objproperty = pstrdup(from->objproperty);
|
||||
Node_Copy(from, newnode, objlist);
|
||||
newnode->comment = pstrdup(from->comment);
|
||||
|
||||
@@ -2044,7 +2048,7 @@ static ExtendStmt *
|
||||
_copyExtendStmt(ExtendStmt *from)
|
||||
{
|
||||
ExtendStmt *newnode = makeNode(ExtendStmt);
|
||||
|
||||
|
||||
newnode->idxname = pstrdup(from->idxname);
|
||||
Node_Copy(from, newnode, whereClause);
|
||||
Node_Copy(from, newnode, rangetable);
|
||||
@@ -2055,8 +2059,8 @@ _copyExtendStmt(ExtendStmt *from)
|
||||
static FetchStmt *
|
||||
_copyFetchStmt(FetchStmt *from)
|
||||
{
|
||||
FetchStmt *newnode = makeNode(FetchStmt);
|
||||
|
||||
FetchStmt *newnode = makeNode(FetchStmt);
|
||||
|
||||
newnode->direction = from->direction;
|
||||
newnode->howMany = from->howMany;
|
||||
newnode->portalname = pstrdup(from->portalname);
|
||||
@@ -2068,8 +2072,8 @@ _copyFetchStmt(FetchStmt *from)
|
||||
static IndexStmt *
|
||||
_copyIndexStmt(IndexStmt *from)
|
||||
{
|
||||
IndexStmt *newnode = makeNode(IndexStmt);
|
||||
|
||||
IndexStmt *newnode = makeNode(IndexStmt);
|
||||
|
||||
newnode->idxname = pstrdup(from->idxname);
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
newnode->accessMethod = pstrdup(from->accessMethod);
|
||||
@@ -2087,7 +2091,7 @@ static ProcedureStmt *
|
||||
_copyProcedureStmt(ProcedureStmt *from)
|
||||
{
|
||||
ProcedureStmt *newnode = makeNode(ProcedureStmt);
|
||||
|
||||
|
||||
newnode->funcname = pstrdup(from->funcname);
|
||||
Node_Copy(from, newnode, argTypes);
|
||||
Node_Copy(from, newnode, returnType);
|
||||
@@ -2102,7 +2106,7 @@ static RemoveAggrStmt *
|
||||
_copyRemoveAggrStmt(RemoveAggrStmt *from)
|
||||
{
|
||||
RemoveAggrStmt *newnode = makeNode(RemoveAggrStmt);
|
||||
|
||||
|
||||
newnode->aggname = pstrdup(from->aggname);
|
||||
Node_Copy(from, newnode, aggtype);
|
||||
|
||||
@@ -2113,7 +2117,7 @@ static RemoveFuncStmt *
|
||||
_copyRemoveFuncStmt(RemoveFuncStmt *from)
|
||||
{
|
||||
RemoveFuncStmt *newnode = makeNode(RemoveFuncStmt);
|
||||
|
||||
|
||||
newnode->funcname = pstrdup(from->funcname);
|
||||
Node_Copy(from, newnode, args);
|
||||
|
||||
@@ -2124,7 +2128,7 @@ static RemoveOperStmt *
|
||||
_copyRemoveOperStmt(RemoveOperStmt *from)
|
||||
{
|
||||
RemoveOperStmt *newnode = makeNode(RemoveOperStmt);
|
||||
|
||||
|
||||
newnode->opname = pstrdup(from->opname);
|
||||
Node_Copy(from, newnode, args);
|
||||
|
||||
@@ -2135,7 +2139,7 @@ static RenameStmt *
|
||||
_copyRenameStmt(RenameStmt *from)
|
||||
{
|
||||
RenameStmt *newnode = makeNode(RenameStmt);
|
||||
|
||||
|
||||
newnode->relname = pstrdup(from->relname);
|
||||
newnode->inhOpt = from->inhOpt;
|
||||
if (from->column)
|
||||
@@ -2149,8 +2153,8 @@ _copyRenameStmt(RenameStmt *from)
|
||||
static RuleStmt *
|
||||
_copyRuleStmt(RuleStmt *from)
|
||||
{
|
||||
RuleStmt *newnode = makeNode(RuleStmt);
|
||||
|
||||
RuleStmt *newnode = makeNode(RuleStmt);
|
||||
|
||||
newnode->rulename = pstrdup(from->rulename);
|
||||
Node_Copy(from, newnode, whereClause);
|
||||
newnode->event = from->event;
|
||||
@@ -2231,7 +2235,7 @@ _copyLoadStmt(LoadStmt *from)
|
||||
static CreatedbStmt *
|
||||
_copyCreatedbStmt(CreatedbStmt *from)
|
||||
{
|
||||
CreatedbStmt *newnode = makeNode(CreatedbStmt);
|
||||
CreatedbStmt *newnode = makeNode(CreatedbStmt);
|
||||
|
||||
if (from->dbname)
|
||||
newnode->dbname = pstrdup(from->dbname);
|
||||
@@ -2247,7 +2251,7 @@ _copyCreatedbStmt(CreatedbStmt *from)
|
||||
static DropdbStmt *
|
||||
_copyDropdbStmt(DropdbStmt *from)
|
||||
{
|
||||
DropdbStmt *newnode = makeNode(DropdbStmt);
|
||||
DropdbStmt *newnode = makeNode(DropdbStmt);
|
||||
|
||||
if (from->dbname)
|
||||
newnode->dbname = pstrdup(from->dbname);
|
||||
@@ -2258,7 +2262,7 @@ _copyDropdbStmt(DropdbStmt *from)
|
||||
static VacuumStmt *
|
||||
_copyVacuumStmt(VacuumStmt *from)
|
||||
{
|
||||
VacuumStmt *newnode = makeNode(VacuumStmt);
|
||||
VacuumStmt *newnode = makeNode(VacuumStmt);
|
||||
|
||||
newnode->verbose = from->verbose;
|
||||
newnode->analyze = from->analyze;
|
||||
@@ -2272,7 +2276,7 @@ _copyVacuumStmt(VacuumStmt *from)
|
||||
static ExplainStmt *
|
||||
_copyExplainStmt(ExplainStmt *from)
|
||||
{
|
||||
ExplainStmt *newnode = makeNode(ExplainStmt);
|
||||
ExplainStmt *newnode = makeNode(ExplainStmt);
|
||||
|
||||
Node_Copy(from, newnode, query);
|
||||
newnode->verbose = from->verbose;
|
||||
@@ -2283,7 +2287,7 @@ _copyExplainStmt(ExplainStmt *from)
|
||||
static CreateSeqStmt *
|
||||
_copyCreateSeqStmt(CreateSeqStmt *from)
|
||||
{
|
||||
CreateSeqStmt *newnode = makeNode(CreateSeqStmt);
|
||||
CreateSeqStmt *newnode = makeNode(CreateSeqStmt);
|
||||
|
||||
if (from->seqname)
|
||||
newnode->seqname = pstrdup(from->seqname);
|
||||
@@ -2346,6 +2350,7 @@ _copyCreateTrigStmt(CreateTrigStmt *from)
|
||||
newnode->lang = pstrdup(from->lang);
|
||||
if (from->text)
|
||||
newnode->text = pstrdup(from->text);
|
||||
|
||||
Node_Copy(from, newnode, attr);
|
||||
if (from->when)
|
||||
newnode->when = pstrdup(from->when);
|
||||
@@ -2459,7 +2464,7 @@ _copyLockStmt(LockStmt *from)
|
||||
static ConstraintsSetStmt *
|
||||
_copyConstraintsSetStmt(ConstraintsSetStmt *from)
|
||||
{
|
||||
ConstraintsSetStmt *newnode = makeNode(ConstraintsSetStmt);
|
||||
ConstraintsSetStmt *newnode = makeNode(ConstraintsSetStmt);
|
||||
|
||||
Node_Copy(from, newnode, constraints);
|
||||
newnode->deferred = from->deferred;
|
||||
@@ -2470,7 +2475,7 @@ _copyConstraintsSetStmt(ConstraintsSetStmt *from)
|
||||
static CreateGroupStmt *
|
||||
_copyCreateGroupStmt(CreateGroupStmt *from)
|
||||
{
|
||||
CreateGroupStmt *newnode = makeNode(CreateGroupStmt);
|
||||
CreateGroupStmt *newnode = makeNode(CreateGroupStmt);
|
||||
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
@@ -2483,7 +2488,7 @@ _copyCreateGroupStmt(CreateGroupStmt *from)
|
||||
static AlterGroupStmt *
|
||||
_copyAlterGroupStmt(AlterGroupStmt *from)
|
||||
{
|
||||
AlterGroupStmt *newnode = makeNode(AlterGroupStmt);
|
||||
AlterGroupStmt *newnode = makeNode(AlterGroupStmt);
|
||||
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
@@ -2497,7 +2502,7 @@ _copyAlterGroupStmt(AlterGroupStmt *from)
|
||||
static DropGroupStmt *
|
||||
_copyDropGroupStmt(DropGroupStmt *from)
|
||||
{
|
||||
DropGroupStmt *newnode = makeNode(DropGroupStmt);
|
||||
DropGroupStmt *newnode = makeNode(DropGroupStmt);
|
||||
|
||||
if (from->name)
|
||||
newnode->name = pstrdup(from->name);
|
||||
@@ -2508,7 +2513,7 @@ _copyDropGroupStmt(DropGroupStmt *from)
|
||||
static ReindexStmt *
|
||||
_copyReindexStmt(ReindexStmt *from)
|
||||
{
|
||||
ReindexStmt *newnode = makeNode(ReindexStmt);
|
||||
ReindexStmt *newnode = makeNode(ReindexStmt);
|
||||
|
||||
newnode->reindexType = from->reindexType;
|
||||
if (from->name)
|
||||
@@ -2919,7 +2924,7 @@ copyObject(void *from)
|
||||
retval = _copyReindexStmt(from);
|
||||
break;
|
||||
case T_CheckPointStmt:
|
||||
retval = (void*)makeNode(CheckPointStmt);
|
||||
retval = (void *) makeNode(CheckPointStmt);
|
||||
break;
|
||||
|
||||
case T_A_Expr:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* NOTE: a general convention when copying or comparing plan nodes is
|
||||
* that we ignore the executor state subnode. We do not need to look
|
||||
* at it because no current uses of copyObject() or equal() need to
|
||||
* deal with already-executing plan trees. By leaving the state subnodes
|
||||
* deal with already-executing plan trees. By leaving the state subnodes
|
||||
* out, we avoid needing to write copy/compare routines for all the
|
||||
* different executor state node types.
|
||||
*
|
||||
@@ -20,7 +20,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.87 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.88 2001/03/22 03:59:31 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
|
||||
/* Macro for comparing string fields that might be NULL */
|
||||
#define equalstr(a, b) \
|
||||
#define equalstr(a, b) \
|
||||
(((a) != NULL && (b) != NULL) ? (strcmp(a, b) == 0) : (a) == (b))
|
||||
|
||||
|
||||
@@ -134,9 +134,9 @@ _equalOper(Oper *a, Oper *b)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We do not examine opid or op_fcache, since these are
|
||||
* logically derived from opno, and they may not be set yet depending
|
||||
* on how far along the node is in the parse/plan pipeline.
|
||||
* We do not examine opid or op_fcache, since these are logically
|
||||
* derived from opno, and they may not be set yet depending on how far
|
||||
* along the node is in the parse/plan pipeline.
|
||||
*
|
||||
* (Besides, op_fcache is executor state, which we don't check --- see
|
||||
* notes at head of file.)
|
||||
@@ -514,6 +514,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
|
||||
{
|
||||
if (!equal(a->clause, b->clause))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* ignore eval_cost, left/right_pathkey, and left/right_dispersion,
|
||||
* since they may not be set yet, and should be derivable from the
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.38 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.39 2001/03/22 03:59:32 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* XXX a few of the following functions are duplicated to handle
|
||||
@@ -557,13 +557,12 @@ set_differencei(List *l1, List *l2)
|
||||
List *
|
||||
lreverse(List *l)
|
||||
{
|
||||
List *result = NIL;
|
||||
List *i;
|
||||
foreach(i, l)
|
||||
{
|
||||
result = lcons(lfirst(i), result);
|
||||
}
|
||||
return result;
|
||||
List *result = NIL;
|
||||
List *i;
|
||||
|
||||
foreach(i, l)
|
||||
result = lcons(lfirst(i), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.25 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.26 2001/03/22 03:59:32 momjian Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Creator functions in POSTGRES 4.2 are generated automatically. Most of
|
||||
@@ -109,9 +109,10 @@ makeResdom(AttrNumber resno,
|
||||
resdom->resname = resname;
|
||||
|
||||
/*
|
||||
* We always set the sorting/grouping fields to 0. If the caller wants
|
||||
* to change them he must do so explicitly. Few if any callers should
|
||||
* be doing that, so omitting these arguments reduces the chance of error.
|
||||
* We always set the sorting/grouping fields to 0. If the caller
|
||||
* wants to change them he must do so explicitly. Few if any callers
|
||||
* should be doing that, so omitting these arguments reduces the
|
||||
* chance of error.
|
||||
*/
|
||||
resdom->ressortgroupref = 0;
|
||||
resdom->reskey = 0;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.13 2001/01/24 19:42:56 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/nodeFuncs.c,v 1.14 2001/03/22 03:59:32 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -114,5 +114,5 @@ non_null(Expr *c)
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user