Commit 6bfe6403 authored by Tom Lane's avatar Tom Lane

Cleanup of code for creating index entries. Functional indexes with

pass-by-ref data types --- eg, an index on lower(textfield) --- no longer
leak memory during index creation or update.  Clean up a lot of redundant
code ... did you know that copy, vacuum, truncate, reindex, extend index,
and bootstrap each basically duplicated the main executor's logic for
extracting information about an index and preparing index entries?
Functional indexes should be a little faster now too, due to removal
of repeated function lookups.
CREATE INDEX 'opt_type' clause is deimplemented by these changes,
but I haven't removed it from the parser yet (need to merge with
Thomas' latest change set first).
parent a30bc7c7
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.61 2000/07/12 02:36:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.62 2000/07/14 22:17:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -65,53 +65,42 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -65,53 +65,42 @@ gistbuild(PG_FUNCTION_ARGS)
{ {
Relation heap = (Relation) PG_GETARG_POINTER(0); Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1); Relation index = (Relation) PG_GETARG_POINTER(1);
int32 natts = PG_GETARG_INT32(2); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
AttrNumber *attnum = (AttrNumber *) PG_GETARG_POINTER(3); Node *oldPred = (Node *) PG_GETARG_POINTER(3);
FuncIndexInfo *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
PredInfo *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
#ifdef NOT_USED #ifdef NOT_USED
bool unique = PG_GETARG_BOOL(6); IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(7);
#endif #endif
HeapScanDesc scan; HeapScanDesc hscan;
AttrNumber i;
HeapTuple htup; HeapTuple htup;
IndexTuple itup; IndexTuple itup;
TupleDesc hd, TupleDesc htupdesc,
id; itupdesc;
InsertIndexResult res; Datum attdata[INDEX_MAX_KEYS];
Datum *d; char nulls[INDEX_MAX_KEYS];
bool *nulls; int nhtups,
int nb, nitups;
nh, Node *pred = indexInfo->ii_Predicate;
ni;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot; TupleTableSlot *slot;
#endif #endif
Node *pred, ExprContext *econtext;
*oldPred; InsertIndexResult res = NULL;
GISTSTATE giststate; GISTSTATE giststate;
GISTENTRY tmpcentry; GISTENTRY tmpcentry;
Buffer buffer = InvalidBuffer; Buffer buffer = InvalidBuffer;
bool *compvec; bool *compvec;
int i;
/* no locking is needed */ /* no locking is needed */
CommandCounterIncrement(); /* so we can see the new pg_index tuple */
initGISTstate(&giststate, index); initGISTstate(&giststate, index);
pred = predInfo->pred;
oldPred = predInfo->oldPred;
/* /*
* We expect to be called exactly once for any index relation. If * We expect to be called exactly once for any index relation. If
* that's not the case, big trouble's what we have. * that's not the case, big trouble's what we have.
*/ */
if (oldPred == NULL && RelationGetNumberOfBlocks(index) != 0)
if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
elog(ERROR, "%s already contains data", RelationGetRelationName(index)); elog(ERROR, "%s already contains data", RelationGetRelationName(index));
/* initialize the root page (if this is a new index) */ /* initialize the root page (if this is a new index) */
...@@ -122,43 +111,50 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -122,43 +111,50 @@ gistbuild(PG_FUNCTION_ARGS)
WriteBuffer(buffer); WriteBuffer(buffer);
} }
/* init the tuple descriptors and get set for a heap scan */ /* get tuple descriptors for heap and index relations */
hd = RelationGetDescr(heap); htupdesc = RelationGetDescr(heap);
id = RelationGetDescr(index); itupdesc = RelationGetDescr(index);
d = (Datum *) palloc(natts * sizeof(*d));
nulls = (bool *) palloc(natts * sizeof(*nulls));
/* /*
* If this is a predicate (partial) index, we will need to evaluate * If this is a predicate (partial) index, we will need to evaluate
* the predicate using ExecQual, which requires the current tuple to * the predicate using ExecQual, which requires the current tuple to
* be in a slot of a TupleTable. In addition, ExecQual must have an * be in a slot of a TupleTable. In addition, ExecQual must have an
* ExprContext referring to that slot. Here, we initialize dummy * ExprContext referring to that slot. Here, we initialize dummy
* TupleTable and ExprContext objects for this purpose. --Nels, Feb * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
* '92 *
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/ */
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, hd); ExecSetSlotDescriptor(slot, htupdesc);
econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
{ {
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
econtext = NULL;
} }
econtext = MakeExprContext(slot, TransactionCommandContext);
#else
econtext = MakeExprContext(NULL, TransactionCommandContext);
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
/* int the tuples as we insert them */
nh = ni = 0;
scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL); /* build the index */
nhtups = nitups = 0;
compvec = (bool *) palloc(sizeof(bool) * indexInfo->ii_NumIndexAttrs);
while (HeapTupleIsValid(htup = heap_getnext(scan, 0))) /* start a heap scan */
hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
{ {
nh++; MemoryContextReset(econtext->ecxt_per_tuple_memory);
nhtups++;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
/* /*
...@@ -167,11 +163,10 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -167,11 +163,10 @@ gistbuild(PG_FUNCTION_ARGS)
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
{ {
ni++; nitups++;
continue; continue;
} }
} }
...@@ -182,61 +177,41 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -182,61 +177,41 @@ gistbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
ni++; nitups++;
/* /*
* For the current heap tuple, extract all the attributes we use * For the current heap tuple, extract all the attributes we use
* in this index, and note which are null. * in this index, and note which are null.
*/ */
FormIndexDatum(indexInfo,
for (i = 1; i <= natts; i++) htup,
{ htupdesc,
int attoff; econtext->ecxt_per_tuple_memory,
bool attnull; attdata,
nulls);
/*
* Offsets are from the start of the tuple, and are
* zero-based; indices are one-based. The next call returns i
* - 1. That's data hiding for you.
*/
attoff = AttrNumberGetAttrOffset(i);
/*
* d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
*/
d[attoff] = GetIndexValue(htup,
hd,
attoff,
attnum,
finfo,
&attnull);
nulls[attoff] = (attnull ? 'n' : ' ');
}
/* immediately compress keys to normalize */ /* immediately compress keys to normalize */
compvec = (bool *) palloc(sizeof(bool) * natts); for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
for (i = 0; i < natts; i++)
{ {
gistcentryinit(&giststate, &tmpcentry, (char *) d[i], gistcentryinit(&giststate, &tmpcentry, (char *) attdata[i],
(Relation) NULL, (Page) NULL, (OffsetNumber) 0, (Relation) NULL, (Page) NULL, (OffsetNumber) 0,
-1 /* size is currently bogus */ , TRUE); -1 /* size is currently bogus */ , TRUE);
if (d[i] != (Datum) tmpcentry.pred && !(giststate.keytypbyval)) if (attdata[i] != (Datum) tmpcentry.pred &&
!(giststate.keytypbyval))
compvec[i] = TRUE; compvec[i] = TRUE;
else else
compvec[i] = FALSE; compvec[i] = FALSE;
d[i] = (Datum) tmpcentry.pred; attdata[i] = (Datum) tmpcentry.pred;
} }
/* form an index tuple and point it at the heap tuple */ /* form an index tuple and point it at the heap tuple */
itup = index_formtuple(id, &d[0], nulls); itup = index_formtuple(itupdesc, attdata, nulls);
itup->t_tid = htup->t_self; itup->t_tid = htup->t_self;
/* /*
...@@ -248,24 +223,27 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -248,24 +223,27 @@ gistbuild(PG_FUNCTION_ARGS)
*/ */
res = gistdoinsert(index, itup, &giststate); res = gistdoinsert(index, itup, &giststate);
for (i = 0; i < natts; i++)
if (compvec[i] == TRUE) for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
pfree((char *) d[i]); if (compvec[i])
pfree(DatumGetPointer(attdata[i]));
pfree(itup); pfree(itup);
pfree(res); pfree(res);
pfree(compvec);
} }
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
heap_endscan(scan); heap_endscan(hscan);
pfree(compvec);
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
...@@ -286,20 +264,16 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -286,20 +264,16 @@ gistbuild(PG_FUNCTION_ARGS)
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
UpdateStats(hrelid, nh, inplace); UpdateStats(hrelid, nhtups, inplace);
UpdateStats(irelid, ni, inplace); UpdateStats(irelid, nitups, inplace);
if (oldPred != NULL && !inplace) if (oldPred != NULL && !inplace)
{ {
if (ni == nh) if (nitups == nhtups)
pred = NULL; pred = NULL;
UpdateIndexPredicate(irelid, oldPred, pred); UpdateIndexPredicate(irelid, oldPred, pred);
} }
} }
/* be tidy */
pfree(nulls);
pfree(d);
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.41 2000/07/12 02:36:46 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.42 2000/07/14 22:17:28 tgl Exp $
* *
* NOTES * NOTES
* This file contains only the public interface routines. * This file contains only the public interface routines.
...@@ -41,42 +41,32 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -41,42 +41,32 @@ hashbuild(PG_FUNCTION_ARGS)
{ {
Relation heap = (Relation) PG_GETARG_POINTER(0); Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1); Relation index = (Relation) PG_GETARG_POINTER(1);
int32 natts = PG_GETARG_INT32(2); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
AttrNumber *attnum = (AttrNumber *) PG_GETARG_POINTER(3); Node *oldPred = (Node *) PG_GETARG_POINTER(3);
FuncIndexInfo *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
PredInfo *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
#ifdef NOT_USED #ifdef NOT_USED
bool unique = PG_GETARG_BOOL(6); IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(7);
#endif #endif
HeapScanDesc hscan; HeapScanDesc hscan;
HeapTuple htup; HeapTuple htup;
IndexTuple itup; IndexTuple itup;
TupleDesc htupdesc, TupleDesc htupdesc,
itupdesc; itupdesc;
Datum *attdata; Datum attdata[INDEX_MAX_KEYS];
bool *nulls; char nulls[INDEX_MAX_KEYS];
InsertIndexResult res;
int nhtups, int nhtups,
nitups; nitups;
int i;
HashItem hitem; HashItem hitem;
Node *pred = indexInfo->ii_Predicate;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot; TupleTableSlot *slot;
#endif #endif
Node *pred, ExprContext *econtext;
*oldPred; InsertIndexResult res = NULL;
/* note that this is a new btree */ /* note that this is a new hash */
BuildingHash = true; BuildingHash = true;
pred = predInfo->pred;
oldPred = predInfo->oldPred;
/* initialize the hash index metadata page (if this is a new index) */ /* initialize the hash index metadata page (if this is a new index) */
if (oldPred == NULL) if (oldPred == NULL)
_hash_metapinit(index); _hash_metapinit(index);
...@@ -85,17 +75,15 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -85,17 +75,15 @@ hashbuild(PG_FUNCTION_ARGS)
htupdesc = RelationGetDescr(heap); htupdesc = RelationGetDescr(heap);
itupdesc = RelationGetDescr(index); itupdesc = RelationGetDescr(index);
/* get space for data items that'll appear in the index tuple */
attdata = (Datum *) palloc(natts * sizeof(Datum));
nulls = (bool *) palloc(natts * sizeof(bool));
/* /*
* If this is a predicate (partial) index, we will need to evaluate * If this is a predicate (partial) index, we will need to evaluate
* the predicate using ExecQual, which requires the current tuple to * the predicate using ExecQual, which requires the current tuple to
* be in a slot of a TupleTable. In addition, ExecQual must have an * be in a slot of a TupleTable. In addition, ExecQual must have an
* ExprContext referring to that slot. Here, we initialize dummy * ExprContext referring to that slot. Here, we initialize dummy
* TupleTable and ExprContext objects for this purpose. --Nels, Feb * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
* '92 *
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/ */
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
...@@ -103,14 +91,15 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -103,14 +91,15 @@ hashbuild(PG_FUNCTION_ARGS)
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, htupdesc); ExecSetSlotDescriptor(slot, htupdesc);
econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
{ {
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
econtext = NULL;
} }
econtext = MakeExprContext(slot, TransactionCommandContext);
#else
econtext = MakeExprContext(NULL, TransactionCommandContext);
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
/* build the index */ /* build the index */
...@@ -121,6 +110,8 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -121,6 +110,8 @@ hashbuild(PG_FUNCTION_ARGS)
while (HeapTupleIsValid(htup = heap_getnext(hscan, 0))) while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
{ {
MemoryContextReset(econtext->ecxt_per_tuple_memory);
nhtups++; nhtups++;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
...@@ -130,7 +121,6 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -130,7 +121,6 @@ hashbuild(PG_FUNCTION_ARGS)
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
{ {
...@@ -145,7 +135,6 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -145,7 +135,6 @@ hashbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
...@@ -158,33 +147,12 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -158,33 +147,12 @@ hashbuild(PG_FUNCTION_ARGS)
* For the current heap tuple, extract all the attributes we use * For the current heap tuple, extract all the attributes we use
* in this index, and note which are null. * in this index, and note which are null.
*/ */
for (i = 1; i <= natts; i++) FormIndexDatum(indexInfo,
{ htup,
int attoff; htupdesc,
bool attnull; econtext->ecxt_per_tuple_memory,
attdata,
/* nulls);
* Offsets are from the start of the tuple, and are
* zero-based; indices are one-based. The next call returns i
* - 1. That's data hiding for you.
*/
/* attoff = i - 1 */
attoff = AttrNumberGetAttrOffset(i);
/*
* below, attdata[attoff] set to equal some datum & attnull is
* changed to indicate whether or not the attribute is null
* for this tuple
*/
attdata[attoff] = GetIndexValue(htup,
htupdesc,
attoff,
attnum,
finfo,
&attnull);
nulls[attoff] = (attnull ? 'n' : ' ');
}
/* form an index tuple and point it at the heap tuple */ /* form an index tuple and point it at the heap tuple */
itup = index_formtuple(itupdesc, attdata, nulls); itup = index_formtuple(itupdesc, attdata, nulls);
...@@ -208,7 +176,9 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -208,7 +176,9 @@ hashbuild(PG_FUNCTION_ARGS)
itup->t_tid = htup->t_self; itup->t_tid = htup->t_self;
hitem = _hash_formitem(itup); hitem = _hash_formitem(itup);
res = _hash_doinsert(index, hitem); res = _hash_doinsert(index, hitem);
pfree(hitem); pfree(hitem);
pfree(itup); pfree(itup);
pfree(res); pfree(res);
...@@ -221,9 +191,9 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -221,9 +191,9 @@ hashbuild(PG_FUNCTION_ARGS)
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
...@@ -254,10 +224,6 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -254,10 +224,6 @@ hashbuild(PG_FUNCTION_ARGS)
} }
} }
/* be tidy */
pfree(nulls);
pfree(attdata);
/* all done */ /* all done */
BuildingHash = false; BuildingHash = false;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.45 2000/06/13 07:34:35 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.46 2000/07/14 22:17:30 tgl Exp $
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
* index_open - open an index relation by relationId * index_open - open an index relation by relationId
...@@ -424,56 +424,3 @@ index_getprocid(Relation irel, ...@@ -424,56 +424,3 @@ index_getprocid(Relation irel,
return loc[(natts * (procnum - 1)) + (attnum - 1)]; return loc[(natts * (procnum - 1)) + (attnum - 1)];
} }
Datum
GetIndexValue(HeapTuple tuple,
TupleDesc hTupDesc,
int attOff,
AttrNumber *attrNums,
FuncIndexInfo *fInfo,
bool *attNull)
{
Datum returnVal;
if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid)
{
FmgrInfo flinfo;
FunctionCallInfoData fcinfo;
int i;
bool anynull = false;
/*
* XXX ought to store lookup info in FuncIndexInfo so it need not
* be repeated on each call?
*/
fmgr_info(FIgetProcOid(fInfo), &flinfo);
MemSet(&fcinfo, 0, sizeof(fcinfo));
fcinfo.flinfo = &flinfo;
fcinfo.nargs = FIgetnArgs(fInfo);
for (i = 0; i < FIgetnArgs(fInfo); i++)
{
fcinfo.arg[i] = heap_getattr(tuple,
attrNums[i],
hTupDesc,
&fcinfo.argnull[i]);
anynull |= fcinfo.argnull[i];
}
if (flinfo.fn_strict && anynull)
{
/* force a null result for strict function */
returnVal = (Datum) 0;
*attNull = true;
}
else
{
returnVal = FunctionCallInvoke(&fcinfo);
*attNull = fcinfo.isnull;
}
}
else
returnVal = heap_getattr(tuple, attrNums[attOff], hTupDesc, attNull);
return returnVal;
}
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.45 2000/06/08 22:36:51 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.46 2000/07/14 22:17:30 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -533,6 +533,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation, ...@@ -533,6 +533,7 @@ OperatorRelationFillScanKeyEntry(Relation operatorRelation,
void void
IndexSupportInitialize(IndexStrategy indexStrategy, IndexSupportInitialize(IndexStrategy indexStrategy,
RegProcedure *indexSupport, RegProcedure *indexSupport,
bool *isUnique,
Oid indexObjectId, Oid indexObjectId,
Oid accessMethodObjectId, Oid accessMethodObjectId,
StrategyNumber maxStrategyNumber, StrategyNumber maxStrategyNumber,
...@@ -544,6 +545,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -544,6 +545,7 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
ScanKeyData entry[2]; ScanKeyData entry[2];
Relation operatorRelation; Relation operatorRelation;
HeapTuple tuple; HeapTuple tuple;
Form_pg_index iform;
StrategyMap map; StrategyMap map;
AttrNumber attributeNumber; AttrNumber attributeNumber;
int attributeIndex; int attributeIndex;
...@@ -568,7 +570,12 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -568,7 +570,12 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
} }
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "IndexSupportInitialize: corrupted catalogs"); elog(ERROR, "IndexSupportInitialize: no pg_index entry for index %u",
indexObjectId);
iform = (Form_pg_index) GETSTRUCT(tuple);
*isUnique = iform->indisunique;
maxStrategyNumber = AMStrategies(maxStrategyNumber); maxStrategyNumber = AMStrategies(maxStrategyNumber);
...@@ -578,10 +585,6 @@ IndexSupportInitialize(IndexStrategy indexStrategy, ...@@ -578,10 +585,6 @@ IndexSupportInitialize(IndexStrategy indexStrategy,
*/ */
for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++) for (attributeIndex = 0; attributeIndex < maxAttributeNumber; attributeIndex++)
{ {
Form_pg_index iform;
iform = (Form_pg_index) GETSTRUCT(tuple);
if (!OidIsValid(iform->indkey[attributeIndex])) if (!OidIsValid(iform->indkey[attributeIndex]))
{ {
if (attributeIndex == InvalidAttrNumber) if (attributeIndex == InvalidAttrNumber)
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.60 2000/07/12 02:36:48 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.61 2000/07/14 22:17:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -45,44 +45,34 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -45,44 +45,34 @@ btbuild(PG_FUNCTION_ARGS)
{ {
Relation heap = (Relation) PG_GETARG_POINTER(0); Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1); Relation index = (Relation) PG_GETARG_POINTER(1);
int32 natts = PG_GETARG_INT32(2); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
AttrNumber *attnum = (AttrNumber *) PG_GETARG_POINTER(3); Node *oldPred = (Node *) PG_GETARG_POINTER(3);
FuncIndexInfo *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
PredInfo *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
bool unique = PG_GETARG_BOOL(6);
#ifdef NOT_USED #ifdef NOT_USED
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(7); IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
#endif #endif
HeapScanDesc hscan; HeapScanDesc hscan;
HeapTuple htup; HeapTuple htup;
IndexTuple itup; IndexTuple itup;
TupleDesc htupdesc, TupleDesc htupdesc,
itupdesc; itupdesc;
Datum *attdata; Datum attdata[INDEX_MAX_KEYS];
bool *nulls; char nulls[INDEX_MAX_KEYS];
InsertIndexResult res = 0;
int nhtups, int nhtups,
nitups; nitups;
int i; Node *pred = indexInfo->ii_Predicate;
BTItem btitem;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext = (ExprContext *) NULL; TupleTable tupleTable;
TupleTable tupleTable = (TupleTable) NULL; TupleTableSlot *slot;
TupleTableSlot *slot = (TupleTableSlot *) NULL;
#endif #endif
Node *pred, ExprContext *econtext;
*oldPred; InsertIndexResult res = NULL;
BTSpool *spool = NULL; BTSpool *spool = NULL;
BTItem btitem;
bool usefast; bool usefast;
/* note that this is a new btree */ /* note that this is a new btree */
BuildingBtree = true; BuildingBtree = true;
pred = predInfo->pred;
oldPred = predInfo->oldPred;
/* /*
* bootstrap processing does something strange, so don't use * bootstrap processing does something strange, so don't use
* sort/build for initial catalog indices. at some point i need to * sort/build for initial catalog indices. at some point i need to
...@@ -104,17 +94,15 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -104,17 +94,15 @@ btbuild(PG_FUNCTION_ARGS)
htupdesc = RelationGetDescr(heap); htupdesc = RelationGetDescr(heap);
itupdesc = RelationGetDescr(index); itupdesc = RelationGetDescr(index);
/* get space for data items that'll appear in the index tuple */
attdata = (Datum *) palloc(natts * sizeof(Datum));
nulls = (bool *) palloc(natts * sizeof(bool));
/* /*
* If this is a predicate (partial) index, we will need to evaluate * If this is a predicate (partial) index, we will need to evaluate
* the predicate using ExecQual, which requires the current tuple to * the predicate using ExecQual, which requires the current tuple to
* be in a slot of a TupleTable. In addition, ExecQual must have an * be in a slot of a TupleTable. In addition, ExecQual must have an
* ExprContext referring to that slot. Here, we initialize dummy * ExprContext referring to that slot. Here, we initialize dummy
* TupleTable and ExprContext objects for this purpose. --Nels, Feb * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
* '92 *
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/ */
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
...@@ -122,7 +110,6 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -122,7 +110,6 @@ btbuild(PG_FUNCTION_ARGS)
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, htupdesc); ExecSetSlotDescriptor(slot, htupdesc);
econtext = MakeExprContext(slot, TransactionCommandContext);
/* /*
* we never want to use sort/build if we are extending an existing * we never want to use sort/build if we are extending an existing
...@@ -133,22 +120,29 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -133,22 +120,29 @@ btbuild(PG_FUNCTION_ARGS)
*/ */
usefast = false; usefast = false;
} }
else
{
tupleTable = NULL;
slot = NULL;
}
econtext = MakeExprContext(slot, TransactionCommandContext);
#else
econtext = MakeExprContext(NULL, TransactionCommandContext);
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
/* start a heap scan */
/* build the index */ /* build the index */
nhtups = nitups = 0; nhtups = nitups = 0;
if (usefast) if (usefast)
{ spool = _bt_spoolinit(index, indexInfo->ii_Unique);
spool = _bt_spoolinit(index, unique);
res = (InsertIndexResult) NULL;
}
/* start a heap scan */
hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL); hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
while (HeapTupleIsValid(htup = heap_getnext(hscan, 0))) while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
{ {
MemoryContextReset(econtext->ecxt_per_tuple_memory);
nhtups++; nhtups++;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
...@@ -158,7 +152,6 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -158,7 +152,6 @@ btbuild(PG_FUNCTION_ARGS)
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
{ {
...@@ -173,7 +166,6 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -173,7 +166,6 @@ btbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
...@@ -186,27 +178,12 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -186,27 +178,12 @@ btbuild(PG_FUNCTION_ARGS)
* For the current heap tuple, extract all the attributes we use * For the current heap tuple, extract all the attributes we use
* in this index, and note which are null. * in this index, and note which are null.
*/ */
FormIndexDatum(indexInfo,
for (i = 1; i <= natts; i++) htup,
{ htupdesc,
int attoff; econtext->ecxt_per_tuple_memory,
bool attnull; attdata,
nulls);
/*
* Offsets are from the start of the tuple, and are
* zero-based; indices are one-based. The next call returns i
* - 1. That's data hiding for you.
*/
attoff = AttrNumberGetAttrOffset(i);
attdata[attoff] = GetIndexValue(htup,
htupdesc,
attoff,
attnum,
finfo,
&attnull);
nulls[attoff] = (attnull ? 'n' : ' ');
}
/* form an index tuple and point it at the heap tuple */ /* form an index tuple and point it at the heap tuple */
itup = index_formtuple(itupdesc, attdata, nulls); itup = index_formtuple(itupdesc, attdata, nulls);
...@@ -246,7 +223,7 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -246,7 +223,7 @@ btbuild(PG_FUNCTION_ARGS)
if (usefast) if (usefast)
_bt_spool(btitem, spool); _bt_spool(btitem, spool);
else else
res = _bt_doinsert(index, btitem, unique, heap); res = _bt_doinsert(index, btitem, indexInfo->ii_Unique, heap);
pfree(btitem); pfree(btitem);
pfree(itup); pfree(itup);
...@@ -261,9 +238,9 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -261,9 +238,9 @@ btbuild(PG_FUNCTION_ARGS)
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
/* /*
* if we are doing bottom-up btree build, finish the build by (1) * if we are doing bottom-up btree build, finish the build by (1)
...@@ -305,10 +282,6 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -305,10 +282,6 @@ btbuild(PG_FUNCTION_ARGS)
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
/*
* UpdateStats(hrelid, nhtups, true); UpdateStats(irelid, nitups,
* false);
*/
UpdateStats(hrelid, nhtups, inplace); UpdateStats(hrelid, nhtups, inplace);
UpdateStats(irelid, nitups, inplace); UpdateStats(irelid, nitups, inplace);
if (oldPred != NULL) if (oldPred != NULL)
...@@ -320,9 +293,6 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -320,9 +293,6 @@ btbuild(PG_FUNCTION_ARGS)
} }
} }
pfree(nulls);
pfree(attdata);
/* all done */ /* all done */
BuildingBtree = false; BuildingBtree = false;
...@@ -361,8 +331,7 @@ btinsert(PG_FUNCTION_ARGS) ...@@ -361,8 +331,7 @@ btinsert(PG_FUNCTION_ARGS)
btitem = _bt_formitem(itup); btitem = _bt_formitem(itup);
res = _bt_doinsert(rel, btitem, res = _bt_doinsert(rel, btitem, rel->rd_uniqueindex, heapRel);
IndexIsUnique(RelationGetRelid(rel)), heapRel);
pfree(btitem); pfree(btitem);
pfree(itup); pfree(itup);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.51 2000/07/12 02:36:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.52 2000/07/14 22:17:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -64,49 +64,37 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -64,49 +64,37 @@ rtbuild(PG_FUNCTION_ARGS)
{ {
Relation heap = (Relation) PG_GETARG_POINTER(0); Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1); Relation index = (Relation) PG_GETARG_POINTER(1);
int32 natts = PG_GETARG_INT32(2); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
AttrNumber *attnum = (AttrNumber *) PG_GETARG_POINTER(3); Node *oldPred = (Node *) PG_GETARG_POINTER(3);
FuncIndexInfo *finfo = (FuncIndexInfo *) PG_GETARG_POINTER(4);
PredInfo *predInfo = (PredInfo *) PG_GETARG_POINTER(5);
#ifdef NOT_USED #ifdef NOT_USED
bool unique = PG_GETARG_BOOL(6); IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(4);
IndexStrategy istrat = (IndexStrategy) PG_GETARG_POINTER(7);
#endif #endif
HeapScanDesc scan; HeapScanDesc hscan;
AttrNumber i;
HeapTuple htup; HeapTuple htup;
IndexTuple itup; IndexTuple itup;
TupleDesc hd, TupleDesc htupdesc,
id; itupdesc;
InsertIndexResult res; Datum attdata[INDEX_MAX_KEYS];
Datum *d; char nulls[INDEX_MAX_KEYS];
bool *nulls; int nhtups,
Buffer buffer = InvalidBuffer; nitups;
int nb, Node *pred = indexInfo->ii_Predicate;
nh,
ni;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot; TupleTableSlot *slot;
#endif #endif
Node *pred, ExprContext *econtext;
*oldPred; InsertIndexResult res = NULL;
Buffer buffer = InvalidBuffer;
RTSTATE rtState; RTSTATE rtState;
initRtstate(&rtState, index); initRtstate(&rtState, index);
pred = predInfo->pred;
oldPred = predInfo->oldPred;
/* /*
* We expect to be called exactly once for any index relation. If * We expect to be called exactly once for any index relation. If
* that's not the case, big trouble's what we have. * that's not the case, big trouble's what we have.
*/ */
if (oldPred == NULL && RelationGetNumberOfBlocks(index) != 0)
if (oldPred == NULL && (nb = RelationGetNumberOfBlocks(index)) != 0)
elog(ERROR, "%s already contains data", RelationGetRelationName(index)); elog(ERROR, "%s already contains data", RelationGetRelationName(index));
/* initialize the root page (if this is a new index) */ /* initialize the root page (if this is a new index) */
...@@ -117,44 +105,48 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -117,44 +105,48 @@ rtbuild(PG_FUNCTION_ARGS)
WriteBuffer(buffer); WriteBuffer(buffer);
} }
/* init the tuple descriptors and get set for a heap scan */ /* get tuple descriptors for heap and index relations */
hd = RelationGetDescr(heap); htupdesc = RelationGetDescr(heap);
id = RelationGetDescr(index); itupdesc = RelationGetDescr(index);
d = (Datum *) palloc(natts * sizeof(*d));
nulls = (bool *) palloc(natts * sizeof(*nulls));
/* /*
* If this is a predicate (partial) index, we will need to evaluate * If this is a predicate (partial) index, we will need to evaluate
* the predicate using ExecQual, which requires the current tuple to * the predicate using ExecQual, which requires the current tuple to
* be in a slot of a TupleTable. In addition, ExecQual must have an * be in a slot of a TupleTable. In addition, ExecQual must have an
* ExprContext referring to that slot. Here, we initialize dummy * ExprContext referring to that slot. Here, we initialize dummy
* TupleTable and ExprContext objects for this purpose. --Nels, Feb * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
* '92 *
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/ */
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, hd); ExecSetSlotDescriptor(slot, htupdesc);
econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
{ {
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
econtext = NULL;
} }
econtext = MakeExprContext(slot, TransactionCommandContext);
#else
econtext = MakeExprContext(NULL, TransactionCommandContext);
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
/* count the tuples as we insert them */ /* count the tuples as we insert them */
nh = ni = 0; nhtups = nitups = 0;
scan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL); /* start a heap scan */
hscan = heap_beginscan(heap, 0, SnapshotNow, 0, (ScanKey) NULL);
while (HeapTupleIsValid(htup = heap_getnext(scan, 0))) while (HeapTupleIsValid(htup = heap_getnext(hscan, 0)))
{ {
nh++; MemoryContextReset(econtext->ecxt_per_tuple_memory);
nhtups++;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
/* /*
...@@ -163,11 +155,10 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -163,11 +155,10 @@ rtbuild(PG_FUNCTION_ARGS)
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
{ {
ni++; nitups++;
continue; continue;
} }
} }
...@@ -178,47 +169,27 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -178,47 +169,27 @@ rtbuild(PG_FUNCTION_ARGS)
*/ */
if (pred != NULL) if (pred != NULL)
{ {
/* SetSlotContents(slot, htup); */
slot->val = htup; slot->val = htup;
if (!ExecQual((List *) pred, econtext, false)) if (!ExecQual((List *) pred, econtext, false))
continue; continue;
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
ni++; nitups++;
/* /*
* For the current heap tuple, extract all the attributes we use * For the current heap tuple, extract all the attributes we use
* in this index, and note which are null. * in this index, and note which are null.
*/ */
FormIndexDatum(indexInfo,
for (i = 1; i <= natts; i++) htup,
{ htupdesc,
int attoff; econtext->ecxt_per_tuple_memory,
bool attnull; attdata,
nulls);
/*
* Offsets are from the start of the tuple, and are
* zero-based; indices are one-based. The next call returns i
* - 1. That's data hiding for you.
*/
attoff = AttrNumberGetAttrOffset(i);
/*
* d[attoff] = HeapTupleGetAttributeValue(htup, buffer,
*/
d[attoff] = GetIndexValue(htup,
hd,
attoff,
attnum,
finfo,
&attnull);
nulls[attoff] = (attnull ? 'n' : ' ');
}
/* form an index tuple and point it at the heap tuple */ /* form an index tuple and point it at the heap tuple */
itup = index_formtuple(id, &d[0], nulls); itup = index_formtuple(itupdesc, attdata, nulls);
itup->t_tid = htup->t_self; itup->t_tid = htup->t_self;
/* /*
...@@ -235,15 +206,15 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -235,15 +206,15 @@ rtbuild(PG_FUNCTION_ARGS)
} }
/* okay, all heap tuples are indexed */ /* okay, all heap tuples are indexed */
heap_endscan(scan); heap_endscan(hscan);
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (pred != NULL || oldPred != NULL) if (pred != NULL || oldPred != NULL)
{ {
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
...@@ -264,20 +235,16 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -264,20 +235,16 @@ rtbuild(PG_FUNCTION_ARGS)
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
UpdateStats(hrelid, nh, inplace); UpdateStats(hrelid, nhtups, inplace);
UpdateStats(irelid, ni, inplace); UpdateStats(irelid, nitups, inplace);
if (oldPred != NULL && !inplace) if (oldPred != NULL && !inplace)
{ {
if (ni == nh) if (nitups == nhtups)
pred = NULL; pred = NULL;
UpdateIndexPredicate(irelid, oldPred, pred); UpdateIndexPredicate(irelid, oldPred, pred);
} }
} }
/* be tidy */
pfree(nulls);
pfree(d);
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.31 2000/07/04 06:11:22 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.32 2000/07/14 22:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "access/attnum.h" #include "access/attnum.h"
#include "access/funcindex.h"
#include "access/htup.h" #include "access/htup.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/skey.h" #include "access/skey.h"
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.17 2000/01/26 05:56:07 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootscanner.l,v 1.18 2000/07/14 22:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include "postgres.h" #include "postgres.h"
#include "access/attnum.h" #include "access/attnum.h"
#include "access/funcindex.h"
#include "access/htup.h" #include "access/htup.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/skey.h" #include "access/skey.h"
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.90 2000/07/03 23:09:23 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.91 2000/07/14 22:17:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -160,20 +160,12 @@ typedef struct _IndexList ...@@ -160,20 +160,12 @@ typedef struct _IndexList
{ {
char *il_heap; char *il_heap;
char *il_ind; char *il_ind;
int il_natts; IndexInfo *il_info;
AttrNumber *il_attnos;
FuncIndexInfo *il_finfo;
PredInfo *il_predInfo;
bool il_unique;
struct _IndexList *il_next; struct _IndexList *il_next;
} IndexList; } IndexList;
static IndexList *ILHead = (IndexList *) NULL; static IndexList *ILHead = (IndexList *) NULL;
typedef void (*sig_func) ();
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* misc functions * misc functions
...@@ -334,9 +326,9 @@ BootstrapMain(int argc, char *argv[]) ...@@ -334,9 +326,9 @@ BootstrapMain(int argc, char *argv[])
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
pqsignal(SIGINT, (sig_func) die); pqsignal(SIGINT, (pqsigfunc) die);
pqsignal(SIGHUP, (sig_func) die); pqsignal(SIGHUP, (pqsigfunc) die);
pqsignal(SIGTERM, (sig_func) die); pqsignal(SIGTERM, (pqsigfunc) die);
} }
/* /*
...@@ -1080,14 +1072,9 @@ AddStr(char *str, int strlength, int mderef) ...@@ -1080,14 +1072,9 @@ AddStr(char *str, int strlength, int mderef)
void void
index_register(char *heap, index_register(char *heap,
char *ind, char *ind,
int natts, IndexInfo *indexInfo)
AttrNumber *attnos,
FuncIndexInfo *finfo,
PredInfo *predInfo,
bool unique)
{ {
IndexList *newind; IndexList *newind;
int len;
MemoryContext oldcxt; MemoryContext oldcxt;
/* /*
...@@ -1108,37 +1095,13 @@ index_register(char *heap, ...@@ -1108,37 +1095,13 @@ index_register(char *heap,
newind = (IndexList *) palloc(sizeof(IndexList)); newind = (IndexList *) palloc(sizeof(IndexList));
newind->il_heap = pstrdup(heap); newind->il_heap = pstrdup(heap);
newind->il_ind = pstrdup(ind); newind->il_ind = pstrdup(ind);
newind->il_natts = natts; newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
if (PointerIsValid(finfo))
len = FIgetnArgs(finfo) * sizeof(AttrNumber);
else
len = natts * sizeof(AttrNumber);
newind->il_attnos = (AttrNumber *) palloc(len);
memcpy(newind->il_attnos, attnos, len);
if (PointerIsValid(finfo))
{
newind->il_finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
memcpy(newind->il_finfo, finfo, sizeof(FuncIndexInfo));
}
else
newind->il_finfo = (FuncIndexInfo *) NULL;
if (predInfo != NULL) memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
{ /* predicate will likely be null anyway, but may as well copy it */
newind->il_predInfo = (PredInfo *) palloc(sizeof(PredInfo)); newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate);
newind->il_predInfo->pred = predInfo->pred;
newind->il_predInfo->oldPred = predInfo->oldPred;
}
else
newind->il_predInfo = NULL;
newind->il_unique = unique;
newind->il_next = ILHead; newind->il_next = ILHead;
ILHead = newind; ILHead = newind;
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
...@@ -1147,18 +1110,16 @@ index_register(char *heap, ...@@ -1147,18 +1110,16 @@ index_register(char *heap,
void void
build_indices() build_indices()
{ {
Relation heap;
Relation ind;
for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next) for (; ILHead != (IndexList *) NULL; ILHead = ILHead->il_next)
{ {
Relation heap;
Relation ind;
heap = heap_openr(ILHead->il_heap, NoLock); heap = heap_openr(ILHead->il_heap, NoLock);
Assert(heap); Assert(heap);
ind = index_openr(ILHead->il_ind); ind = index_openr(ILHead->il_ind);
Assert(ind); Assert(ind);
index_build(heap, ind, ILHead->il_natts, ILHead->il_attnos, index_build(heap, ind, ILHead->il_info, NULL);
ILHead->il_finfo, ILHead->il_predInfo,
ILHead->il_unique);
/* /*
* In normal processing mode, index_build would close the heap and * In normal processing mode, index_build would close the heap and
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.139 2000/07/05 23:11:06 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.140 2000/07/14 22:17:40 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1073,91 +1073,37 @@ RelationTruncateIndexes(Relation heapRelation) ...@@ -1073,91 +1073,37 @@ RelationTruncateIndexes(Relation heapRelation)
ScanKeyData entry; ScanKeyData entry;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple indexTuple, HeapTuple indexTuple,
procTuple,
classTuple; classTuple;
Form_pg_index index; IndexInfo *indexInfo;
Oid heapId, Oid heapId,
indexId, indexId,
procId,
accessMethodId; accessMethodId;
Node *oldPred = NULL;
PredInfo *predInfo;
List *cnfPred = NULL;
AttrNumber *attributeNumberA;
FuncIndexInfo fInfo,
*funcInfo = NULL;
bool unique;
int i,
numberOfAttributes;
char *predString;
heapId = RelationGetRelid(heapRelation); heapId = RelationGetRelid(heapRelation);
/* Scan pg_index to find indexes on heapRelation */ /* Scan pg_index to find indexes on heapRelation */
indexRelation = heap_openr(IndexRelationName, AccessShareLock); indexRelation = heap_openr(IndexRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ, ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ,
ObjectIdGetDatum(heapId)); ObjectIdGetDatum(heapId));
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry); scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0))) while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0)))
{ {
/* /*
* For each index, fetch index attributes so we can apply * For each index, fetch info needed for index_build
* index_build
*/ */
index = (Form_pg_index) GETSTRUCT(indexTuple); indexId = ((Form_pg_index) GETSTRUCT(indexTuple))->indexrelid;
indexId = index->indexrelid; indexInfo = BuildIndexInfo(indexTuple);
procId = index->indproc;
unique = index->indisunique;
for (i = 0; i < INDEX_MAX_KEYS; i++)
{
if (index->indkey[i] == InvalidAttrNumber)
break;
}
numberOfAttributes = i;
/* If a valid where predicate, compute predicate Node */
if (VARSIZE(&index->indpred) != 0)
{
predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&index->indpred)));
oldPred = stringToNode(predString);
pfree(predString);
}
predInfo = (PredInfo *) palloc(sizeof(PredInfo));
predInfo->pred = (Node *) cnfPred;
predInfo->oldPred = oldPred;
/* Assign Index keys to attributes array */
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
sizeof(AttrNumber));
for (i = 0; i < numberOfAttributes; i++)
attributeNumberA[i] = index->indkey[i];
/* If this is a procedural index, initialize our FuncIndexInfo */
if (procId != InvalidOid)
{
funcInfo = &fInfo;
FIsetnArgs(funcInfo, numberOfAttributes);
procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId),
0, 0, 0);
if (!HeapTupleIsValid(procTuple))
elog(ERROR, "RelationTruncateIndexes: index procedure not found");
namecpy(&(funcInfo->funcName),
&(((Form_pg_proc) GETSTRUCT(procTuple))->proname));
FIsetProcOid(funcInfo, procTuple->t_data->t_oid);
}
/* Fetch the classTuple associated with this index */ /* Fetch the pg_class tuple associated with this index */
classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId), classTuple = SearchSysCacheTupleCopy(RELOID,
ObjectIdGetDatum(indexId),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(classTuple)) if (!HeapTupleIsValid(classTuple))
elog(ERROR, "RelationTruncateIndexes: index access method not found"); elog(ERROR, "RelationTruncateIndexes: index %u not found in pg_class",
indexId);
accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam; accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
/* Open our index relation */ /* Open the index relation */
currentIndex = index_open(indexId); currentIndex = index_open(indexId);
if (currentIndex == NULL) if (currentIndex == NULL)
elog(ERROR, "RelationTruncateIndexes: can't open index relation"); elog(ERROR, "RelationTruncateIndexes: can't open index relation");
...@@ -1176,9 +1122,9 @@ RelationTruncateIndexes(Relation heapRelation) ...@@ -1176,9 +1122,9 @@ RelationTruncateIndexes(Relation heapRelation)
currentIndex->rd_nblocks = 0; currentIndex->rd_nblocks = 0;
/* Initialize the index and rebuild */ /* Initialize the index and rebuild */
InitIndexStrategy(numberOfAttributes, currentIndex, accessMethodId); InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
index_build(heapRelation, currentIndex, numberOfAttributes, currentIndex, accessMethodId);
attributeNumberA, funcInfo, predInfo, unique); index_build(heapRelation, currentIndex, indexInfo, NULL);
/* /*
* index_build will close both the heap and index relations (but * index_build will close both the heap and index relations (but
......
...@@ -8,13 +8,14 @@ ...@@ -8,13 +8,14 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.125 2000/07/12 02:36:55 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.126 2000/07/14 22:17:41 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
* index_create() - Create a cataloged index relation * index_create() - Create a cataloged index relation
* index_drop() - Removes index relation from catalogs * index_drop() - Removes index relation from catalogs
* * BuildIndexInfo() - Prepare to insert index tuples
* FormIndexDatum() - Construct datum vector for one index tuple
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -58,28 +59,29 @@ ...@@ -58,28 +59,29 @@
/* non-export function prototypes */ /* non-export function prototypes */
static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName, static Oid GetHeapRelationOid(char *heapRelationName, char *indexRelationName,
bool istemp); bool istemp);
static TupleDesc BuildFuncTupleDesc(FuncIndexInfo *funcInfo); static TupleDesc BuildFuncTupleDesc(Oid funcOid);
static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation, static TupleDesc ConstructTupleDescriptor(Oid heapoid, Relation heapRelation,
List *attributeList, int numatts, AttrNumber *attNums); int numatts, AttrNumber *attNums);
static void ConstructIndexReldesc(Relation indexRelation, Oid amoid); static void ConstructIndexReldesc(Relation indexRelation, Oid amoid);
static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname); static Oid UpdateRelationRelation(Relation indexRelation, char *temp_relname);
static void InitializeAttributeOids(Relation indexRelation, static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid); int numatts, Oid indexoid);
static void AppendAttributeTuples(Relation indexRelation, int numatts); static void AppendAttributeTuples(Relation indexRelation, int numatts);
static void UpdateIndexRelation(Oid indexoid, Oid heapoid, static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
FuncIndexInfo *funcInfo, int natts, IndexInfo *indexInfo,
AttrNumber *attNums, Oid *classOids, Node *predicate, Oid *classOids,
List *attributeList, bool islossy, bool unique, bool primary); bool islossy, bool primary);
static void DefaultBuild(Relation heapRelation, Relation indexRelation, static void DefaultBuild(Relation heapRelation, Relation indexRelation,
int numberOfAttributes, AttrNumber *attributeNumber, IndexInfo *indexInfo, Node *oldPred,
FuncIndexInfoPtr funcInfo, PredInfo *predInfo, IndexStrategy indexStrategy);
bool unique, IndexStrategy indexStrategy);
static Oid IndexGetRelation(Oid indexId); static Oid IndexGetRelation(Oid indexId);
static bool activate_index(Oid indexId, bool activate); static bool activate_index(Oid indexId, bool activate);
static bool reindexing = false; static bool reindexing = false;
extern bool
bool
SetReindexProcessing(bool reindexmode) SetReindexProcessing(bool reindexmode)
{ {
bool old = reindexing; bool old = reindexing;
...@@ -87,7 +89,8 @@ SetReindexProcessing(bool reindexmode) ...@@ -87,7 +89,8 @@ SetReindexProcessing(bool reindexmode)
reindexing = reindexmode; reindexing = reindexmode;
return old; return old;
} }
extern bool
bool
IsReindexProcessing(void) IsReindexProcessing(void)
{ {
return reindexing; return reindexing;
...@@ -154,14 +157,11 @@ GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp) ...@@ -154,14 +157,11 @@ GetHeapRelationOid(char *heapRelationName, char *indexRelationName, bool istemp)
} }
static TupleDesc static TupleDesc
BuildFuncTupleDesc(FuncIndexInfo *funcInfo) BuildFuncTupleDesc(Oid funcOid)
{ {
HeapTuple tuple;
TupleDesc funcTupDesc; TupleDesc funcTupDesc;
HeapTuple tuple;
Oid retType; Oid retType;
char *funcname;
int4 nargs;
Oid *argtypes;
/* /*
* Allocate and zero a tuple descriptor. * Allocate and zero a tuple descriptor.
...@@ -171,30 +171,29 @@ BuildFuncTupleDesc(FuncIndexInfo *funcInfo) ...@@ -171,30 +171,29 @@ BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE); MemSet(funcTupDesc->attrs[0], 0, ATTRIBUTE_TUPLE_SIZE);
/* /*
* Lookup the function for the return type. * Lookup the function to get its name and return type.
*/ */
funcname = FIgetname(funcInfo); tuple = SearchSysCacheTuple(PROCOID,
nargs = FIgetnArgs(funcInfo); ObjectIdGetDatum(funcOid),
argtypes = FIgetArglist(funcInfo); 0, 0, 0);
tuple = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(funcname),
Int32GetDatum(nargs),
PointerGetDatum(argtypes),
0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
func_error("BuildFuncTupleDesc", funcname, nargs, argtypes, NULL); elog(ERROR, "Function %u does not exist", funcOid);
retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype; retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
/* /*
* Look up the return type in pg_type for the type length. * make the attributes name the same as the functions
*/
namestrcpy(&funcTupDesc->attrs[0]->attname,
NameStr(((Form_pg_proc) GETSTRUCT(tuple))->proname));
/*
* Lookup the return type in pg_type for the type length etc.
*/ */
tuple = SearchSysCacheTuple(TYPEOID, tuple = SearchSysCacheTuple(TYPEOID,
ObjectIdGetDatum(retType), ObjectIdGetDatum(retType),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "Function %s return type does not exist", FIgetname(funcInfo)); elog(ERROR, "Type %u does not exist", retType);
/* /*
* Assign some of the attributes values. Leave the rest as 0. * Assign some of the attributes values. Leave the rest as 0.
...@@ -208,57 +207,48 @@ BuildFuncTupleDesc(FuncIndexInfo *funcInfo) ...@@ -208,57 +207,48 @@ BuildFuncTupleDesc(FuncIndexInfo *funcInfo)
funcTupDesc->attrs[0]->attstorage = 'p'; funcTupDesc->attrs[0]->attstorage = 'p';
funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign; funcTupDesc->attrs[0]->attalign = ((Form_pg_type) GETSTRUCT(tuple))->typalign;
/*
* make the attributes name the same as the functions
*/
namestrcpy(&funcTupDesc->attrs[0]->attname, funcname);
return funcTupDesc; return funcTupDesc;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ConstructTupleDescriptor * ConstructTupleDescriptor
*
* Build an index tuple descriptor for a new index (plain not functional)
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
static TupleDesc static TupleDesc
ConstructTupleDescriptor(Oid heapoid, ConstructTupleDescriptor(Oid heapoid,
Relation heapRelation, Relation heapRelation,
List *attributeList,
int numatts, int numatts,
AttrNumber *attNums) AttrNumber *attNums)
{ {
TupleDesc heapTupDesc; TupleDesc heapTupDesc;
TupleDesc indexTupDesc; TupleDesc indexTupDesc;
IndexElem *IndexKey; int natts; /* #atts in heap rel --- for error checks */
TypeName *IndexKeyType;
AttrNumber atnum; /* attributeNumber[attributeOffset] */
AttrNumber atind;
int natts; /* Form_pg_class->relnatts */
char *from; /* used to simplify memcpy below */
char *to; /* used to simplify memcpy below */
int i; int i;
heapTupDesc = RelationGetDescr(heapRelation);
natts = RelationGetForm(heapRelation)->relnatts;
/* ---------------- /* ----------------
* allocate the new tuple descriptor * allocate the new tuple descriptor
* ---------------- * ----------------
*/ */
natts = RelationGetForm(heapRelation)->relnatts;
indexTupDesc = CreateTemplateTupleDesc(numatts); indexTupDesc = CreateTemplateTupleDesc(numatts);
/* ----------------
*
* ----------------
*/
/* ---------------- /* ----------------
* for each attribute we are indexing, obtain its attribute * for each attribute we are indexing, obtain its attribute
* tuple form from either the static table of system attribute * tuple form from either the static table of system attribute
* tuple forms or the relation tuple descriptor * tuple forms or the relation tuple descriptor
* ---------------- * ----------------
*/ */
for (i = 0; i < numatts; i += 1) for (i = 0; i < numatts; i++)
{ {
AttrNumber atnum; /* attributeNumber[attributeOffset] */
AttrNumber atind;
char *from; /* used to simplify memcpy below */
char *to; /* used to simplify memcpy below */
/* ---------------- /* ----------------
* get the attribute number and make sure it's valid * get the attribute number and make sure it's valid
...@@ -268,16 +258,9 @@ ConstructTupleDescriptor(Oid heapoid, ...@@ -268,16 +258,9 @@ ConstructTupleDescriptor(Oid heapoid,
if (atnum > natts) if (atnum > natts)
elog(ERROR, "Cannot create index: attribute %d does not exist", elog(ERROR, "Cannot create index: attribute %d does not exist",
atnum); atnum);
if (attributeList)
{
IndexKey = (IndexElem *) lfirst(attributeList);
IndexKeyType = IndexKey->typename;
attributeList = lnext(attributeList);
}
else
IndexKeyType = NULL;
indexTupDesc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); indexTupDesc->attrs[i] =
(Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
/* ---------------- /* ----------------
* determine which tuple descriptor to copy * determine which tuple descriptor to copy
...@@ -285,10 +268,9 @@ ConstructTupleDescriptor(Oid heapoid, ...@@ -285,10 +268,9 @@ ConstructTupleDescriptor(Oid heapoid,
*/ */
if (!AttrNumberIsForUserDefinedAttr(atnum)) if (!AttrNumberIsForUserDefinedAttr(atnum))
{ {
/* ---------------- /* ----------------
* here we are indexing on a system attribute (-1...-12) * here we are indexing on a system attribute (-1...-n)
* so we convert atnum into a usable index 0...11 so we can * so we convert atnum into a usable index 0...n-1 so we can
* use it to dereference the array sysatts[] which stores * use it to dereference the array sysatts[] which stores
* tuple descriptor information for system attributes. * tuple descriptor information for system attributes.
* ---------------- * ----------------
...@@ -298,7 +280,6 @@ ConstructTupleDescriptor(Oid heapoid, ...@@ -298,7 +280,6 @@ ConstructTupleDescriptor(Oid heapoid,
atind = (-atnum) - 1; atind = (-atnum) - 1;
from = (char *) (&sysatts[atind]); from = (char *) (&sysatts[atind]);
} }
else else
{ {
...@@ -306,7 +287,6 @@ ConstructTupleDescriptor(Oid heapoid, ...@@ -306,7 +287,6 @@ ConstructTupleDescriptor(Oid heapoid,
* here we are indexing on a normal attribute (1...n) * here we are indexing on a normal attribute (1...n)
* ---------------- * ----------------
*/ */
heapTupDesc = RelationGetDescr(heapRelation);
atind = AttrNumberGetAttrOffset(atnum); atind = AttrNumberGetAttrOffset(atnum);
from = (char *) (heapTupDesc->attrs[atind]); from = (char *) (heapTupDesc->attrs[atind]);
...@@ -317,43 +297,18 @@ ConstructTupleDescriptor(Oid heapoid, ...@@ -317,43 +297,18 @@ ConstructTupleDescriptor(Oid heapoid,
* the tuple desc data... * the tuple desc data...
* ---------------- * ----------------
*/ */
to = (char *) (indexTupDesc->attrs[i]); to = (char *) (indexTupDesc->attrs[i]);
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE); memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
/*
* Fix the stuff that should not be the same as the underlying attr
*/
((Form_pg_attribute) to)->attnum = i + 1; ((Form_pg_attribute) to)->attnum = i + 1;
((Form_pg_attribute) to)->attdisbursion = 0.0;
((Form_pg_attribute) to)->attnotnull = false; ((Form_pg_attribute) to)->attnotnull = false;
((Form_pg_attribute) to)->atthasdef = false; ((Form_pg_attribute) to)->atthasdef = false;
((Form_pg_attribute) to)->attcacheoff = -1; ((Form_pg_attribute) to)->attcacheoff = -1;
((Form_pg_attribute) to)->atttypmod = -1;
((Form_pg_attribute) to)->attalign = 'i';
/*
* if the keytype is defined, we need to change the tuple form's
* atttypid & attlen field to match that of the key's type
*/
if (IndexKeyType != NULL)
{
HeapTuple tup;
tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(IndexKeyType->name),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "create index: type '%s' undefined",
IndexKeyType->name);
((Form_pg_attribute) to)->atttypid = tup->t_data->t_oid;
((Form_pg_attribute) to)->attbyval =
((Form_pg_type) GETSTRUCT(tup))->typbyval;
((Form_pg_attribute) to)->attlen =
((Form_pg_type) GETSTRUCT(tup))->typlen;
((Form_pg_attribute) to)->attstorage = 'p';
((Form_pg_attribute) to)->attalign =
((Form_pg_type) GETSTRUCT(tup))->typalign;
((Form_pg_attribute) to)->atttypmod = IndexKeyType->typmod;
}
/* ---------------- /* ----------------
* now we have to drop in the proper relation descriptor * now we have to drop in the proper relation descriptor
...@@ -539,17 +494,14 @@ AppendAttributeTuples(Relation indexRelation, int numatts) ...@@ -539,17 +494,14 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
new_tuple; new_tuple;
bool hasind; bool hasind;
Relation idescs[Num_pg_attr_indices]; Relation idescs[Num_pg_attr_indices];
Datum value[Natts_pg_attribute]; Datum value[Natts_pg_attribute];
char nullv[Natts_pg_attribute]; char nullv[Natts_pg_attribute];
char replace[Natts_pg_attribute]; char replace[Natts_pg_attribute];
TupleDesc indexTupDesc; TupleDesc indexTupDesc;
int i; int i;
/* ---------------- /* ----------------
* open the attribute relation * open the attribute relation
* XXX ADD INDEXING
* ---------------- * ----------------
*/ */
pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock); pg_attribute = heap_openr(AttributeRelationName, RowExclusiveLock);
...@@ -641,7 +593,6 @@ AppendAttributeTuples(Relation indexRelation, int numatts) ...@@ -641,7 +593,6 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
heap_close(pg_attribute, RowExclusiveLock); heap_close(pg_attribute, RowExclusiveLock);
if (hasind) if (hasind)
CatalogCloseIndices(Num_pg_attr_indices, idescs); CatalogCloseIndices(Num_pg_attr_indices, idescs);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -651,18 +602,12 @@ AppendAttributeTuples(Relation indexRelation, int numatts) ...@@ -651,18 +602,12 @@ AppendAttributeTuples(Relation indexRelation, int numatts)
static void static void
UpdateIndexRelation(Oid indexoid, UpdateIndexRelation(Oid indexoid,
Oid heapoid, Oid heapoid,
FuncIndexInfo *funcInfo, IndexInfo *indexInfo,
int natts,
AttrNumber *attNums,
Oid *classOids, Oid *classOids,
Node *predicate,
List *attributeList,
bool islossy, bool islossy,
bool unique,
bool primary) bool primary)
{ {
Form_pg_index indexForm; Form_pg_index indexForm;
IndexElem *IndexKey;
char *predString; char *predString;
text *predText; text *predText;
int predLen, int predLen,
...@@ -673,13 +618,13 @@ UpdateIndexRelation(Oid indexoid, ...@@ -673,13 +618,13 @@ UpdateIndexRelation(Oid indexoid,
Relation idescs[Num_pg_index_indices]; Relation idescs[Num_pg_index_indices];
/* ---------------- /* ----------------
* allocate an Form_pg_index big enough to hold the * allocate a Form_pg_index big enough to hold the
* index-predicate (if any) in string form * index-predicate (if any) in string form
* ---------------- * ----------------
*/ */
if (predicate != NULL) if (indexInfo->ii_Predicate != NULL)
{ {
predString = nodeToString(predicate); predString = nodeToString(indexInfo->ii_Predicate);
predText = DatumGetTextP(DirectFunctionCall1(textin, predText = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(predString))); CStringGetDatum(predString)));
pfree(predString); pfree(predString);
...@@ -691,57 +636,33 @@ UpdateIndexRelation(Oid indexoid, ...@@ -691,57 +636,33 @@ UpdateIndexRelation(Oid indexoid,
predLen = VARSIZE(predText); predLen = VARSIZE(predText);
itupLen = predLen + sizeof(FormData_pg_index); itupLen = predLen + sizeof(FormData_pg_index);
indexForm = (Form_pg_index) palloc(itupLen); indexForm = (Form_pg_index) palloc(itupLen);
memset(indexForm, 0, sizeof(FormData_pg_index)); MemSet(indexForm, 0, sizeof(FormData_pg_index));
memmove((char *) &indexForm->indpred, (char *) predText, predLen);
/* ---------------- /* ----------------
* store the oid information into the index tuple form * store information into the index tuple form
* ---------------- * ----------------
*/ */
indexForm->indrelid = heapoid;
indexForm->indexrelid = indexoid; indexForm->indexrelid = indexoid;
indexForm->indproc = (PointerIsValid(funcInfo)) ? indexForm->indrelid = heapoid;
FIgetProcOid(funcInfo) : InvalidOid; indexForm->indproc = indexInfo->ii_FuncOid;
indexForm->indisclustered = false;
indexForm->indislossy = islossy; indexForm->indislossy = islossy;
indexForm->indhaskeytype = true; /* not actually used anymore */
indexForm->indisunique = indexInfo->ii_Unique;
indexForm->indisprimary = primary; indexForm->indisprimary = primary;
indexForm->indisunique = unique; memcpy((char *) &indexForm->indpred, (char *) predText, predLen);
indexForm->indhaskeytype = 0;
while (attributeList != NIL)
{
IndexKey = (IndexElem *) lfirst(attributeList);
if (IndexKey->typename != NULL)
{
indexForm->indhaskeytype = 1;
break;
}
attributeList = lnext(attributeList);
}
MemSet((char *) &indexForm->indkey[0], 0, sizeof indexForm->indkey);
MemSet((char *) &indexForm->indclass[0], 0, sizeof indexForm->indclass);
/* ---------------- /* ----------------
* copy index key and op class information * copy index key and op class information
*
* We zeroed the extra slots (if any) above --- that's essential.
* ---------------- * ----------------
*/ */
for (i = 0; i < natts; i += 1) for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
{ indexForm->indkey[i] = indexInfo->ii_KeyAttrNumbers[i];
indexForm->indkey[i] = attNums[i];
indexForm->indclass[i] = classOids[i];
}
/*
* If we have a functional index, add all attribute arguments
*/
if (PointerIsValid(funcInfo))
{
for (i = 1; i < FIgetnArgs(funcInfo); i++)
indexForm->indkey[i] = attNums[i];
}
indexForm->indisclustered = '\0'; /* XXX constant */ for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
indexForm->indclass[i] = classOids[i];
/* ---------------- /* ----------------
* open the system catalog index relation * open the system catalog index relation
...@@ -759,13 +680,12 @@ UpdateIndexRelation(Oid indexoid, ...@@ -759,13 +680,12 @@ UpdateIndexRelation(Oid indexoid,
/* ---------------- /* ----------------
* insert the tuple into the pg_index * insert the tuple into the pg_index
* XXX ADD INDEX TUPLES TOO
* ---------------- * ----------------
*/ */
heap_insert(pg_index, tuple); heap_insert(pg_index, tuple);
/* ---------------- /* ----------------
* insert the index tuple into the pg_index * add index tuples for it
* ---------------- * ----------------
*/ */
if (!IsIgnoringSystemIndexes()) if (!IsIgnoringSystemIndexes())
...@@ -774,6 +694,7 @@ UpdateIndexRelation(Oid indexoid, ...@@ -774,6 +694,7 @@ UpdateIndexRelation(Oid indexoid,
CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple); CatalogIndexInsert(idescs, Num_pg_index_indices, pg_index, tuple);
CatalogCloseIndices(Num_pg_index_indices, idescs); CatalogCloseIndices(Num_pg_index_indices, idescs);
} }
/* ---------------- /* ----------------
* close the relation and free the tuple * close the relation and free the tuple
* ---------------- * ----------------
...@@ -923,6 +844,7 @@ InitIndexStrategy(int numatts, ...@@ -923,6 +844,7 @@ InitIndexStrategy(int numatts,
CommandCounterIncrement(); CommandCounterIncrement();
IndexSupportInitialize(strategy, support, IndexSupportInitialize(strategy, support,
&indexRelation->rd_uniqueindex,
attrelid, accessMethodObjectId, attrelid, accessMethodObjectId,
amstrategies, amsupport, numatts); amstrategies, amsupport, numatts);
...@@ -941,15 +863,10 @@ InitIndexStrategy(int numatts, ...@@ -941,15 +863,10 @@ InitIndexStrategy(int numatts,
void void
index_create(char *heapRelationName, index_create(char *heapRelationName,
char *indexRelationName, char *indexRelationName,
FuncIndexInfo *funcInfo, IndexInfo *indexInfo,
List *attributeList,
Oid accessMethodObjectId, Oid accessMethodObjectId,
int numatts,
AttrNumber *attNums,
Oid *classObjectId, Oid *classObjectId,
Node *predicate,
bool islossy, bool islossy,
bool unique,
bool primary, bool primary,
bool allow_system_table_mods) bool allow_system_table_mods)
{ {
...@@ -958,16 +875,17 @@ index_create(char *heapRelationName, ...@@ -958,16 +875,17 @@ index_create(char *heapRelationName,
TupleDesc indexTupDesc; TupleDesc indexTupDesc;
Oid heapoid; Oid heapoid;
Oid indexoid; Oid indexoid;
PredInfo *predInfo;
bool istemp = (get_temp_rel_by_username(heapRelationName) != NULL); bool istemp = (get_temp_rel_by_username(heapRelationName) != NULL);
char *temp_relname = NULL; char *temp_relname = NULL;
SetReindexProcessing(false);
/* ---------------- /* ----------------
* check parameters * check parameters
* ---------------- * ----------------
*/ */
SetReindexProcessing(false); if (indexInfo->ii_NumIndexAttrs < 1 ||
if (numatts < 1) indexInfo->ii_NumKeyAttrs < 1)
elog(ERROR, "must index at least one attribute"); elog(ERROR, "must index at least one attribute");
/* ---------------- /* ----------------
...@@ -985,14 +903,13 @@ index_create(char *heapRelationName, ...@@ -985,14 +903,13 @@ index_create(char *heapRelationName,
* construct new tuple descriptor * construct new tuple descriptor
* ---------------- * ----------------
*/ */
if (PointerIsValid(funcInfo)) if (OidIsValid(indexInfo->ii_FuncOid))
indexTupDesc = BuildFuncTupleDesc(funcInfo); indexTupDesc = BuildFuncTupleDesc(indexInfo->ii_FuncOid);
else else
indexTupDesc = ConstructTupleDescriptor(heapoid, indexTupDesc = ConstructTupleDescriptor(heapoid,
heapRelation, heapRelation,
attributeList, indexInfo->ii_NumKeyAttrs,
numatts, indexInfo->ii_KeyAttrNumbers);
attNums);
if (istemp) if (istemp)
{ {
...@@ -1035,13 +952,15 @@ index_create(char *heapRelationName, ...@@ -1035,13 +952,15 @@ index_create(char *heapRelationName,
* tuple forms in the index relation's tuple descriptor * tuple forms in the index relation's tuple descriptor
* ---------------- * ----------------
*/ */
InitializeAttributeOids(indexRelation, numatts, indexoid); InitializeAttributeOids(indexRelation,
indexInfo->ii_NumIndexAttrs,
indexoid);
/* ---------------- /* ----------------
* append ATTRIBUTE tuples * append ATTRIBUTE tuples for the index
* ---------------- * ----------------
*/ */
AppendAttributeTuples(indexRelation, numatts); AppendAttributeTuples(indexRelation, indexInfo->ii_NumIndexAttrs);
/* ---------------- /* ----------------
* update pg_index * update pg_index
...@@ -1051,19 +970,16 @@ index_create(char *heapRelationName, ...@@ -1051,19 +970,16 @@ index_create(char *heapRelationName,
* (Or, could define a rule to maintain the predicate) --Nels, Feb '92 * (Or, could define a rule to maintain the predicate) --Nels, Feb '92
* ---------------- * ----------------
*/ */
UpdateIndexRelation(indexoid, heapoid, funcInfo, UpdateIndexRelation(indexoid, heapoid, indexInfo,
numatts, attNums, classObjectId, predicate, classObjectId, islossy, primary);
attributeList, islossy, unique, primary);
predInfo = (PredInfo *) palloc(sizeof(PredInfo));
predInfo->pred = predicate;
predInfo->oldPred = NULL;
/* ---------------- /* ----------------
* initialize the index strategy * initialize the index strategy
* ---------------- * ----------------
*/ */
InitIndexStrategy(numatts, indexRelation, accessMethodObjectId); InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
indexRelation,
accessMethodObjectId);
/* /*
* If this is bootstrap (initdb) time, then we don't actually fill in * If this is bootstrap (initdb) time, then we don't actually fill in
...@@ -1078,14 +994,12 @@ index_create(char *heapRelationName, ...@@ -1078,14 +994,12 @@ index_create(char *heapRelationName,
*/ */
if (IsBootstrapProcessingMode()) if (IsBootstrapProcessingMode())
{ {
index_register(heapRelationName, indexRelationName, numatts, attNums, index_register(heapRelationName, indexRelationName, indexInfo);
funcInfo, predInfo, unique);
/* XXX shouldn't we close the heap and index rels here? */ /* XXX shouldn't we close the heap and index rels here? */
} }
else else
{ {
index_build(heapRelation, indexRelation, numatts, attNums, index_build(heapRelation, indexRelation, indexInfo, NULL);
funcInfo, predInfo, unique);
} }
} }
...@@ -1238,43 +1152,163 @@ index_drop(Oid indexId) ...@@ -1238,43 +1152,163 @@ index_drop(Oid indexId)
* index_build support * index_build support
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* ----------------
* BuildIndexInfo
* Construct an IndexInfo record given the index's pg_index tuple
*
* 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
* just once per command, and then use it for (potentially) many tuples.
* ----------------
*/
IndexInfo *
BuildIndexInfo(HeapTuple indexTuple)
{
Form_pg_index indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
IndexInfo *ii = makeNode(IndexInfo);
int i;
int numKeys;
/* ----------------
* count the number of keys, and copy them into the IndexInfo
* ----------------
*/
numKeys = 0;
for (i = 0; i < INDEX_MAX_KEYS &&
indexStruct->indkey[i] != InvalidAttrNumber; i++)
{
ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i];
numKeys++;
}
ii->ii_NumKeyAttrs = numKeys;
/* ----------------
* Handle functional index.
*
* If we have a functional index then the number of
* attributes defined in the index must be 1 (the function's
* single return value). Otherwise it's same as number of keys.
* ----------------
*/
ii->ii_FuncOid = indexStruct->indproc;
if (OidIsValid(indexStruct->indproc))
{
ii->ii_NumIndexAttrs = 1;
/* Do a lookup on the function, too */
fmgr_info(indexStruct->indproc, & ii->ii_FuncInfo);
}
else
ii->ii_NumIndexAttrs = numKeys;
/* ----------------
* If partial index, convert predicate into expression nodetree
* ----------------
*/
if (VARSIZE(&indexStruct->indpred) != 0)
{
char *predString;
predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&indexStruct->indpred)));
ii->ii_Predicate = stringToNode(predString);
pfree(predString);
}
else
ii->ii_Predicate = NULL;
/* Other info */
ii->ii_Unique = indexStruct->indisunique;
return ii;
}
/* ---------------- /* ----------------
* FormIndexDatum * FormIndexDatum
* Construct Datum[] and nullv[] arrays for a new index tuple.
*
* indexInfo Info about the index
* heapTuple Heap tuple for which we must prepare an index entry
* heapDescriptor tupledesc for heap tuple
* resultCxt Temporary memory context for any palloc'd datums created
* datum Array of index Datums (output area)
* nullv Array of is-null indicators (output area)
*
* For largely historical reasons, we don't actually call index_formtuple()
* here, we just prepare its input arrays datum[] and nullv[].
* ---------------- * ----------------
*/ */
void void
FormIndexDatum(int numberOfAttributes, FormIndexDatum(IndexInfo *indexInfo,
AttrNumber *attributeNumber,
HeapTuple heapTuple, HeapTuple heapTuple,
TupleDesc heapDescriptor, TupleDesc heapDescriptor,
MemoryContext resultCxt,
Datum *datum, Datum *datum,
char *nullv, char *nullv)
FuncIndexInfoPtr fInfo)
{ {
AttrNumber i; MemoryContext oldContext;
int offset; int i;
Datum iDatum;
bool isNull; bool isNull;
/* ---------------- oldContext = MemoryContextSwitchTo(resultCxt);
* for each attribute we need from the heap tuple,
* get the attribute and stick it into the datum and
* null arrays.
* ----------------
*/
for (i = 1; i <= numberOfAttributes; i++) if (OidIsValid(indexInfo->ii_FuncOid))
{ {
offset = AttrNumberGetAttrOffset(i); /* ----------------
* Functional index --- compute the single index attribute
* ----------------
*/
FunctionCallInfoData fcinfo;
bool anynull = false;
datum[offset] = PointerGetDatum(GetIndexValue(heapTuple, MemSet(&fcinfo, 0, sizeof(fcinfo));
heapDescriptor, fcinfo.flinfo = &indexInfo->ii_FuncInfo;
offset, fcinfo.nargs = indexInfo->ii_NumKeyAttrs;
attributeNumber,
fInfo,
&isNull));
nullv[offset] = (isNull) ? 'n' : ' '; for (i = 0; i < indexInfo->ii_NumKeyAttrs; i++)
{
fcinfo.arg[i] = heap_getattr(heapTuple,
indexInfo->ii_KeyAttrNumbers[i],
heapDescriptor,
&fcinfo.argnull[i]);
anynull |= fcinfo.argnull[i];
}
if (indexInfo->ii_FuncInfo.fn_strict && anynull)
{
/* force a null result for strict function */
iDatum = (Datum) 0;
isNull = true;
}
else
{
iDatum = FunctionCallInvoke(&fcinfo);
isNull = fcinfo.isnull;
}
datum[0] = iDatum;
nullv[0] = (isNull) ? 'n' : ' ';
}
else
{
/* ----------------
* Plain index --- for each attribute we need from the heap tuple,
* get the attribute and stick it into the datum and nullv arrays.
* ----------------
*/
for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
{
iDatum = heap_getattr(heapTuple,
indexInfo->ii_KeyAttrNumbers[i],
heapDescriptor,
&isNull);
datum[i] = iDatum;
nullv[i] = (isNull) ? 'n' : ' ';
}
} }
MemoryContextSwitchTo(oldContext);
} }
...@@ -1282,9 +1316,9 @@ FormIndexDatum(int numberOfAttributes, ...@@ -1282,9 +1316,9 @@ FormIndexDatum(int numberOfAttributes,
* Lock class info for update * Lock class info for update
* -------------------------------------------- * --------------------------------------------
*/ */
static static bool
bool LockClassinfoForUpdate(Oid relid, HeapTuple rtup,
LockClassinfoForUpdate(Oid relid, HeapTuple rtup, Buffer *buffer, bool confirmCommitted) Buffer *buffer, bool confirmCommitted)
{ {
HeapTuple classTuple; HeapTuple classTuple;
Form_pg_class pgcform; Form_pg_class pgcform;
...@@ -1429,7 +1463,7 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate) ...@@ -1429,7 +1463,7 @@ setRelhasindexInplace(Oid relid, bool hasindex, bool immediate)
/* /*
* Confirm that target tuple is locked by this transaction in case of * Confirm that target tuple is locked by this transaction in case of
* immedaite updation. * immediate updation.
*/ */
if (immediate) if (immediate)
{ {
...@@ -1682,32 +1716,23 @@ UpdateStats(Oid relid, long reltuples, bool inplace) ...@@ -1682,32 +1716,23 @@ UpdateStats(Oid relid, long reltuples, bool inplace)
static void static void
DefaultBuild(Relation heapRelation, DefaultBuild(Relation heapRelation,
Relation indexRelation, Relation indexRelation,
int numberOfAttributes, IndexInfo *indexInfo,
AttrNumber *attributeNumber, Node *oldPred,
FuncIndexInfoPtr funcInfo,
PredInfo *predInfo,
bool unique, /* not used */
IndexStrategy indexStrategy) /* not used */ IndexStrategy indexStrategy) /* not used */
{ {
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple heapTuple; HeapTuple heapTuple;
IndexTuple indexTuple;
TupleDesc heapDescriptor; TupleDesc heapDescriptor;
TupleDesc indexDescriptor; Datum datum[INDEX_MAX_KEYS];
Datum *datum; char nullv[INDEX_MAX_KEYS];
char *nullv;
long reltuples, long reltuples,
indtuples; indtuples;
Node *predicate = indexInfo->ii_Predicate;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot; TupleTableSlot *slot;
#endif #endif
Node *predicate; ExprContext *econtext;
Node *oldPred;
InsertIndexResult insertResult; InsertIndexResult insertResult;
/* ---------------- /* ----------------
...@@ -1716,48 +1741,33 @@ DefaultBuild(Relation heapRelation, ...@@ -1716,48 +1741,33 @@ DefaultBuild(Relation heapRelation,
*/ */
Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */ Assert(OidIsValid(indexRelation->rd_rel->relam)); /* XXX */
/* ----------------
* get the tuple descriptors from the relations so we know
* how to form the index tuples..
* ----------------
*/
heapDescriptor = RelationGetDescr(heapRelation); heapDescriptor = RelationGetDescr(heapRelation);
indexDescriptor = RelationGetDescr(indexRelation);
/* ----------------
* datum and null are arrays in which we collect the index attributes
* when forming a new index tuple.
* ----------------
*/
datum = (Datum *) palloc(numberOfAttributes * sizeof *datum);
nullv = (char *) palloc(numberOfAttributes * sizeof *nullv);
/* /*
* If this is a predicate (partial) index, we will need to evaluate * If this is a predicate (partial) index, we will need to evaluate
* the predicate using ExecQual, which requires the current tuple to * the predicate using ExecQual, which requires the current tuple to
* be in a slot of a TupleTable. In addition, ExecQual must have an * be in a slot of a TupleTable. In addition, ExecQual must have an
* ExprContext referring to that slot. Here, we initialize dummy * ExprContext referring to that slot. Here, we initialize dummy
* TupleTable and ExprContext objects for this purpose. --Nels, Feb * TupleTable and ExprContext objects for this purpose. --Nels, Feb 92
* '92 *
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/ */
predicate = predInfo->pred;
oldPred = predInfo->oldPred;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (predicate != NULL || oldPred != NULL) if (predicate != NULL || oldPred != NULL)
{ {
tupleTable = ExecCreateTupleTable(1); tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable); slot = ExecAllocTableSlot(tupleTable);
ExecSetSlotDescriptor(slot, heapDescriptor); ExecSetSlotDescriptor(slot, heapDescriptor);
econtext = MakeExprContext(slot, TransactionCommandContext);
} }
else else
{ {
tupleTable = NULL; tupleTable = NULL;
slot = NULL; slot = NULL;
econtext = NULL;
} }
econtext = MakeExprContext(slot, TransactionCommandContext);
#else
econtext = MakeExprContext(NULL, TransactionCommandContext);
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
/* ---------------- /* ----------------
...@@ -1781,6 +1791,8 @@ DefaultBuild(Relation heapRelation, ...@@ -1781,6 +1791,8 @@ DefaultBuild(Relation heapRelation,
*/ */
while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0))) while (HeapTupleIsValid(heapTuple = heap_getnext(scan, 0)))
{ {
MemoryContextReset(econtext->ecxt_per_tuple_memory);
reltuples++; reltuples++;
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
...@@ -1790,7 +1802,6 @@ DefaultBuild(Relation heapRelation, ...@@ -1790,7 +1802,6 @@ DefaultBuild(Relation heapRelation,
*/ */
if (oldPred != NULL) if (oldPred != NULL)
{ {
/* SetSlotContents(slot, heapTuple); */
slot->val = heapTuple; slot->val = heapTuple;
if (ExecQual((List *) oldPred, econtext, false)) if (ExecQual((List *) oldPred, econtext, false))
{ {
...@@ -1805,7 +1816,6 @@ DefaultBuild(Relation heapRelation, ...@@ -1805,7 +1816,6 @@ DefaultBuild(Relation heapRelation,
*/ */
if (predicate != NULL) if (predicate != NULL)
{ {
/* SetSlotContents(slot, heapTuple); */
slot->val = heapTuple; slot->val = heapTuple;
if (!ExecQual((List *) predicate, econtext, false)) if (!ExecQual((List *) predicate, econtext, false))
continue; continue;
...@@ -1819,26 +1829,18 @@ DefaultBuild(Relation heapRelation, ...@@ -1819,26 +1829,18 @@ DefaultBuild(Relation heapRelation,
* with attribute information taken from the given heap tuple. * with attribute information taken from the given heap tuple.
* ---------------- * ----------------
*/ */
FormIndexDatum(numberOfAttributes, /* num attributes */ FormIndexDatum(indexInfo,
attributeNumber, /* array of att nums to extract */ heapTuple,
heapTuple, /* tuple from base relation */ heapDescriptor,
heapDescriptor, /* heap tuple's descriptor */ econtext->ecxt_per_tuple_memory,
datum, /* return: array of attributes */ datum,
nullv, /* return: array of char's */ nullv);
funcInfo);
indexTuple = index_formtuple(indexDescriptor,
datum,
nullv);
indexTuple->t_tid = heapTuple->t_self;
insertResult = index_insert(indexRelation, datum, nullv, insertResult = index_insert(indexRelation, datum, nullv,
&(heapTuple->t_self), heapRelation); &(heapTuple->t_self), heapRelation);
if (insertResult) if (insertResult)
pfree(insertResult); pfree(insertResult);
pfree(indexTuple);
} }
heap_endscan(scan); heap_endscan(scan);
...@@ -1846,14 +1848,10 @@ DefaultBuild(Relation heapRelation, ...@@ -1846,14 +1848,10 @@ DefaultBuild(Relation heapRelation,
#ifndef OMIT_PARTIAL_INDEX #ifndef OMIT_PARTIAL_INDEX
if (predicate != NULL || oldPred != NULL) if (predicate != NULL || oldPred != NULL)
{ {
/* parameter was 'false', almost certainly wrong --- tgl 9/21/99 */
ExecDropTupleTable(tupleTable, true); ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);
} }
#endif /* OMIT_PARTIAL_INDEX */ #endif /* OMIT_PARTIAL_INDEX */
FreeExprContext(econtext);
pfree(nullv);
pfree(datum);
/* /*
* Since we just counted the tuples in the heap, we update its stats * Since we just counted the tuples in the heap, we update its stats
...@@ -1893,11 +1891,8 @@ DefaultBuild(Relation heapRelation, ...@@ -1893,11 +1891,8 @@ DefaultBuild(Relation heapRelation,
void void
index_build(Relation heapRelation, index_build(Relation heapRelation,
Relation indexRelation, Relation indexRelation,
int numberOfAttributes, IndexInfo *indexInfo,
AttrNumber *attributeNumber, Node *oldPred)
FuncIndexInfo *funcInfo,
PredInfo *predInfo,
bool unique)
{ {
RegProcedure procedure; RegProcedure procedure;
...@@ -1915,23 +1910,17 @@ index_build(Relation heapRelation, ...@@ -1915,23 +1910,17 @@ index_build(Relation heapRelation,
* ---------------- * ----------------
*/ */
if (RegProcedureIsValid(procedure)) if (RegProcedureIsValid(procedure))
OidFunctionCall8(procedure, OidFunctionCall5(procedure,
PointerGetDatum(heapRelation), PointerGetDatum(heapRelation),
PointerGetDatum(indexRelation), PointerGetDatum(indexRelation),
Int32GetDatum(numberOfAttributes), PointerGetDatum(indexInfo),
PointerGetDatum(attributeNumber), PointerGetDatum(oldPred),
PointerGetDatum(funcInfo),
PointerGetDatum(predInfo),
BoolGetDatum(unique),
PointerGetDatum(RelationGetIndexStrategy(indexRelation))); PointerGetDatum(RelationGetIndexStrategy(indexRelation)));
else else
DefaultBuild(heapRelation, DefaultBuild(heapRelation,
indexRelation, indexRelation,
numberOfAttributes, indexInfo,
attributeNumber, oldPred,
funcInfo,
predInfo,
unique,
RelationGetIndexStrategy(indexRelation)); RelationGetIndexStrategy(indexRelation));
} }
...@@ -1959,34 +1948,9 @@ IndexGetRelation(Oid indexId) ...@@ -1959,34 +1948,9 @@ IndexGetRelation(Oid indexId)
return index->indrelid; return index->indrelid;
} }
/*
* IndexIsUnique: given an index's relation OID, see if it
* is unique using the system cache.
*/
bool
IndexIsUnique(Oid indexId)
{
HeapTuple tuple;
Form_pg_index index;
tuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(indexId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
{
elog(ERROR, "IndexIsUnique: can't find index id %u",
indexId);
}
index = (Form_pg_index) GETSTRUCT(tuple);
Assert(index->indexrelid == indexId);
return index->indisunique;
}
/* --------------------------------- /* ---------------------------------
* activate_index -- activate/deactivate the specified index. * activate_index -- activate/deactivate the specified index.
* Note that currelntly PostgreSQL doesn't hold the * Note that currently PostgreSQL doesn't hold the
* status per index * status per index
* --------------------------------- * ---------------------------------
*/ */
...@@ -2011,92 +1975,47 @@ reindex_index(Oid indexId, bool force) ...@@ -2011,92 +1975,47 @@ reindex_index(Oid indexId, bool force)
ScanKeyData entry; ScanKeyData entry;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple indexTuple, HeapTuple indexTuple,
procTuple,
classTuple; classTuple;
Form_pg_index index; IndexInfo *indexInfo;
Oid heapId, Oid heapId,
procId,
accessMethodId; accessMethodId;
Node *oldPred = NULL;
PredInfo *predInfo;
AttrNumber *attributeNumberA;
FuncIndexInfo fInfo,
*funcInfo = NULL;
int i,
numberOfAttributes;
bool unique;
char *predString;
bool old; bool old;
old = SetReindexProcessing(true); old = SetReindexProcessing(true);
/* Scan pg_index to find indexes on heapRelation */
/* Scan pg_index to find the index's pg_index entry */
indexRelation = heap_openr(IndexRelationName, AccessShareLock); indexRelation = heap_openr(IndexRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ, ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indexrelid, F_OIDEQ,
ObjectIdGetDatum(indexId)); ObjectIdGetDatum(indexId));
scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry); scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry);
indexTuple = heap_getnext(scan, 0); indexTuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(indexTuple)) if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "reindex_index index %d tuple is invalid", indexId); elog(ERROR, "reindex_index: index %u not found in pg_index", indexId);
/*
* For the index, fetch index attributes so we can apply index_build
*/
index = (Form_pg_index) GETSTRUCT(indexTuple);
heapId = index->indrelid;
procId = index->indproc;
unique = index->indisunique;
for (i = 0; i < INDEX_MAX_KEYS; i++)
{
if (index->indkey[i] == InvalidAttrNumber)
break;
}
numberOfAttributes = i;
/* If a valid where predicate, compute predicate Node */ /* Get OID of index's parent table */
if (VARSIZE(&index->indpred) != 0) heapId = ((Form_pg_index) GETSTRUCT(indexTuple))->indrelid;
{ /* Fetch info needed for index_build */
predString = DatumGetCString(DirectFunctionCall1(textout, indexInfo = BuildIndexInfo(indexTuple);
PointerGetDatum(&index->indpred)));
oldPred = stringToNode(predString);
pfree(predString);
}
predInfo = (PredInfo *) palloc(sizeof(PredInfo));
predInfo->pred = (Node *) oldPred;
predInfo->oldPred = NULL;
/* Assign Index keys to attributes array */ /* Complete the scan and close pg_index */
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes * sizeof(AttrNumber)); heap_endscan(scan);
for (i = 0; i < numberOfAttributes; i++) heap_close(indexRelation, AccessShareLock);
attributeNumberA[i] = index->indkey[i];
/* If this is a procedural index, initialize our FuncIndexInfo */
if (procId != InvalidOid)
{
funcInfo = &fInfo;
FIsetnArgs(funcInfo, numberOfAttributes);
procTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(procId),
0, 0, 0);
if (!HeapTupleIsValid(procTuple))
elog(ERROR, "RelationTruncateIndexes: index procedure not found");
namecpy(&(funcInfo->funcName),
&(((Form_pg_proc) GETSTRUCT(procTuple))->proname));
FIsetProcOid(funcInfo, procTuple->t_data->t_oid);
}
/* Fetch the classTuple associated with this index */ /* Fetch the classTuple associated with this index */
classTuple = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(indexId), 0, 0, 0); classTuple = SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(indexId),
0, 0, 0);
if (!HeapTupleIsValid(classTuple)) if (!HeapTupleIsValid(classTuple))
elog(ERROR, "RelationTruncateIndexes: index access method not found"); elog(ERROR, "reindex_index: index %u not found in pg_class", indexId);
accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam; accessMethodId = ((Form_pg_class) GETSTRUCT(classTuple))->relam;
/* Open our index relation */ /* Open our index relation */
iRel = index_open(indexId);
if (iRel == NULL)
elog(ERROR, "reindex_index: can't open index relation");
heapRelation = heap_open(heapId, ExclusiveLock); heapRelation = heap_open(heapId, ExclusiveLock);
if (heapRelation == NULL) if (heapRelation == NULL)
elog(ERROR, "reindex_index: can't open heap relation"); elog(ERROR, "reindex_index: can't open heap relation");
iRel = index_open(indexId);
if (iRel == NULL)
elog(ERROR, "reindex_index: can't open index relation");
/* Obtain exclusive lock on it, just to be sure */ /* Obtain exclusive lock on it, just to be sure */
LockRelation(iRel, AccessExclusiveLock); LockRelation(iRel, AccessExclusiveLock);
...@@ -2112,23 +2031,16 @@ reindex_index(Oid indexId, bool force) ...@@ -2112,23 +2031,16 @@ reindex_index(Oid indexId, bool force)
iRel->rd_nblocks = 0; iRel->rd_nblocks = 0;
/* Initialize the index and rebuild */ /* Initialize the index and rebuild */
InitIndexStrategy(numberOfAttributes, iRel, accessMethodId); InitIndexStrategy(indexInfo->ii_NumIndexAttrs, iRel, accessMethodId);
index_build(heapRelation, iRel, numberOfAttributes, index_build(heapRelation, iRel, indexInfo, NULL);
attributeNumberA, funcInfo, predInfo, unique);
/* /*
* index_build will close both the heap and index relations (but not * index_build will close both the heap and index relations (but not
* give up the locks we hold on them). That's fine for the index, but * give up the locks we hold on them). So we're done.
* we need to open the heap again. We need no new lock, since this
* backend still has the exclusive lock grabbed by heap_truncate.
*/ */
iRel = index_open(indexId);
Assert(iRel != NULL);
/* Complete the scan and close pg_index */
heap_endscan(scan);
heap_close(indexRelation, AccessShareLock);
SetReindexProcessing(old); SetReindexProcessing(old);
return true; return true;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.66 2000/06/17 04:56:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.67 2000/07/14 22:17:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -83,9 +83,9 @@ static HeapTuple CatalogIndexFetchTuple(Relation heapRelation, ...@@ -83,9 +83,9 @@ static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
/* /*
* Changes (appends) to catalogs can (and does) happen at various places * Changes (appends) to catalogs can and do happen at various places
* throughout the code. We need a generic routine that will open all of * throughout the code. We need a generic routine that will open all of
* the indices defined on a given catalog a return the relation descriptors * the indices defined on a given catalog and return the relation descriptors
* associated with them. * associated with them.
*/ */
void void
...@@ -115,9 +115,20 @@ CatalogCloseIndices(int nIndices, Relation *idescs) ...@@ -115,9 +115,20 @@ CatalogCloseIndices(int nIndices, Relation *idescs)
/* /*
* For the same reasons outlined above CatalogOpenIndices() we need a routine * For the same reasons outlined above for CatalogOpenIndices(), we need a
* that takes a new catalog tuple and inserts an associated index tuple into * routine that takes a new catalog tuple and inserts an associated index
* each catalog index. * tuple into each catalog index.
*
* 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
* are inserting tuples in bulk.
*
* NOTE: we do not bother to handle partial indices. Nor do we try to
* be efficient for functional indices (the code should work for them,
* but may leak memory intraquery). This should be OK for system catalogs,
* but don't use this routine for user tables!
*/ */
void void
CatalogIndexInsert(Relation *idescs, CatalogIndexInsert(Relation *idescs,
...@@ -125,15 +136,9 @@ CatalogIndexInsert(Relation *idescs, ...@@ -125,15 +136,9 @@ CatalogIndexInsert(Relation *idescs,
Relation heapRelation, Relation heapRelation,
HeapTuple heapTuple) HeapTuple heapTuple)
{ {
HeapTuple index_tup;
TupleDesc heapDescriptor; TupleDesc heapDescriptor;
Form_pg_index index_form;
Datum datum[INDEX_MAX_KEYS]; Datum datum[INDEX_MAX_KEYS];
char nulls[INDEX_MAX_KEYS]; char nullv[INDEX_MAX_KEYS];
int natts;
AttrNumber *attnumP;
FuncIndexInfo finfo,
*finfoP;
int i; int i;
if (IsIgnoringSystemIndexes()) if (IsIgnoringSystemIndexes())
...@@ -142,51 +147,30 @@ CatalogIndexInsert(Relation *idescs, ...@@ -142,51 +147,30 @@ CatalogIndexInsert(Relation *idescs,
for (i = 0; i < nIndices; i++) for (i = 0; i < nIndices; i++)
{ {
HeapTuple index_tup;
IndexInfo *indexInfo;
InsertIndexResult indexRes; InsertIndexResult indexRes;
index_tup = SearchSysCacheTupleCopy(INDEXRELID, index_tup = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(idescs[i]->rd_id), ObjectIdGetDatum(idescs[i]->rd_id),
0, 0, 0); 0, 0, 0);
Assert(index_tup); if (!HeapTupleIsValid(index_tup))
index_form = (Form_pg_index) GETSTRUCT(index_tup); elog(ERROR, "CatalogIndexInsert: index %u not found",
idescs[i]->rd_id);
if (index_form->indproc != InvalidOid) indexInfo = BuildIndexInfo(index_tup);
{
int fatts;
/*
* Compute the number of attributes we are indexing upon.
*/
for (attnumP = index_form->indkey, fatts = 0;
fatts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
attnumP++, fatts++)
;
FIgetnArgs(&finfo) = fatts;
natts = 1;
FIgetProcOid(&finfo) = index_form->indproc;
*(FIgetname(&finfo)) = '\0';
finfoP = &finfo;
}
else
{
natts = RelationGetDescr(idescs[i])->natts;
finfoP = (FuncIndexInfo *) NULL;
}
FormIndexDatum(natts, FormIndexDatum(indexInfo,
(AttrNumber *) index_form->indkey,
heapTuple, heapTuple,
heapDescriptor, heapDescriptor,
CurrentMemoryContext,
datum, datum,
nulls, nullv);
finfoP);
indexRes = index_insert(idescs[i], datum, nulls, indexRes = index_insert(idescs[i], datum, nullv,
&heapTuple->t_self, heapRelation); &heapTuple->t_self, heapRelation);
if (indexRes) if (indexRes)
pfree(indexRes); pfree(indexRes);
pfree(indexInfo);
heap_freetuple(index_tup);
} }
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.57 2000/07/04 06:11:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.58 2000/07/14 22:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -198,35 +198,31 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) ...@@ -198,35 +198,31 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
Relation OldIndex, Relation OldIndex,
NewHeap; NewHeap;
HeapTuple Old_pg_index_Tuple, HeapTuple Old_pg_index_Tuple,
Old_pg_index_relation_Tuple, Old_pg_index_relation_Tuple;
pg_proc_Tuple;
Form_pg_index Old_pg_index_Form; Form_pg_index Old_pg_index_Form;
Form_pg_class Old_pg_index_relation_Form; Form_pg_class Old_pg_index_relation_Form;
Form_pg_proc pg_proc_Form; IndexInfo *indexInfo;
char *NewIndexName; char *NewIndexName;
AttrNumber *attnumP;
int natts;
FuncIndexInfo *finfo;
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock); NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
OldIndex = index_open(OIDOldIndex); OldIndex = index_open(OIDOldIndex);
/* /*
* OK. Create a new (temporary) index for the one that's already here. * OK. Create a new (temporary) index for the one that's already here.
* To do this I get the info from pg_index, re-build the FunctInfo if * To do this I get the info from pg_index, and add a new index with
* I have to, and add a new index with a temporary name. * a temporary name.
*/ */
Old_pg_index_Tuple = SearchSysCacheTuple(INDEXRELID, Old_pg_index_Tuple = SearchSysCacheTupleCopy(INDEXRELID,
ObjectIdGetDatum(RelationGetRelid(OldIndex)), ObjectIdGetDatum(RelationGetRelid(OldIndex)),
0, 0, 0); 0, 0, 0);
Assert(Old_pg_index_Tuple); Assert(Old_pg_index_Tuple);
Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple); Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
Old_pg_index_relation_Tuple = SearchSysCacheTuple(RELOID, indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
ObjectIdGetDatum(RelationGetRelid(OldIndex)),
0, 0, 0);
Old_pg_index_relation_Tuple = SearchSysCacheTupleCopy(RELOID,
ObjectIdGetDatum(RelationGetRelid(OldIndex)),
0, 0, 0);
Assert(Old_pg_index_relation_Tuple); Assert(Old_pg_index_relation_Tuple);
Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple); Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
...@@ -234,50 +230,12 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) ...@@ -234,50 +230,12 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
NewIndexName = palloc(NAMEDATALEN); /* XXX */ NewIndexName = palloc(NAMEDATALEN); /* XXX */
snprintf(NewIndexName, NAMEDATALEN, "temp_%x", OIDOldIndex); snprintf(NewIndexName, NAMEDATALEN, "temp_%x", OIDOldIndex);
/*
* Ugly as it is, the only way I have of working out the number of
* attribues is to count them. Mostly there'll be just one but I've
* got to be sure.
*/
for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0;
natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
attnumP++, natts++);
/*
* If this is a functional index, I need to rebuild the functional
* component to pass it to the defining procedure.
*/
if (Old_pg_index_Form->indproc != InvalidOid)
{
finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
FIgetnArgs(finfo) = natts;
FIgetProcOid(finfo) = Old_pg_index_Form->indproc;
pg_proc_Tuple = SearchSysCacheTuple(PROCOID,
ObjectIdGetDatum(Old_pg_index_Form->indproc),
0, 0, 0);
Assert(pg_proc_Tuple);
pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple);
namecpy(&(finfo->funcName), &(pg_proc_Form->proname));
natts = 1; /* function result is a single column */
}
else
{
finfo = (FuncIndexInfo *) NULL;
}
index_create(RelationGetRelationName(NewHeap), index_create(RelationGetRelationName(NewHeap),
NewIndexName, NewIndexName,
finfo, indexInfo,
NULL, /* type info is in the old index */
Old_pg_index_relation_Form->relam, Old_pg_index_relation_Form->relam,
natts,
Old_pg_index_Form->indkey,
Old_pg_index_Form->indclass, Old_pg_index_Form->indclass,
(Node *) NULL, /* XXX where's the predicate? */
Old_pg_index_Form->indislossy, Old_pg_index_Form->indislossy,
Old_pg_index_Form->indisunique,
Old_pg_index_Form->indisprimary, Old_pg_index_Form->indisprimary,
allowSystemTableMods); allowSystemTableMods);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.88 2000/07/05 23:11:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.89 2000/07/14 22:17:42 tgl Exp $
* *
* NOTES * NOTES
* The PerformAddAttribute() code, like most of the relation * The PerformAddAttribute() code, like most of the relation
...@@ -1205,7 +1205,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent) ...@@ -1205,7 +1205,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
char toast_relname[NAMEDATALEN + 1]; char toast_relname[NAMEDATALEN + 1];
char toast_idxname[NAMEDATALEN + 1]; char toast_idxname[NAMEDATALEN + 1];
Relation toast_rel; Relation toast_rel;
AttrNumber attNums[1]; IndexInfo *indexInfo;
Oid classObjectId[1]; Oid classObjectId[1];
/* /*
...@@ -1334,11 +1334,20 @@ AlterTableCreateToastTable(const char *relationName, bool silent) ...@@ -1334,11 +1334,20 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
CommandCounterIncrement(); CommandCounterIncrement();
/* create index on chunk_id */ /* create index on chunk_id */
attNums[0] = 1;
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = 1;
indexInfo->ii_NumKeyAttrs = 1;
indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_Predicate = NULL;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = false;
classObjectId[0] = OID_OPS_OID; classObjectId[0] = OID_OPS_OID;
index_create(toast_relname, toast_idxname, NULL, NULL, BTREE_AM_OID,
1, attNums, classObjectId, index_create(toast_relname, toast_idxname, indexInfo,
(Node *) NULL, false, false, false, true); BTREE_AM_OID, classObjectId,
false, false, true);
/* make the index visible in this transaction */ /* make the index visible in this transaction */
CommandCounterIncrement(); CommandCounterIncrement();
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.118 2000/07/12 02:36:58 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.119 2000/07/14 22:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -50,10 +50,6 @@ static Oid GetOutputFunction(Oid type); ...@@ -50,10 +50,6 @@ static Oid GetOutputFunction(Oid type);
static Oid GetTypeElement(Oid type); static Oid GetTypeElement(Oid type);
static Oid GetInputFunction(Oid type); static Oid GetInputFunction(Oid type);
static Oid IsTypeByVal(Oid type); static Oid IsTypeByVal(Oid type);
static void GetIndexRelations(Oid main_relation_oid,
int *n_indices,
Relation **index_rels);
static void CopyReadNewline(FILE *fp, int *newline); static void CopyReadNewline(FILE *fp, int *newline);
static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print); static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline, char *null_print);
...@@ -576,53 +572,35 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p ...@@ -576,53 +572,35 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p
} }
static void static void
CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_print) CopyFrom(Relation rel, bool binary, bool oids, FILE *fp,
char *delim, char *null_print)
{ {
HeapTuple tuple; HeapTuple tuple;
AttrNumber attr_count; TupleDesc tupDesc;
Form_pg_attribute *attr; Form_pg_attribute *attr;
AttrNumber attr_count;
FmgrInfo *in_functions; FmgrInfo *in_functions;
Oid *elements;
int32 *typmod;
int i; int i;
Oid in_func_oid; Oid in_func_oid;
Datum *values; Datum *values;
char *nulls, char *nulls;
*index_nulls;
bool *byval; bool *byval;
bool isnull; bool isnull;
bool has_index;
int done = 0; int done = 0;
char *string = NULL, char *string = NULL,
*ptr; *ptr;
Relation *index_rels;
int32 len, int32 len,
null_ct, null_ct,
null_id; null_id;
int32 ntuples, int32 ntuples,
tuples_read = 0; tuples_read = 0;
bool reading_to_eof = true; bool reading_to_eof = true;
Oid *elements; RelationInfo *relationInfo;
int32 *typmod;
FuncIndexInfo *finfo,
**finfoP = NULL;
TupleDesc *itupdescArr;
HeapTuple pgIndexTup;
Form_pg_index *pgIndexP = NULL;
int *indexNatts = NULL;
char *predString;
Node **indexPred = NULL;
TupleDesc rtupdesc;
EState *estate = makeNode(EState); /* for ExecConstraints() */ EState *estate = makeNode(EState); /* for ExecConstraints() */
#ifndef OMIT_PARTIAL_INDEX
ExprContext *econtext = NULL;
TupleTable tupleTable; TupleTable tupleTable;
TupleTableSlot *slot = NULL; TupleTableSlot *slot;
#endif
int natts;
AttrNumber *attnumP;
Datum *idatum;
int n_indices;
InsertIndexResult indexRes;
TupleDesc tupDesc;
Oid loaded_oid = InvalidOid; Oid loaded_oid = InvalidOid;
bool skip_tuple = false; bool skip_tuple = false;
...@@ -630,71 +608,26 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -630,71 +608,26 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
attr = tupDesc->attrs; attr = tupDesc->attrs;
attr_count = tupDesc->natts; attr_count = tupDesc->natts;
has_index = false;
/* /*
* This may be a scalar or a functional index. We initialize all * We need a RelationInfo so we can use the regular executor's
* kinds of arrays here to avoid doing extra work at every tuple copy. * index-entry-making machinery. (There used to be a huge amount
* of code here that basically duplicated execUtils.c ...)
*/ */
relationInfo = makeNode(RelationInfo);
relationInfo->ri_RangeTableIndex = 1; /* dummy */
relationInfo->ri_RelationDesc = rel;
relationInfo->ri_NumIndices = 0;
relationInfo->ri_IndexRelationDescs = NULL;
relationInfo->ri_IndexRelationInfo = NULL;
if (rel->rd_rel->relhasindex) ExecOpenIndices(relationInfo);
{
GetIndexRelations(RelationGetRelid(rel), &n_indices, &index_rels); estate->es_result_relation_info = relationInfo;
if (n_indices > 0)
{ /* Set up a dummy tuple table too */
has_index = true; tupleTable = ExecCreateTupleTable(1);
itupdescArr = (TupleDesc *) palloc(n_indices * sizeof(TupleDesc)); slot = ExecAllocTableSlot(tupleTable);
pgIndexP = (Form_pg_index *) palloc(n_indices * sizeof(Form_pg_index)); ExecSetSlotDescriptor(slot, tupDesc);
indexNatts = (int *) palloc(n_indices * sizeof(int));
finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
indexPred = (Node **) palloc(n_indices * sizeof(Node *));
for (i = 0; i < n_indices; i++)
{
itupdescArr[i] = RelationGetDescr(index_rels[i]);
pgIndexTup = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(RelationGetRelid(index_rels[i])),
0, 0, 0);
Assert(pgIndexTup);
pgIndexP[i] = (Form_pg_index) GETSTRUCT(pgIndexTup);
for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
attnumP++, natts++);
if (pgIndexP[i]->indproc != InvalidOid)
{
FIgetnArgs(&finfo[i]) = natts;
natts = 1;
FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
*(FIgetname(&finfo[i])) = '\0';
finfoP[i] = &finfo[i];
}
else
finfoP[i] = (FuncIndexInfo *) NULL;
indexNatts[i] = natts;
if (VARSIZE(&pgIndexP[i]->indpred) != 0)
{
predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&pgIndexP[i]->indpred)));
indexPred[i] = stringToNode(predString);
pfree(predString);
#ifndef OMIT_PARTIAL_INDEX
/* make dummy ExprContext for use by ExecQual */
if (econtext == NULL)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
rtupdesc = RelationGetDescr(rel);
ExecSetSlotDescriptor(slot, rtupdesc);
econtext = MakeExprContext(slot,
TransactionCommandContext);
}
#endif /* OMIT_PARTIAL_INDEX */
}
else
indexPred[i] = NULL;
}
}
}
if (!binary) if (!binary)
{ {
...@@ -723,16 +656,13 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -723,16 +656,13 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
reading_to_eof = false; reading_to_eof = false;
} }
values = (Datum *) palloc(sizeof(Datum) * attr_count); values = (Datum *) palloc(attr_count * sizeof(Datum));
nulls = (char *) palloc(attr_count); nulls = (char *) palloc(attr_count * sizeof(char));
index_nulls = (char *) palloc(attr_count);
idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
byval = (bool *) palloc(attr_count * sizeof(bool)); byval = (bool *) palloc(attr_count * sizeof(bool));
for (i = 0; i < attr_count; i++) for (i = 0; i < attr_count; i++)
{ {
nulls[i] = ' '; nulls[i] = ' ';
index_nulls[i] = ' ';
#ifdef _DROP_COLUMN_HACK__ #ifdef _DROP_COLUMN_HACK__
if (COLUMN_IS_DROPPED(attr[i])) if (COLUMN_IS_DROPPED(attr[i]))
{ {
...@@ -873,6 +803,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -873,6 +803,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
tuple->t_data->t_oid = loaded_oid; tuple->t_data->t_oid = loaded_oid;
skip_tuple = false; skip_tuple = false;
/* BEFORE ROW INSERT Triggers */ /* BEFORE ROW INSERT Triggers */
if (rel->trigdesc && if (rel->trigdesc &&
rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0) rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
...@@ -893,45 +824,25 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -893,45 +824,25 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
if (!skip_tuple) if (!skip_tuple)
{ {
/* ---------------- /* ----------------
* Check the constraints of a tuple * Check the constraints of the tuple
* ---------------- * ----------------
*/ */
if (rel->rd_att->constr) if (rel->rd_att->constr)
ExecConstraints("CopyFrom", rel, tuple, estate); ExecConstraints("CopyFrom", rel, tuple, estate);
/* ----------------
* OK, store the tuple and create index entries for it
* ----------------
*/
heap_insert(rel, tuple); heap_insert(rel, tuple);
if (has_index) if (relationInfo->ri_NumIndices > 0)
{ {
for (i = 0; i < n_indices; i++) ExecStoreTuple(tuple, slot, InvalidBuffer, false);
{ ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
#ifndef OMIT_PARTIAL_INDEX
if (indexPred[i] != NULL)
{
/*
* if tuple doesn't satisfy predicate, don't
* update index
*/
slot->val = tuple;
/* SetSlotContents(slot, tuple); */
if (!ExecQual((List *) indexPred[i], econtext, false))
continue;
}
#endif /* OMIT_PARTIAL_INDEX */
FormIndexDatum(indexNatts[i],
(AttrNumber *) &(pgIndexP[i]->indkey[0]),
tuple,
tupDesc,
idatum,
index_nulls,
finfoP[i]);
indexRes = index_insert(index_rels[i], idatum, index_nulls,
&(tuple->t_self), rel);
if (indexRes)
pfree(indexRes);
}
} }
/* AFTER ROW INSERT Triggers */ /* AFTER ROW INSERT Triggers */
if (rel->trigdesc && if (rel->trigdesc &&
rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0) rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
...@@ -948,8 +859,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -948,8 +859,8 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
if (!binary) if (!binary)
pfree((void *) values[i]); pfree((void *) values[i]);
} }
else if (nulls[i] == 'n') /* reset nulls[] array for next time */
nulls[i] = ' '; nulls[i] = ' ';
} }
heap_freetuple(tuple); heap_freetuple(tuple);
...@@ -958,11 +869,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -958,11 +869,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
if (!reading_to_eof && ntuples == tuples_read) if (!reading_to_eof && ntuples == tuples_read)
done = true; done = true;
} }
/*
* Done, clean up
*/
lineno = 0; lineno = 0;
pfree(values); pfree(values);
pfree(nulls); pfree(nulls);
pfree(index_nulls);
pfree(idatum);
pfree(byval); pfree(byval);
if (!binary) if (!binary)
...@@ -972,21 +886,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null ...@@ -972,21 +886,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null
pfree(typmod); pfree(typmod);
} }
if (has_index) ExecDropTupleTable(tupleTable, true);
{
for (i = 0; i < n_indices; i++)
{
if (index_rels[i] == NULL)
continue;
/* see comments in ExecOpenIndices() in execUtils.c */
if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID &&
(index_rels[i])->rd_rel->relam != HASH_AM_OID)
UnlockRelation(index_rels[i], AccessExclusiveLock);
index_close(index_rels[i]);
}
}
}
ExecCloseIndices(relationInfo);
}
static Oid static Oid
...@@ -1054,52 +957,6 @@ IsTypeByVal(Oid type) ...@@ -1054,52 +957,6 @@ IsTypeByVal(Oid type)
return InvalidOid; return InvalidOid;
} }
/*
* Given the OID of a relation, return an array of index relation descriptors
* and the number of index relations. These relation descriptors are open
* using index_open().
*
* Space for the array itself is palloc'ed.
*/
static void
GetIndexRelations(Oid main_relation_oid,
int *n_indices,
Relation **index_rels)
{
Relation relation;
List *indexoidlist,
*indexoidscan;
int i;
relation = heap_open(main_relation_oid, AccessShareLock);
indexoidlist = RelationGetIndexList(relation);
*n_indices = length(indexoidlist);
if (*n_indices > 0)
*index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
else
*index_rels = NULL;
i = 0;
foreach(indexoidscan, indexoidlist)
{
Oid indexoid = lfirsti(indexoidscan);
Relation index = index_open(indexoid);
/* see comments in ExecOpenIndices() in execUtils.c */
if (index != NULL &&
index->rd_rel->relam != BTREE_AM_OID &&
index->rd_rel->relam != HASH_AM_OID)
LockRelation(index, AccessExclusiveLock);
(*index_rels)[i] = index;
i++;
}
freeList(indexoidlist);
heap_close(relation, AccessShareLock);
}
/* /*
* Reads input from fp until an end of line is seen. * Reads input from fp until an end of line is seen.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.34 2000/07/05 23:11:11 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.35 2000/07/14 22:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/heap.h" #include "catalog/heap.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
...@@ -47,14 +48,14 @@ ...@@ -47,14 +48,14 @@
static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid); static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid); static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid); static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
static void FuncIndexArgs(IndexElem *funcIndex, FuncIndexInfo *funcInfo, static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
AttrNumber *attNumP, Oid *opOidP, Oid relId, IndexElem *funcIndex,
Oid relId,
char *accessMethodName, Oid accessMethodId); char *accessMethodName, Oid accessMethodId);
static void NormIndexAttrs(List *attList, AttrNumber *attNumP, static void NormIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
Oid *opOidP, Oid relId, List *attList,
Oid relId,
char *accessMethodName, Oid accessMethodId); char *accessMethodName, Oid accessMethodId);
static void ProcessAttrTypename(IndexElem *attribute,
Oid defType, int32 defTypmod);
static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType, static Oid GetAttrOpClass(IndexElem *attribute, Oid attrType,
char *accessMethodName, Oid accessMethodId); char *accessMethodName, Oid accessMethodId);
static char *GetDefaultOpClass(Oid atttypid); static char *GetDefaultOpClass(Oid atttypid);
...@@ -67,10 +68,7 @@ static char *GetDefaultOpClass(Oid atttypid); ...@@ -67,10 +68,7 @@ static char *GetDefaultOpClass(Oid atttypid);
* index or a list of attributes to index on. * index or a list of attributes to index on.
* 'parameterList' is a list of DefElem specified in the with clause. * 'parameterList' is a list of DefElem specified in the with clause.
* 'predicate' is the qual specified in the where clause. * 'predicate' is the qual specified in the where clause.
* 'rangetable' is for the predicate * 'rangetable' is needed to interpret the predicate
*
* Exceptions:
* XXX
*/ */
void void
DefineIndex(char *heapRelationName, DefineIndex(char *heapRelationName,
...@@ -86,16 +84,15 @@ DefineIndex(char *heapRelationName, ...@@ -86,16 +84,15 @@ DefineIndex(char *heapRelationName,
Oid *classObjectId; Oid *classObjectId;
Oid accessMethodId; Oid accessMethodId;
Oid relationId; Oid relationId;
IndexInfo *indexInfo;
int numberOfAttributes; int numberOfAttributes;
AttrNumber *attributeNumberA;
HeapTuple tuple; HeapTuple tuple;
FuncIndexInfo fInfo; List *cnfPred = NIL;
List *cnfPred = NULL;
bool lossy = false; bool lossy = false;
List *pl; List *pl;
/* /*
* count attributes * count attributes in index
*/ */
numberOfAttributes = length(attributeList); numberOfAttributes = length(attributeList);
if (numberOfAttributes <= 0) if (numberOfAttributes <= 0)
...@@ -108,21 +105,8 @@ DefineIndex(char *heapRelationName, ...@@ -108,21 +105,8 @@ DefineIndex(char *heapRelationName,
* compute heap relation id * compute heap relation id
*/ */
if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid) if ((relationId = RelnameFindRelid(heapRelationName)) == InvalidOid)
{
elog(ERROR, "DefineIndex: relation \"%s\" not found", elog(ERROR, "DefineIndex: relation \"%s\" not found",
heapRelationName); heapRelationName);
}
/*
* 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 && strcmp(accessMethodName, "btree") != 0)
elog(ERROR, "DefineIndex: unique indices are only available with the btree access method");
if (numberOfAttributes > 1 && strcmp(accessMethodName, "btree") != 0)
elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
/* /*
* compute access method id * compute access method id
...@@ -131,12 +115,21 @@ DefineIndex(char *heapRelationName, ...@@ -131,12 +115,21 @@ DefineIndex(char *heapRelationName,
PointerGetDatum(accessMethodName), PointerGetDatum(accessMethodName),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{
elog(ERROR, "DefineIndex: access method \"%s\" not found", elog(ERROR, "DefineIndex: access method \"%s\" not found",
accessMethodName); accessMethodName);
}
accessMethodId = tuple->t_data->t_oid; accessMethodId = tuple->t_data->t_oid;
/*
* 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");
if (numberOfAttributes > 1 && accessMethodId != BTREE_AM_OID)
elog(ERROR, "DefineIndex: multi-column indices are only available with the btree access method");
/* /*
* WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96 * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
*/ */
...@@ -145,7 +138,7 @@ DefineIndex(char *heapRelationName, ...@@ -145,7 +138,7 @@ DefineIndex(char *heapRelationName,
DefElem *param = (DefElem *) lfirst(pl); DefElem *param = (DefElem *) lfirst(pl);
if (!strcasecmp(param->defname, "islossy")) if (!strcasecmp(param->defname, "islossy"))
lossy = TRUE; lossy = true;
else else
elog(NOTICE, "Unrecognized index attribute \"%s\" ignored", elog(NOTICE, "Unrecognized index attribute \"%s\" ignored",
param->defname); param->defname);
...@@ -169,55 +162,51 @@ DefineIndex(char *heapRelationName, ...@@ -169,55 +162,51 @@ DefineIndex(char *heapRelationName,
if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false)) if (!IsBootstrapProcessingMode() && !IndexesAreActive(relationId, false))
elog(ERROR, "Existing indexes are inactive. REINDEX first"); elog(ERROR, "Existing indexes are inactive. REINDEX first");
/*
* Prepare arguments for index_create, primarily an IndexInfo structure
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_Predicate = (Node *) cnfPred;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = unique;
if (IsFuncIndex(attributeList)) if (IsFuncIndex(attributeList))
{ {
IndexElem *funcIndex = lfirst(attributeList); IndexElem *funcIndex = (IndexElem *) lfirst(attributeList);
int nargs; int nargs;
/* Parser should have given us only one list item, but check */
if (numberOfAttributes != 1)
elog(ERROR, "Functional index can only have one attribute");
nargs = length(funcIndex->args); nargs = length(funcIndex->args);
if (nargs > INDEX_MAX_KEYS) if (nargs > INDEX_MAX_KEYS)
elog(ERROR, "Index function can take at most %d arguments", elog(ERROR, "Index function can take at most %d arguments",
INDEX_MAX_KEYS); INDEX_MAX_KEYS);
FIsetnArgs(&fInfo, nargs); indexInfo->ii_NumIndexAttrs = 1;
indexInfo->ii_NumKeyAttrs = nargs;
namestrcpy(&fInfo.funcName, funcIndex->name);
attributeNumberA = (AttrNumber *) palloc(nargs *
sizeof attributeNumberA[0]);
classObjectId = (Oid *) palloc(sizeof(Oid)); classObjectId = (Oid *) palloc(sizeof(Oid));
FuncIndexArgs(funcIndex, &fInfo, attributeNumberA, FuncIndexArgs(indexInfo, classObjectId, funcIndex,
classObjectId, relationId, relationId, accessMethodName, accessMethodId);
accessMethodName, accessMethodId);
index_create(heapRelationName, indexRelationName,
&fInfo, NULL,
accessMethodId, numberOfAttributes, attributeNumberA,
classObjectId,
(Node *) cnfPred,
lossy, unique, primary, allowSystemTableMods);
} }
else else
{ {
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes * indexInfo->ii_NumIndexAttrs = numberOfAttributes;
sizeof attributeNumberA[0]); indexInfo->ii_NumKeyAttrs = numberOfAttributes;
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
NormIndexAttrs(attributeList, attributeNumberA, NormIndexAttrs(indexInfo, classObjectId, attributeList,
classObjectId, relationId, relationId, accessMethodName, accessMethodId);
accessMethodName, accessMethodId);
index_create(heapRelationName, indexRelationName,
NULL, attributeList,
accessMethodId, numberOfAttributes, attributeNumberA,
classObjectId,
(Node *) cnfPred,
lossy, unique, primary, allowSystemTableMods);
} }
index_create(heapRelationName, indexRelationName,
indexInfo, accessMethodId, classObjectId,
lossy, primary, allowSystemTableMods);
/* /*
* We update the relation's pg_class tuple even if it already has * 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
...@@ -232,83 +221,48 @@ DefineIndex(char *heapRelationName, ...@@ -232,83 +221,48 @@ DefineIndex(char *heapRelationName,
/* /*
* ExtendIndex * ExtendIndex
* Extends a partial index. * Extends a partial index.
*
* Exceptions:
* XXX
*/ */
void void
ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
{ {
Oid *classObjectId; Relation heapRelation;
Oid accessMethodId; Relation indexRelation;
Oid indexId, Oid accessMethodId,
indexId,
relationId; relationId;
Oid indproc;
int numberOfAttributes;
AttrNumber *attributeNumberA;
HeapTuple tuple; HeapTuple tuple;
FuncIndexInfo fInfo;
FuncIndexInfo *funcInfo = NULL;
bool unique;
Form_pg_index index; Form_pg_index index;
Node *oldPred = NULL; List *cnfPred = NIL;
List *cnfPred = NULL; IndexInfo *indexInfo;
PredInfo *predInfo; Node *oldPred;
Relation heapRelation;
Relation indexRelation;
int i;
/* /*
* compute index relation id and access method id * Get index's relation id and access method id from pg_class
*/ */
tuple = SearchSysCacheTuple(RELNAME, tuple = SearchSysCacheTuple(RELNAME,
PointerGetDatum(indexRelationName), PointerGetDatum(indexRelationName),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{
elog(ERROR, "ExtendIndex: index \"%s\" not found", elog(ERROR, "ExtendIndex: index \"%s\" not found",
indexRelationName); indexRelationName);
}
indexId = tuple->t_data->t_oid; indexId = tuple->t_data->t_oid;
accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam; accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
/* /*
* find pg_index tuple * Extract info from the pg_index tuple for the index
*/ */
tuple = SearchSysCacheTuple(INDEXRELID, tuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(indexId), ObjectIdGetDatum(indexId),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{
elog(ERROR, "ExtendIndex: relation \"%s\" is not an index", elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
indexRelationName); indexRelationName);
}
/*
* Extract info from the pg_index tuple
*/
index = (Form_pg_index) GETSTRUCT(tuple); index = (Form_pg_index) GETSTRUCT(tuple);
Assert(index->indexrelid == indexId); Assert(index->indexrelid == indexId);
relationId = index->indrelid; relationId = index->indrelid;
indproc = index->indproc; indexInfo = BuildIndexInfo(tuple);
unique = index->indisunique; oldPred = indexInfo->ii_Predicate;
for (i = 0; i < INDEX_MAX_KEYS; i++)
{
if (index->indkey[i] == InvalidAttrNumber)
break;
}
numberOfAttributes = i;
if (VARSIZE(&index->indpred) != 0)
{
char *predString;
predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&index->indpred)));
oldPred = stringToNode(predString);
pfree(predString);
}
if (oldPred == NULL) if (oldPred == NULL)
elog(ERROR, "ExtendIndex: \"%s\" is not a partial index", elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
indexRelationName); indexRelationName);
...@@ -316,8 +270,11 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) ...@@ -316,8 +270,11 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
/* /*
* Convert the extension predicate from parsetree form to plan form, * Convert the extension predicate from parsetree form to plan form,
* so it can be readily evaluated during index creation. Note: * so it can be readily evaluated during index creation. Note:
* "predicate" comes in as a list containing (1) the predicate itself * "predicate" comes in two parts (1) the predicate expression itself,
* (a where_clause), and (2) a corresponding range table. * and (2) a corresponding range table.
*
* XXX I think this code is broken --- index_build expects a single
* expression not a list --- tgl Jul 00
*/ */
if (rangetable != NIL) if (rangetable != NIL)
{ {
...@@ -326,47 +283,20 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) ...@@ -326,47 +283,20 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
CheckPredicate(cnfPred, rangetable, relationId); CheckPredicate(cnfPred, rangetable, relationId);
} }
/* make predInfo list to pass to index_build */ /* pass new predicate to index_build */
predInfo = (PredInfo *) palloc(sizeof(PredInfo)); indexInfo->ii_Predicate = (Node *) cnfPred;
predInfo->pred = (Node *) cnfPred;
predInfo->oldPred = oldPred;
attributeNumberA = (AttrNumber *) palloc(numberOfAttributes *
sizeof attributeNumberA[0]);
classObjectId = (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
for (i = 0; i < numberOfAttributes; i++)
{
attributeNumberA[i] = index->indkey[i];
classObjectId[i] = index->indclass[i];
}
if (indproc != InvalidOid)
{
funcInfo = &fInfo;
FIsetnArgs(funcInfo, numberOfAttributes);
tuple = SearchSysCacheTuple(PROCOID,
ObjectIdGetDatum(indproc),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ExtendIndex: index procedure %u not found",
indproc);
namecpy(&(funcInfo->funcName),
&(((Form_pg_proc) GETSTRUCT(tuple))->proname));
FIsetProcOid(funcInfo, tuple->t_data->t_oid);
}
/* Open heap and index rels, and get suitable locks */
heapRelation = heap_open(relationId, ShareLock); heapRelation = heap_open(relationId, ShareLock);
indexRelation = index_open(indexId); indexRelation = index_open(indexId);
InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId); /* Obtain exclusive lock on it, just to be sure */
LockRelation(indexRelation, AccessExclusiveLock);
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
indexRelation, accessMethodId);
index_build(heapRelation, indexRelation, numberOfAttributes, index_build(heapRelation, indexRelation, indexInfo, oldPred);
attributeNumberA, funcInfo, predInfo, unique);
/* heap and index rels are closed as a side-effect of index_build */ /* heap and index rels are closed as a side-effect of index_build */
} }
...@@ -431,15 +361,15 @@ CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid) ...@@ -431,15 +361,15 @@ CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
static void static void
FuncIndexArgs(IndexElem *funcIndex, FuncIndexArgs(IndexInfo *indexInfo,
FuncIndexInfo *funcInfo, Oid *classOidP,
AttrNumber *attNumP, IndexElem *funcIndex,
Oid *opOidP,
Oid relId, Oid relId,
char *accessMethodName, char *accessMethodName,
Oid accessMethodId) Oid accessMethodId)
{ {
List *rest; Oid argTypes[FUNC_MAX_ARGS];
List *arglist;
HeapTuple tuple; HeapTuple tuple;
Oid retType; Oid retType;
int argn = 0; int argn = 0;
...@@ -447,68 +377,77 @@ FuncIndexArgs(IndexElem *funcIndex, ...@@ -447,68 +377,77 @@ FuncIndexArgs(IndexElem *funcIndex,
/* /*
* process the function arguments, which are a list of T_String * process the function arguments, which are a list of T_String
* (someday ought to allow more general expressions?) * (someday ought to allow more general expressions?)
*
* Note caller already checked that list is not too long.
*/ */
MemSet(funcInfo->arglist, 0, FUNC_MAX_ARGS * sizeof(Oid)); MemSet(argTypes, 0, sizeof(argTypes));
foreach(rest, funcIndex->args) foreach(arglist, funcIndex->args)
{ {
char *arg = strVal(lfirst(rest)); char *arg = strVal(lfirst(arglist));
Form_pg_attribute att; Form_pg_attribute att;
tuple = SearchSysCacheTuple(ATTNAME, tuple = SearchSysCacheTuple(ATTNAME,
ObjectIdGetDatum(relId), ObjectIdGetDatum(relId),
PointerGetDatum(arg), 0, 0); PointerGetDatum(arg),
0, 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg); elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg);
att = (Form_pg_attribute) GETSTRUCT(tuple); att = (Form_pg_attribute) GETSTRUCT(tuple);
*attNumP++ = att->attnum;
funcInfo->arglist[argn++] = att->atttypid; indexInfo->ii_KeyAttrNumbers[argn] = att->attnum;
argTypes[argn] = att->atttypid;
argn++;
} }
/* ---------------- /* ----------------
* Lookup the function procedure to get its OID and result type. * Lookup the function procedure to get its OID and result type.
*
* XXX need to accept binary-compatible functions here, not just
* an exact match.
* ---------------- * ----------------
*/ */
tuple = SearchSysCacheTuple(PROCNAME, tuple = SearchSysCacheTuple(PROCNAME,
PointerGetDatum(FIgetname(funcInfo)), PointerGetDatum(funcIndex->name),
Int32GetDatum(FIgetnArgs(funcInfo)), Int32GetDatum(indexInfo->ii_NumKeyAttrs),
PointerGetDatum(FIgetArglist(funcInfo)), PointerGetDatum(argTypes),
0); 0);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
func_error("DefineIndex", FIgetname(funcInfo), func_error("DefineIndex", funcIndex->name,
FIgetnArgs(funcInfo), FIgetArglist(funcInfo), NULL); indexInfo->ii_NumKeyAttrs, argTypes, NULL);
} }
FIsetProcOid(funcInfo, tuple->t_data->t_oid); indexInfo->ii_FuncOid = tuple->t_data->t_oid;
retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype; retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype;
/* Process type and opclass, using func return type as default */ /* Process opclass, using func return type as default type */
ProcessAttrTypename(funcIndex, retType, -1); classOidP[0] = GetAttrOpClass(funcIndex, retType,
accessMethodName, accessMethodId);
*opOidP = GetAttrOpClass(funcIndex, retType, /* Need to do the fmgr function lookup now, too */
accessMethodName, accessMethodId);
fmgr_info(indexInfo->ii_FuncOid, & indexInfo->ii_FuncInfo);
} }
static void static void
NormIndexAttrs(List *attList, /* list of IndexElem's */ NormIndexAttrs(IndexInfo *indexInfo,
AttrNumber *attNumP,
Oid *classOidP, Oid *classOidP,
List *attList, /* list of IndexElem's */
Oid relId, Oid relId,
char *accessMethodName, char *accessMethodName,
Oid accessMethodId) Oid accessMethodId)
{ {
List *rest; List *rest;
int attn = 0;
/* /*
* process attributeList * process attributeList
*/ */
foreach(rest, attList) foreach(rest, attList)
{ {
IndexElem *attribute = lfirst(rest); IndexElem *attribute = (IndexElem *) lfirst(rest);
HeapTuple atttuple; HeapTuple atttuple;
Form_pg_attribute attform; Form_pg_attribute attform;
...@@ -524,36 +463,13 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */ ...@@ -524,36 +463,13 @@ NormIndexAttrs(List *attList, /* list of IndexElem's */
attribute->name); attribute->name);
attform = (Form_pg_attribute) GETSTRUCT(atttuple); attform = (Form_pg_attribute) GETSTRUCT(atttuple);
*attNumP++ = attform->attnum; indexInfo->ii_KeyAttrNumbers[attn] = attform->attnum;
ProcessAttrTypename(attribute, attform->atttypid, attform->atttypmod);
*classOidP++ = GetAttrOpClass(attribute, attform->atttypid, classOidP[attn] = GetAttrOpClass(attribute, attform->atttypid,
accessMethodName, accessMethodId); accessMethodName, accessMethodId);
heap_freetuple(atttuple); heap_freetuple(atttuple);
} attn++;
}
static void
ProcessAttrTypename(IndexElem *attribute,
Oid defType, int32 defTypmod)
{
HeapTuple tuple;
/* build a type node so we can set the proper alignment, etc. */
if (attribute->typename == NULL)
{
tuple = SearchSysCacheTuple(TYPEOID,
ObjectIdGetDatum(defType),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "DefineIndex: type for attribute \"%s\" undefined",
attribute->name);
attribute->typename = makeNode(TypeName);
attribute->typename->name = nameout(&((Form_pg_type) GETSTRUCT(tuple))->typname);
attribute->typename->typmod = defTypmod;
} }
} }
...@@ -626,7 +542,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType, ...@@ -626,7 +542,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
* *
* If the opclass was the default for the datatype, assume we can skip * 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. * this check --- that saves a few cycles in the most common case.
* If pg_opclass is messed up then we're probably screwed anyway... * If pg_opclass is wrong then we're probably screwed anyway...
*/ */
if (doTypeCheck) if (doTypeCheck)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.162 2000/07/05 16:17:38 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.163 2000/07/14 22:17:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "catalog/index.h" #include "catalog/index.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/execnodes.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
...@@ -71,7 +72,8 @@ static void reap_page(VacPageList vacpagelist, VacPage vacpage); ...@@ -71,7 +72,8 @@ static void reap_page(VacPageList vacpagelist, VacPage vacpage);
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew); static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
static void get_indices(Relation relation, int *nindices, Relation **Irel); static void get_indices(Relation relation, int *nindices, Relation **Irel);
static void close_indices(int nindices, Relation *Irel); static void close_indices(int nindices, Relation *Irel);
static void get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc); static IndexInfo **get_index_desc(Relation onerel, int nindices,
Relation *Irel);
static void *vac_find_eq(void *bot, int nelem, int size, void *elm, 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_blk(const void *left, const void *right);
...@@ -948,9 +950,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -948,9 +950,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
newitemid; newitemid;
HeapTupleData tuple, HeapTupleData tuple,
newtup; newtup;
TupleDesc tupdesc = NULL; TupleDesc tupdesc;
Datum *idatum = NULL; IndexInfo **indexInfo = NULL;
char *inulls = NULL; Datum idatum[INDEX_MAX_KEYS];
char inulls[INDEX_MAX_KEYS];
InsertIndexResult iresult; InsertIndexResult iresult;
VacPageListData Nvacpagelist; VacPageListData Nvacpagelist;
VacPage cur_page = NULL, VacPage cur_page = NULL,
...@@ -958,8 +961,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -958,8 +961,6 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
vacpage, vacpage,
*curpage; *curpage;
int cur_item = 0; int cur_item = 0;
IndDesc *Idesc,
*idcur;
int last_move_dest_block = -1, int last_move_dest_block = -1,
last_vacuum_block, last_vacuum_block,
i = 0; i = 0;
...@@ -980,13 +981,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -980,13 +981,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
myXID = GetCurrentTransactionId(); myXID = GetCurrentTransactionId();
myCID = GetCurrentCommandId(); myCID = GetCurrentCommandId();
tupdesc = RelationGetDescr(onerel);
if (Irel != (Relation *) NULL) /* preparation for index' inserts */ if (Irel != (Relation *) NULL) /* preparation for index' inserts */
{ indexInfo = get_index_desc(onerel, nindices, Irel);
get_index_desc(onerel, nindices, Irel, &Idesc);
tupdesc = RelationGetDescr(onerel);
idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof(*idatum));
inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof(*inulls));
}
Nvacpagelist.num_pages = 0; Nvacpagelist.num_pages = 0;
num_fraged_pages = fraged_pages->num_pages; num_fraged_pages = fraged_pages->num_pages;
...@@ -1456,15 +1454,22 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, ...@@ -1456,15 +1454,22 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
if (Irel != (Relation *) NULL) if (Irel != (Relation *) NULL)
{ {
for (i = 0, idcur = Idesc; i < nindices; i++, idcur++) /*
* 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.
*/
for (i = 0; i < nindices; i++)
{ {
FormIndexDatum(idcur->natts, FormIndexDatum(indexInfo[i],
(AttrNumber *) &(idcur->tform->indkey[0]),
&newtup, &newtup,
tupdesc, tupdesc,
CurrentMemoryContext,
idatum, idatum,
inulls, inulls);
idcur->finfoP);
iresult = index_insert(Irel[i], iresult = index_insert(Irel[i],
idatum, idatum,
inulls, inulls,
...@@ -1575,15 +1580,22 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", ...@@ -1575,15 +1580,22 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
/* insert index' tuples if needed */ /* insert index' tuples if needed */
if (Irel != (Relation *) NULL) if (Irel != (Relation *) NULL)
{ {
for (i = 0, idcur = Idesc; i < nindices; i++, idcur++) /*
* 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.
*/
for (i = 0; i < nindices; i++)
{ {
FormIndexDatum(idcur->natts, FormIndexDatum(indexInfo[i],
(AttrNumber *) &(idcur->tform->indkey[0]),
&newtup, &newtup,
tupdesc, tupdesc,
CurrentMemoryContext,
idatum, idatum,
inulls, inulls);
idcur->finfoP);
iresult = index_insert(Irel[i], iresult = index_insert(Irel[i],
idatum, idatum,
inulls, inulls,
...@@ -1821,10 +1833,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)", ...@@ -1821,10 +1833,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
if (Irel != (Relation *) NULL) /* pfree index' allocations */ if (Irel != (Relation *) NULL) /* pfree index' allocations */
{ {
pfree(Idesc);
pfree(idatum);
pfree(inulls);
close_indices(nindices, Irel); close_indices(nindices, Irel);
pfree(indexInfo);
} }
pfree(vacpage); pfree(vacpage);
...@@ -2347,46 +2357,30 @@ close_indices(int nindices, Relation *Irel) ...@@ -2347,46 +2357,30 @@ close_indices(int nindices, Relation *Irel)
} }
static void /*
get_index_desc(Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc) * Obtain IndexInfo data for each index on the rel
*/
static IndexInfo **
get_index_desc(Relation onerel, int nindices, Relation *Irel)
{ {
IndDesc *idcur; IndexInfo **indexInfo;
HeapTuple cachetuple;
AttrNumber *attnumP;
int natts;
int i; int i;
HeapTuple cachetuple;
*Idesc = (IndDesc *) palloc(nindices * sizeof(IndDesc)); indexInfo = (IndexInfo **) palloc(nindices * sizeof(IndexInfo *));
for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++) for (i = 0; i < nindices; i++)
{ {
cachetuple = SearchSysCacheTupleCopy(INDEXRELID, cachetuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(RelationGetRelid(Irel[i])), ObjectIdGetDatum(RelationGetRelid(Irel[i])),
0, 0, 0); 0, 0, 0);
Assert(cachetuple); if (!HeapTupleIsValid(cachetuple))
elog(ERROR, "get_index_desc: index %u not found",
/* RelationGetRelid(Irel[i]));
* we never free the copy we make, because Idesc needs it for indexInfo[i] = BuildIndexInfo(cachetuple);
* later
*/
idcur->tform = (Form_pg_index) GETSTRUCT(cachetuple);
for (attnumP = &(idcur->tform->indkey[0]), natts = 0;
natts < INDEX_MAX_KEYS && *attnumP != InvalidAttrNumber;
attnumP++, natts++);
if (idcur->tform->indproc != InvalidOid)
{
idcur->finfoP = &(idcur->finfo);
FIgetnArgs(idcur->finfoP) = natts;
natts = 1;
FIgetProcOid(idcur->finfoP) = idcur->tform->indproc;
*(FIgetname(idcur->finfoP)) = '\0';
}
else
idcur->finfoP = (FuncIndexInfo *) NULL;
idcur->natts = natts;
} }
return indexInfo;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.63 2000/07/12 02:37:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.64 2000/07/14 22:17:45 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,11 +27,9 @@ ...@@ -27,11 +27,9 @@
* QueryDescGetTypeInfo - moved here from main.c * QueryDescGetTypeInfo - moved here from main.c
* am not sure what uses it -cim 10/12/89 * am not sure what uses it -cim 10/12/89
* *
* ExecGetIndexKeyInfo \ * ExecOpenIndices \
* ExecOpenIndices | referenced by InitPlan, EndPlan, * ExecCloseIndices | referenced by InitPlan, EndPlan,
* ExecCloseIndices | ExecAppend, ExecReplace * ExecInsertIndexTuples / ExecAppend, ExecReplace
* ExecFormIndexTuple |
* ExecInsertIndexTuple /
* *
* NOTES * NOTES
* This file has traditionally been the place to stick misc. * This file has traditionally been the place to stick misc.
...@@ -55,8 +53,6 @@ ...@@ -55,8 +53,6 @@
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP,
AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* global counters for number of tuples processed, retrieved, * global counters for number of tuples processed, retrieved,
...@@ -684,93 +680,6 @@ QueryDescGetTypeInfo(QueryDesc *queryDesc) ...@@ -684,93 +680,6 @@ QueryDescGetTypeInfo(QueryDesc *queryDesc)
* ExecInsertIndexTuples support * ExecInsertIndexTuples support
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
/* ----------------------------------------------------------------
* ExecGetIndexKeyInfo
*
* Extracts the index key attribute numbers from
* an index tuple form (i.e. a tuple from the pg_index relation)
* into an array of attribute numbers. The array and the
* size of the array are returned to the caller via return
* parameters.
* ----------------------------------------------------------------
*/
static void
ExecGetIndexKeyInfo(Form_pg_index indexTuple,
int *numAttsOutP,
AttrNumber **attsOutP,
FuncIndexInfoPtr fInfoP)
{
int i;
int numKeys;
AttrNumber *attKeys;
/* ----------------
* check parameters
* ----------------
*/
if (numAttsOutP == NULL || attsOutP == NULL)
{
elog(DEBUG, "ExecGetIndexKeyInfo: %s",
"invalid parameters: numAttsOutP and attsOutP must be non-NULL");
}
/* ----------------
* set the procid for a possible functional index.
* ----------------
*/
FIsetProcOid(fInfoP, indexTuple->indproc);
/* ----------------
* count the number of keys..
* ----------------
*/
numKeys = 0;
for (i = 0; i < INDEX_MAX_KEYS &&
indexTuple->indkey[i] != InvalidAttrNumber; i++)
numKeys++;
/* ----------------
* place number keys in callers return area
* or the number of arguments for a functional index.
*
* If we have a functional index then the number of
* attributes defined in the index must 1 (the function's
* single return value).
* ----------------
*/
if (FIgetProcOid(fInfoP) != InvalidOid)
{
FIsetnArgs(fInfoP, numKeys);
(*numAttsOutP) = 1;
}
else
(*numAttsOutP) = numKeys;
if (numKeys < 1)
{
elog(DEBUG, "ExecGetIndexKeyInfo: %s",
"all index key attribute numbers are zero!");
(*attsOutP) = NULL;
return;
}
/* ----------------
* allocate and fill in array of key attribute numbers
* ----------------
*/
CXT1_printf("ExecGetIndexKeyInfo: context is %d\n", CurrentMemoryContext);
attKeys = (AttrNumber *) palloc(numKeys * sizeof(AttrNumber));
for (i = 0; i < numKeys; i++)
attKeys[i] = indexTuple->indkey[i];
/* ----------------
* return array to caller.
* ----------------
*/
(*attsOutP) = attKeys;
}
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* ExecOpenIndices * ExecOpenIndices
...@@ -838,11 +747,6 @@ ExecOpenIndices(RelationInfo *resultRelationInfo) ...@@ -838,11 +747,6 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
Oid indexOid = lfirsti(indexoidscan); Oid indexOid = lfirsti(indexoidscan);
Relation indexDesc; Relation indexDesc;
HeapTuple indexTuple; HeapTuple indexTuple;
Form_pg_index indexStruct;
int numKeyAtts;
AttrNumber *indexKeyAtts;
FuncIndexInfoPtr fInfoP;
PredInfo *predicate;
IndexInfo *ii; IndexInfo *ii;
/* ---------------- /* ----------------
...@@ -874,47 +778,17 @@ ExecOpenIndices(RelationInfo *resultRelationInfo) ...@@ -874,47 +778,17 @@ ExecOpenIndices(RelationInfo *resultRelationInfo)
* Get the pg_index tuple for the index * Get the pg_index tuple for the index
* ---------------- * ----------------
*/ */
indexTuple = SearchSysCacheTupleCopy(INDEXRELID, indexTuple = SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(indexOid), ObjectIdGetDatum(indexOid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(indexTuple)) if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "ExecOpenIndices: index %u not found", indexOid); elog(ERROR, "ExecOpenIndices: index %u not found", indexOid);
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
/* ---------------- /* ----------------
* extract the index key information from the tuple * extract the index key information from the tuple
* ---------------- * ----------------
*/ */
fInfoP = (FuncIndexInfoPtr) palloc(sizeof(*fInfoP)); ii = BuildIndexInfo(indexTuple);
ExecGetIndexKeyInfo(indexStruct,
&numKeyAtts,
&indexKeyAtts,
fInfoP);
/* ----------------
* next get the index predicate from the tuple
* ----------------
*/
if (VARSIZE(&indexStruct->indpred) != 0)
{
char *predString;
predString = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(&indexStruct->indpred)));
predicate = (PredInfo *) stringToNode(predString);
pfree(predString);
}
else
predicate = NULL;
/* Save the index info */
ii = makeNode(IndexInfo);
ii->ii_NumKeyAttributes = numKeyAtts;
ii->ii_KeyAttributeNumbers = indexKeyAtts;
ii->ii_FuncIndexInfo = fInfoP;
ii->ii_Predicate = (Node *) predicate;
heap_freetuple(indexTuple);
relationDescs[i] = indexDesc; relationDescs[i] = indexDesc;
indexInfoArray[i] = ii; indexInfoArray[i] = ii;
...@@ -984,17 +858,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -984,17 +858,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
int numIndices; int numIndices;
RelationPtr relationDescs; RelationPtr relationDescs;
Relation heapRelation; Relation heapRelation;
TupleDesc heapDescriptor;
IndexInfo **indexInfoArray; IndexInfo **indexInfoArray;
IndexInfo *indexInfo;
Node *predicate;
ExprContext *econtext; ExprContext *econtext;
InsertIndexResult result; Datum datum[INDEX_MAX_KEYS];
int numberOfAttributes; char nullv[INDEX_MAX_KEYS];
AttrNumber *keyAttributeNumbers;
FuncIndexInfoPtr fInfoP;
TupleDesc heapDescriptor;
Datum *datum;
char *nulls;
heapTuple = slot->val; heapTuple = slot->val;
...@@ -1007,14 +875,27 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -1007,14 +875,27 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
relationDescs = resultRelationInfo->ri_IndexRelationDescs; relationDescs = resultRelationInfo->ri_IndexRelationDescs;
indexInfoArray = resultRelationInfo->ri_IndexRelationInfo; indexInfoArray = resultRelationInfo->ri_IndexRelationInfo;
heapRelation = resultRelationInfo->ri_RelationDesc; heapRelation = resultRelationInfo->ri_RelationDesc;
heapDescriptor = RelationGetDescr(heapRelation);
/* ----------------
* Make a temporary expr/memory context for evaluating predicates
* and functional-index functions.
* XXX should do this once per command not once per tuple, and
* just reset it once per tuple.
* ----------------
*/
econtext = MakeExprContext(slot, TransactionCommandContext);
/* ---------------- /* ----------------
* for each index, form and insert the index tuple * for each index, form and insert the index tuple
* ---------------- * ----------------
*/ */
econtext = NULL;
for (i = 0; i < numIndices; i++) for (i = 0; i < numIndices; i++)
{ {
IndexInfo *indexInfo;
Node *predicate;
InsertIndexResult result;
if (relationDescs[i] == NULL) if (relationDescs[i] == NULL)
continue; continue;
...@@ -1022,39 +903,26 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -1022,39 +903,26 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
predicate = indexInfo->ii_Predicate; predicate = indexInfo->ii_Predicate;
if (predicate != NULL) if (predicate != NULL)
{ {
if (econtext == NULL)
econtext = MakeExprContext(slot,
TransactionCommandContext);
/* Skip this index-update if the predicate isn't satisfied */ /* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual((List *) predicate, econtext, false)) if (!ExecQual((List *) predicate, econtext, false))
continue; continue;
} }
/* ---------------- /* ----------------
* get information from index info structure * FormIndexDatum fills in its datum and null parameters
* with attribute information taken from the given heap tuple.
* ---------------- * ----------------
*/ */
numberOfAttributes = indexInfo->ii_NumKeyAttributes; FormIndexDatum(indexInfo,
keyAttributeNumbers = indexInfo->ii_KeyAttributeNumbers; heapTuple,
fInfoP = indexInfo->ii_FuncIndexInfo; heapDescriptor,
datum = (Datum *) palloc(numberOfAttributes * sizeof *datum); econtext->ecxt_per_tuple_memory,
nulls = (char *) palloc(numberOfAttributes * sizeof *nulls); datum,
heapDescriptor = (TupleDesc) RelationGetDescr(heapRelation); nullv);
FormIndexDatum(numberOfAttributes, /* num attributes */
keyAttributeNumbers, /* array of att nums to
* extract */
heapTuple, /* tuple from base relation */
heapDescriptor, /* heap tuple's descriptor */
datum, /* return: array of attributes */
nulls, /* return: array of char's */
fInfoP); /* functional index information */
result = index_insert(relationDescs[i], /* index relation */ result = index_insert(relationDescs[i], /* index relation */
datum, /* array of heaptuple Datums */ datum, /* array of heaptuple Datums */
nulls, /* info on nulls */ nullv, /* info on nulls */
&(heapTuple->t_self), /* tid of heap tuple */ &(heapTuple->t_self), /* tid of heap tuple */
heapRelation); heapRelation);
...@@ -1064,15 +932,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot, ...@@ -1064,15 +932,11 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
*/ */
IncrIndexInserted(); IncrIndexInserted();
/* ----------------
* free index tuple after insertion
* ----------------
*/
if (result) if (result)
pfree(result); pfree(result);
} }
if (econtext != NULL)
FreeExprContext(econtext); FreeExprContext(econtext);
} }
void void
...@@ -1094,5 +958,4 @@ SetChangedParamList(Plan *node, List *newchg) ...@@ -1094,5 +958,4 @@ SetChangedParamList(Plan *node, List *newchg)
/* else - add this param to the list */ /* else - add this param to the list */
node->chgParam = lappendi(node->chgParam, paramId); node->chgParam = lappendi(node->chgParam, paramId);
} }
} }
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.73 2000/07/04 06:11:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.74 2000/07/14 22:17:48 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -87,12 +87,12 @@ static int _inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln); ...@@ -87,12 +87,12 @@ static int _inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln);
LargeObjectDesc * LargeObjectDesc *
inv_create(int flags) inv_create(int flags)
{ {
int file_oid;
LargeObjectDesc *retval; LargeObjectDesc *retval;
Oid file_oid;
Relation r; Relation r;
Relation indr; Relation indr;
TupleDesc tupdesc; TupleDesc tupdesc;
AttrNumber attNums[1]; IndexInfo *indexInfo;
Oid classObjectId[1]; Oid classObjectId[1];
char objname[NAMEDATALEN]; char objname[NAMEDATALEN];
char indname[NAMEDATALEN]; char indname[NAMEDATALEN];
...@@ -109,17 +109,13 @@ inv_create(int flags) ...@@ -109,17 +109,13 @@ inv_create(int flags)
sprintf(indname, "xinx%u", file_oid); sprintf(indname, "xinx%u", file_oid);
if (RelnameFindRelid(objname) != InvalidOid) if (RelnameFindRelid(objname) != InvalidOid)
{
elog(ERROR, elog(ERROR,
"internal error: %s already exists -- cannot create large obj", "internal error: %s already exists -- cannot create large obj",
objname); objname);
}
if (RelnameFindRelid(indname) != InvalidOid) if (RelnameFindRelid(indname) != InvalidOid)
{
elog(ERROR, elog(ERROR,
"internal error: %s already exists -- cannot create large obj", "internal error: %s already exists -- cannot create large obj",
indname); indname);
}
/* this is pretty painful... want a tuple descriptor */ /* this is pretty painful... want a tuple descriptor */
tupdesc = CreateTemplateTupleDesc(2); tupdesc = CreateTemplateTupleDesc(2);
...@@ -155,21 +151,25 @@ inv_create(int flags) ...@@ -155,21 +151,25 @@ inv_create(int flags)
/* /*
* Now create a btree index on the relation's olastbyte attribute to * Now create a btree index on the relation's olastbyte attribute to
* make seeks go faster. The hardwired constants are embarassing to * make seeks go faster.
* me, and are symptomatic of the pressure under which this code was
* written.
*
* ok, mao, let's put in some symbolic constants - jolly
*/ */
indexInfo = makeNode(IndexInfo);
indexInfo->ii_NumIndexAttrs = 1;
indexInfo->ii_NumKeyAttrs = 1;
indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_Predicate = NULL;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = false;
attNums[0] = 1;
classObjectId[0] = INT4_OPS_OID; classObjectId[0] = INT4_OPS_OID;
index_create(objname, indname, NULL, NULL, BTREE_AM_OID,
1, &attNums[0], &classObjectId[0], index_create(objname, indname, indexInfo,
(Node *) NULL, false, false, false, false); BTREE_AM_OID, classObjectId,
false, false, false);
/* make the index visible in this transaction */ /* make the index visible in this transaction */
CommandCounterIncrement(); CommandCounterIncrement();
indr = index_openr(indname); indr = index_openr(indname);
if (!RelationIsValid(indr)) if (!RelationIsValid(indr))
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.106 2000/07/05 23:11:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.107 2000/07/14 22:17:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1065,6 +1065,7 @@ IndexedAccessMethodInitialize(Relation relation) ...@@ -1065,6 +1065,7 @@ IndexedAccessMethodInitialize(Relation relation)
support = (RegProcedure *) NULL; support = (RegProcedure *) NULL;
IndexSupportInitialize(strategy, support, IndexSupportInitialize(strategy, support,
&relation->rd_uniqueindex,
relation->rd_att->attrs[0]->attrelid, relation->rd_att->attrs[0]->attrelid,
relation->rd_rel->relam, relation->rd_rel->relam,
relamstrategies, relamsupport, natts); relamstrategies, relamsupport, natts);
......
/*-------------------------------------------------------------------------
*
* funcindex.h
*
*
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: funcindex.h,v 1.9 2000/01/26 05:57:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef _FUNC_INDEX_INCLUDED_
#define _FUNC_INDEX_INCLUDED_
typedef struct
{
int nargs;
Oid arglist[FUNC_MAX_ARGS];
Oid procOid;
NameData funcName;
} FuncIndexInfo;
typedef FuncIndexInfo *FuncIndexInfoPtr;
/*
* some marginally useful macro definitions
*/
/* #define FIgetname(FINFO) (&((FINFO)->funcName.data[0]))*/
#define FIgetname(FINFO) (FINFO)->funcName.data
#define FIgetnArgs(FINFO) (FINFO)->nargs
#define FIgetProcOid(FINFO) (FINFO)->procOid
#define FIgetArg(FINFO, argnum) (FINFO)->arglist[argnum]
#define FIgetArglist(FINFO) (FINFO)->arglist
#define FIsetnArgs(FINFO, numargs) ((FINFO)->nargs = numargs)
#define FIsetProcOid(FINFO, id) ((FINFO)->procOid = id)
#define FIsetArg(FINFO, argnum, argtype) ((FINFO)->arglist[argnum] = argtype)
#define FIisFunctionalIndex(FINFO) (FINFO->procOid != InvalidOid)
#endif /* FUNCINDEX_H */
...@@ -7,14 +7,13 @@ ...@@ -7,14 +7,13 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: genam.h,v 1.23 2000/01/26 05:57:50 momjian Exp $ * $Id: genam.h,v 1.24 2000/07/14 22:17:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef GENAM_H #ifndef GENAM_H
#define GENAM_H #define GENAM_H
#include "access/funcindex.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
...@@ -42,9 +41,6 @@ extern RetrieveIndexResult index_getnext(IndexScanDesc scan, ...@@ -42,9 +41,6 @@ extern RetrieveIndexResult index_getnext(IndexScanDesc scan,
extern RegProcedure index_cost_estimator(Relation relation); extern RegProcedure index_cost_estimator(Relation relation);
extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum, extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
uint16 procnum); uint16 procnum);
extern Datum GetIndexValue(HeapTuple tuple, TupleDesc hTupDesc,
int attOff, AttrNumber *attrNums, FuncIndexInfo *fInfo,
bool *attNull);
/* in genam.c */ /* in genam.c */
extern IndexScanDesc RelationGetIndexScan(Relation relation, bool scanFromEnd, extern IndexScanDesc RelationGetIndexScan(Relation relation, bool scanFromEnd,
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#ifndef GIST_H #ifndef GIST_H
#define GIST_H #define GIST_H
#include "access/funcindex.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: hash.h,v 1.34 2000/06/19 03:54:35 tgl Exp $ * $Id: hash.h,v 1.35 2000/07/14 22:17:53 tgl Exp $
* *
* NOTES * NOTES
* modeled after Margo Seltzer's hash implementation for unix. * modeled after Margo Seltzer's hash implementation for unix.
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#ifndef HASH_H #ifndef HASH_H
#define HASH_H #define HASH_H
#include "access/funcindex.h"
#include "access/itup.h" #include "access/itup.h"
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: istrat.h,v 1.17 2000/06/08 22:37:36 momjian Exp $ * $Id: istrat.h,v 1.18 2000/07/14 22:17:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,9 +56,12 @@ extern StrategyNumber RelationGetStrategy(Relation relation, ...@@ -56,9 +56,12 @@ extern StrategyNumber RelationGetStrategy(Relation relation,
AttrNumber attributeNumber, StrategyEvaluation evaluation, AttrNumber attributeNumber, StrategyEvaluation evaluation,
RegProcedure procedure); RegProcedure procedure);
extern void IndexSupportInitialize(IndexStrategy indexStrategy, extern void IndexSupportInitialize(IndexStrategy indexStrategy,
RegProcedure *indexSupport, Oid indexObjectId, RegProcedure *indexSupport,
Oid accessMethodObjectId, StrategyNumber maxStrategyNumber, bool *isUnique,
StrategyNumber maxSupportNumber, AttrNumber maxAttributeNumber); Oid indexObjectId,
Oid accessMethodObjectId,
StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber);
#endif /* ISTRAT_H */ #endif /* ISTRAT_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: itup.h,v 1.24 2000/03/17 02:36:37 tgl Exp $ * $Id: itup.h,v 1.25 2000/07/14 22:17:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,18 +61,6 @@ typedef struct RetrieveIndexResultData ...@@ -61,18 +61,6 @@ typedef struct RetrieveIndexResultData
typedef RetrieveIndexResultData *RetrieveIndexResult; typedef RetrieveIndexResultData *RetrieveIndexResult;
/*-----------------
* PredInfo -
* used for partial indices
*-----------------
*/
typedef struct PredInfo
{
Node *pred;
Node *oldPred;
} PredInfo;
/* ---------------- /* ----------------
* externs * externs
* ---------------- * ----------------
......
...@@ -7,18 +7,21 @@ ...@@ -7,18 +7,21 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bootstrap.h,v 1.18 2000/06/17 23:41:49 tgl Exp $ * $Id: bootstrap.h,v 1.19 2000/07/14 22:17:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef BOOTSTRAP_H #ifndef BOOTSTRAP_H
#define BOOTSTRAP_H #define BOOTSTRAP_H
#include "access/funcindex.h"
#include "access/itup.h" #include "access/itup.h"
#include "nodes/execnodes.h"
#include "utils/rel.h" #include "utils/rel.h"
#define MAXATTR 40 /* max. number of attributes in a relation */ /* MAXATTR is the maximum number of attributes in a relation supported
* at bootstrap time (ie, the max possible in a system table).
*/
#define MAXATTR 40
typedef struct hashnode typedef struct hashnode
{ {
...@@ -35,10 +38,7 @@ extern int DebugMode; ...@@ -35,10 +38,7 @@ extern int DebugMode;
extern int BootstrapMain(int ac, char *av[]); extern int BootstrapMain(int ac, char *av[]);
extern void index_register(char *heap, char *ind, extern void index_register(char *heap, char *ind, IndexInfo *indexInfo);
int natts, AttrNumber *attnos,
FuncIndexInfo *finfo, PredInfo *predInfo,
bool unique);
extern void err_out(void); extern void err_out(void);
extern void InsertOneTuple(Oid objectid); extern void InsertOneTuple(Oid objectid);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: index.h,v 1.28 2000/07/12 02:37:27 tgl Exp $ * $Id: index.h,v 1.29 2000/07/14 22:17:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -27,25 +27,24 @@ extern void InitIndexStrategy(int numatts, ...@@ -27,25 +27,24 @@ extern void InitIndexStrategy(int numatts,
Oid accessMethodObjectId); Oid accessMethodObjectId);
extern void index_create(char *heapRelationName, extern void index_create(char *heapRelationName,
char *indexRelationName, char *indexRelationName,
FuncIndexInfo *funcInfo, IndexInfo *indexInfo,
List *attributeList, Oid accessMethodObjectId,
Oid accessMethodObjectId, Oid *classObjectId,
int numatts, bool islossy,
AttrNumber *attNums, bool primary,
Oid *classObjectId, bool allow_system_table_mods);
Node *predicate,
bool islossy,
bool unique,
bool primary,
bool allow_system_table_mods);
extern void index_drop(Oid indexId); extern void index_drop(Oid indexId);
extern void FormIndexDatum(int numberOfAttributes, extern IndexInfo *BuildIndexInfo(HeapTuple indexTuple);
AttrNumber *attributeNumber, HeapTuple heapTuple,
TupleDesc heapDescriptor, Datum *datum, extern void FormIndexDatum(IndexInfo *indexInfo,
char *nullv, FuncIndexInfoPtr fInfo); HeapTuple heapTuple,
TupleDesc heapDescriptor,
MemoryContext resultCxt,
Datum *datum,
char *nullv);
extern void UpdateStats(Oid relid, long reltuples, bool inplace); extern void UpdateStats(Oid relid, long reltuples, bool inplace);
extern bool IndexesAreActive(Oid relid, bool comfirmCommitted); extern bool IndexesAreActive(Oid relid, bool comfirmCommitted);
...@@ -54,11 +53,7 @@ extern bool SetReindexProcessing(bool processing); ...@@ -54,11 +53,7 @@ extern bool SetReindexProcessing(bool processing);
extern bool IsReindexProcessing(void); extern bool IsReindexProcessing(void);
extern void index_build(Relation heapRelation, Relation indexRelation, extern void index_build(Relation heapRelation, Relation indexRelation,
int numberOfAttributes, AttrNumber *attributeNumber, IndexInfo *indexInfo, Node *oldPred);
FuncIndexInfo *funcInfo, PredInfo *predInfo,
bool unique);
extern bool IndexIsUnique(Oid indexId);
extern bool reindex_index(Oid indexId, bool force); extern bool reindex_index(Oid indexId, bool force);
extern bool activate_indexes_of_a_table(Oid relid, bool activate); extern bool activate_indexes_of_a_table(Oid relid, bool activate);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_proc.h,v 1.146 2000/07/08 03:04:21 tgl Exp $ * $Id: pg_proc.h,v 1.147 2000/07/14 22:17:56 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -677,7 +677,7 @@ DATA(insert OID = 321 ( rtdelete PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100 ...@@ -677,7 +677,7 @@ DATA(insert OID = 321 ( rtdelete PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100
DESCR("r-tree(internal)"); DESCR("r-tree(internal)");
DATA(insert OID = 322 ( rtgettuple PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100 rtgettuple - )); DATA(insert OID = 322 ( rtgettuple PGUID 12 f t f t 2 f 23 "0 0" 100 0 0 100 rtgettuple - ));
DESCR("r-tree(internal)"); DESCR("r-tree(internal)");
DATA(insert OID = 323 ( rtbuild PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100 rtbuild - )); DATA(insert OID = 323 ( rtbuild PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100 rtbuild - ));
DESCR("r-tree(internal)"); DESCR("r-tree(internal)");
DATA(insert OID = 324 ( rtbeginscan PGUID 12 f t f t 4 f 23 "0 0 0 0" 100 0 0 100 rtbeginscan - )); DATA(insert OID = 324 ( rtbeginscan PGUID 12 f t f t 4 f 23 "0 0 0 0" 100 0 0 100 rtbeginscan - ));
DESCR("r-tree(internal)"); DESCR("r-tree(internal)");
...@@ -706,7 +706,7 @@ DATA(insert OID = 336 ( btmarkpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 ...@@ -706,7 +706,7 @@ DATA(insert OID = 336 ( btmarkpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 337 ( btrestrpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 btrestrpos - )); DATA(insert OID = 337 ( btrestrpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 btrestrpos - ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 338 ( btbuild PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100 btbuild - )); DATA(insert OID = 338 ( btbuild PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100 btbuild - ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 339 ( poly_same PGUID 11 f t t t 2 f 16 "604 604" 100 0 1 0 poly_same - )); DATA(insert OID = 339 ( poly_same PGUID 11 f t t t 2 f 16 "604 604" 100 0 1 0 poly_same - ));
...@@ -810,7 +810,7 @@ DATA(insert OID = 446 ( hashmarkpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 ...@@ -810,7 +810,7 @@ DATA(insert OID = 446 ( hashmarkpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 447 ( hashrestrpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 hashrestrpos - )); DATA(insert OID = 447 ( hashrestrpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 hashrestrpos - ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 448 ( hashbuild PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100 hashbuild - )); DATA(insert OID = 448 ( hashbuild PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100 hashbuild - ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 449 ( hashint2 PGUID 12 f t t t 1 f 23 "21" 100 0 0 100 hashint2 - )); DATA(insert OID = 449 ( hashint2 PGUID 12 f t t t 1 f 23 "21" 100 0 0 100 hashint2 - ));
DESCR("hash"); DESCR("hash");
...@@ -1033,7 +1033,7 @@ DATA(insert OID = 780 ( gistmarkpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 ...@@ -1033,7 +1033,7 @@ DATA(insert OID = 780 ( gistmarkpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 781 ( gistrestrpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 gistrestrpos - )); DATA(insert OID = 781 ( gistrestrpos PGUID 12 f t f t 1 f 23 "0" 100 0 0 100 gistrestrpos - ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 782 ( gistbuild PGUID 12 f t f t 8 f 23 "0 0 0 0 0 0 0 0" 100 0 0 100 gistbuild - )); DATA(insert OID = 782 ( gistbuild PGUID 12 f t f t 5 f 23 "0 0 0 0 0" 100 0 0 100 gistbuild - ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 784 ( tintervaleq PGUID 12 f t f t 2 f 16 "704 704" 100 0 0 100 tintervaleq - )); DATA(insert OID = 784 ( tintervaleq PGUID 12 f t f t 2 f 16 "704 704" 100 0 0 100 tintervaleq - ));
......
...@@ -7,17 +7,16 @@ ...@@ -7,17 +7,16 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: vacuum.h,v 1.31 2000/05/29 17:40:44 momjian Exp $ * $Id: vacuum.h,v 1.32 2000/07/14 22:17:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef VACUUM_H #ifndef VACUUM_H
#define VACUUM_H #define VACUUM_H
#include "fmgr.h"
#include "access/funcindex.h"
#include "catalog/pg_index.h"
#include "catalog/pg_attribute.h" #include "catalog/pg_attribute.h"
#include "catalog/pg_index.h"
#include "fmgr.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "storage/itemptr.h" #include "storage/itemptr.h"
...@@ -54,14 +53,6 @@ typedef struct VacPageListData ...@@ -54,14 +53,6 @@ typedef struct VacPageListData
typedef VacPageListData *VacPageList; typedef VacPageListData *VacPageList;
typedef struct
{
FuncIndexInfo finfo;
FuncIndexInfo *finfoP;
Form_pg_index tform;
int natts;
} IndDesc;
typedef struct typedef struct
{ {
Form_pg_attribute attr; Form_pg_attribute attr;
......
...@@ -7,39 +7,49 @@ ...@@ -7,39 +7,49 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execnodes.h,v 1.43 2000/07/12 02:37:32 tgl Exp $ * $Id: execnodes.h,v 1.44 2000/07/14 22:17:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef EXECNODES_H #ifndef EXECNODES_H
#define EXECNODES_H #define EXECNODES_H
#include "access/funcindex.h"
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sdir.h" #include "access/sdir.h"
#include "executor/hashjoin.h" #include "executor/hashjoin.h"
#include "executor/tuptable.h" #include "executor/tuptable.h"
#include "fmgr.h"
#include "nodes/params.h" #include "nodes/params.h"
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
/* ---------------- /* ----------------
* IndexInfo information * IndexInfo information
* *
* this class holds the information saying what attributes * this class holds the information needed to construct new index
* are the key attributes for this index. -cim 10/15/89 * entries for a particular index. Used for both index_build and
* * retail creation of index entries.
* NumKeyAttributes number of key attributes for this index *
* KeyAttributeNumbers array of attribute numbers used as keys * NumIndexAttrs number of columns in this index
* Predicate partial-index predicate for this index * (1 if a func. index, else same as NumKeyAttrs)
* NumKeyAttrs number of key attributes for this index
* (ie, number of attrs from underlying relation)
* KeyAttrNumbers underlying-rel attribute numbers used as keys
* Predicate partial-index predicate, or NULL if none
* FuncOid OID of function, or InvalidOid if not f. index
* FuncInfo fmgr lookup data for function, if FuncOid valid
* Unique is it a unique index?
* ---------------- * ----------------
*/ */
typedef struct IndexInfo typedef struct IndexInfo
{ {
NodeTag type; NodeTag type;
int ii_NumKeyAttributes; int ii_NumIndexAttrs;
AttrNumber *ii_KeyAttributeNumbers; int ii_NumKeyAttrs;
FuncIndexInfoPtr ii_FuncIndexInfo; AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS];
Node *ii_Predicate; Node *ii_Predicate;
Oid ii_FuncOid;
FmgrInfo ii_FuncInfo;
bool ii_Unique;
} IndexInfo; } IndexInfo;
/* ---------------- /* ----------------
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: rel.h,v 1.39 2000/06/30 07:04:03 tgl Exp $ * $Id: rel.h,v 1.40 2000/07/14 22:18:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,6 +92,7 @@ typedef struct RelationData ...@@ -92,6 +92,7 @@ typedef struct RelationData
bool rd_isnailed; /* rel is nailed in cache */ bool rd_isnailed; /* rel is nailed in cache */
bool rd_unlinked; /* rel already unlinked or not created yet */ bool rd_unlinked; /* rel already unlinked or not created yet */
bool rd_indexfound; /* true if rd_indexlist is valid */ bool rd_indexfound; /* true if rd_indexlist is valid */
bool rd_uniqueindex; /* true if rel is a UNIQUE index */
Form_pg_am rd_am; /* AM tuple */ Form_pg_am rd_am; /* AM tuple */
Form_pg_class rd_rel; /* RELATION tuple */ Form_pg_class rd_rel; /* RELATION tuple */
Oid rd_id; /* relation's object id */ Oid rd_id; /* relation's object id */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment