1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-23 14:01:44 +03:00

Partial indexes work again, courtesy of Martijn van Oosterhout.

Note: I didn't force an initdb, figuring that one today was enough.
However, there is a new function in pg_proc.h, and pg_dump won't be
able to dump partial indexes until you add that function.
This commit is contained in:
Tom Lane
2001-07-16 05:07:00 +00:00
parent 237e5dfa58
commit f31dc0ada7
32 changed files with 474 additions and 491 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.51 2001/07/15 22:48:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.52 2001/07/16 05:06:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,8 +45,6 @@
/* non-export function prototypes */
static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
static void CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid);
static void CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
static void FuncIndexArgs(IndexInfo *indexInfo, Oid *classOidP,
IndexElem *funcIndex,
Oid relId,
@ -144,12 +142,8 @@ DefineIndex(char *heapRelationName,
}
/*
* Convert the partial-index predicate from parsetree form to plan
* form, so it can be readily evaluated during index creation. Note:
* "predicate" comes in as a list containing (1) the predicate itself
* (a where_clause), and (2) a corresponding range table.
*
* [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
* Convert the partial-index predicate from parsetree form to
* an implicit-AND qual expression, for easier evaluation at runtime.
*/
if (predicate != NULL && rangetable != NIL)
{
@ -166,7 +160,7 @@ DefineIndex(char *heapRelationName,
* structure
*/
indexInfo = makeNode(IndexInfo);
indexInfo->ii_Predicate = (Node *) cnfPred;
indexInfo->ii_Predicate = cnfPred;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = unique;
@ -218,155 +212,30 @@ DefineIndex(char *heapRelationName,
}
/*
* ExtendIndex
* Extends a partial index.
*/
void
ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
{
Relation heapRelation;
Relation indexRelation;
Oid accessMethodId,
indexId,
relationId;
HeapTuple tuple;
Form_pg_index index;
List *cnfPred = NIL;
IndexInfo *indexInfo;
Node *oldPred;
/*
* Get index's relation id and access method id from pg_class
*/
tuple = SearchSysCache(RELNAME,
PointerGetDatum(indexRelationName),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ExtendIndex: index \"%s\" not found",
indexRelationName);
indexId = tuple->t_data->t_oid;
accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
ReleaseSysCache(tuple);
/*
* Extract info from the pg_index tuple for the index
*/
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexId),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "ExtendIndex: relation \"%s\" is not an index",
indexRelationName);
index = (Form_pg_index) GETSTRUCT(tuple);
Assert(index->indexrelid == indexId);
relationId = index->indrelid;
indexInfo = BuildIndexInfo(tuple);
oldPred = indexInfo->ii_Predicate;
ReleaseSysCache(tuple);
if (oldPred == NULL)
elog(ERROR, "ExtendIndex: \"%s\" is not a partial index",
indexRelationName);
/*
* Convert the extension predicate from parsetree form to plan form,
* so it can be readily evaluated during index creation. Note:
* "predicate" comes in two parts (1) the predicate expression itself,
* 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)
{
cnfPred = cnfify((Expr *) copyObject(predicate), true);
fix_opids((Node *) cnfPred);
CheckPredicate(cnfPred, rangetable, relationId);
}
/* pass new predicate to index_build */
indexInfo->ii_Predicate = (Node *) cnfPred;
/* Open heap and index rels, and get suitable locks */
heapRelation = heap_open(relationId, ShareLock);
indexRelation = index_open(indexId);
/* Obtain exclusive lock on it, just to be sure */
LockRelation(indexRelation, AccessExclusiveLock);
InitIndexStrategy(indexInfo->ii_NumIndexAttrs,
indexRelation, accessMethodId);
/*
* XXX currently BROKEN: if we want to support EXTEND INDEX, oldPred
* needs to be passed through to IndexBuildHeapScan. We could do this
* without help from the index AMs if we added an oldPred field to the
* IndexInfo struct. Currently I'm expecting that EXTEND INDEX will
* get removed, so I'm not going to do that --- tgl 7/14/01
*/
index_build(heapRelation, indexRelation, indexInfo);
/* heap and index rels are closed as a side-effect of index_build */
}
/*
* CheckPredicate
* Checks that the given list of partial-index predicates refer
* (via the given range table) only to the given base relation oid,
* and that they're in a form the planner can handle, i.e.,
* boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR
* has to be on the left).
* (via the given range table) only to the given base relation oid.
*
* This used to also constrain the form of the predicate to forms that
* indxpath.c could do something with. However, that seems overly
* restrictive. One useful application of partial indexes is to apply
* a UNIQUE constraint across a subset of a table, and in that scenario
* any evaluatable predicate will work. So accept any predicate here
* (except ones requiring a plan), and let indxpath.c fend for itself.
*/
static void
CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
{
List *item;
foreach(item, predList)
CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
}
static void
CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid)
{
List *clauses = NIL,
*clause;
if (is_opclause(predicate))
{
CheckPredClause((Expr *) predicate, rangeTable, baseRelOid);
return;
}
else if (or_clause(predicate) || and_clause(predicate))
clauses = ((Expr *) predicate)->args;
else
elog(ERROR, "Unsupported partial-index predicate expression type");
foreach(clause, clauses)
CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
}
static void
CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
{
Var *pred_var;
Const *pred_const;
pred_var = (Var *) get_leftop(predicate);
pred_const = (Const *) get_rightop(predicate);
if (!IsA(predicate->oper, Oper) ||
!IsA(pred_var, Var) ||
!IsA(pred_const, Const))
elog(ERROR, "Unsupported partial-index predicate clause type");
if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
if (length(rangeTable) != 1 || getrelid(1, rangeTable) != baseRelOid)
elog(ERROR,
"Partial-index predicates may refer only to the base relation");
"Partial-index predicates may refer only to the base relation");
if (contain_subplans((Node *) predList))
elog(ERROR, "Cannot use subselect in index predicate");
if (contain_agg_clause((Node *) predList))
elog(ERROR, "Cannot use aggregate in index predicate");
}