1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +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 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.111 2001/07/15 22:48:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.112 2001/07/16 05:06:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1100,8 +1100,9 @@ index_register(char *heap,
newind->il_info = (IndexInfo *) palloc(sizeof(IndexInfo));
memcpy(newind->il_info, indexInfo, sizeof(IndexInfo));
/* predicate will likely be null anyway, but may as well copy it */
newind->il_info->ii_Predicate = copyObject(indexInfo->ii_Predicate);
/* predicate will likely be null, but may as well copy it */
newind->il_info->ii_Predicate = (List *)
copyObject(indexInfo->ii_Predicate);
newind->il_next = ILHead;
ILHead = newind;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.156 2001/07/15 22:48:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.157 2001/07/16 05:06:57 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -510,7 +510,7 @@ UpdateIndexRelation(Oid indexoid,
* allocate a Form_pg_index big enough to hold the index-predicate (if
* any) in string form
*/
if (indexInfo->ii_Predicate != NULL)
if (indexInfo->ii_Predicate != NIL)
{
predString = nodeToString(indexInfo->ii_Predicate);
predText = DatumGetTextP(DirectFunctionCall1(textin,
@@ -586,87 +586,6 @@ UpdateIndexRelation(Oid indexoid,
heap_freetuple(tuple);
}
/* ----------------------------------------------------------------
* UpdateIndexPredicate
* ----------------------------------------------------------------
*/
void
UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate)
{
Node *newPred;
char *predString;
text *predText;
Relation pg_index;
HeapTuple tuple;
HeapTuple newtup;
int i;
Datum values[Natts_pg_index];
char nulls[Natts_pg_index];
char replace[Natts_pg_index];
/*
* Construct newPred as a CNF expression equivalent to the OR of the
* original partial-index predicate ("oldPred") and the extension
* predicate ("predicate").
*
* This should really try to process the result to change things like
* "a>2 OR a>1" to simply "a>1", but for now all it does is make sure
* that if the extension predicate is NULL (i.e., it is being extended
* to be a complete index), then newPred will be NULL - in effect,
* changing "a>2 OR TRUE" to "TRUE". --Nels, Jan '93
*/
newPred = NULL;
if (predicate != NULL)
{
newPred = (Node *) make_orclause(lcons(make_andclause((List *) predicate),
lcons(make_andclause((List *) oldPred),
NIL)));
newPred = (Node *) cnfify((Expr *) newPred, true);
}
/* translate the index-predicate to string form */
if (newPred != NULL)
{
predString = nodeToString(newPred);
predText = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(predString)));
pfree(predString);
}
else
predText = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum("")));
/* open the index system catalog relation */
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
tuple = SearchSysCache(INDEXRELID,
ObjectIdGetDatum(indexoid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "UpdateIndexPredicate: cache lookup failed for index %u",
indexoid);
for (i = 0; i < Natts_pg_index; i++)
{
nulls[i] = heap_attisnull(tuple, i + 1) ? 'n' : ' ';
replace[i] = ' ';
values[i] = (Datum) NULL;
}
replace[Anum_pg_index_indpred - 1] = 'r';
values[Anum_pg_index_indpred - 1] = PointerGetDatum(predText);
newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace);
simple_heap_update(pg_index, &newtup->t_self, newtup);
heap_freetuple(newtup);
ReleaseSysCache(tuple);
heap_close(pg_index, RowExclusiveLock);
pfree(predText);
}
/* ----------------------------------------------------------------
* InitIndexStrategy
*
@@ -1084,7 +1003,7 @@ BuildIndexInfo(HeapTuple indexTuple)
pfree(predString);
}
else
ii->ii_Predicate = NULL;
ii->ii_Predicate = NIL;
/* Other info */
ii->ii_Unique = indexStruct->indisunique;
@@ -1684,7 +1603,7 @@ IndexBuildHeapScan(Relation heapRelation,
Datum attdata[INDEX_MAX_KEYS];
char nulls[INDEX_MAX_KEYS];
double reltuples;
Node *predicate = indexInfo->ii_Predicate;
List *predicate = indexInfo->ii_Predicate;
TupleTable tupleTable;
TupleTableSlot *slot;
ExprContext *econtext;
@@ -1708,7 +1627,7 @@ IndexBuildHeapScan(Relation heapRelation,
* We construct the ExprContext anyway since we need a per-tuple
* temporary memory context for function evaluation -- tgl July 00
*/
if (predicate != NULL)
if (predicate != NIL)
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
@@ -1831,12 +1750,12 @@ IndexBuildHeapScan(Relation heapRelation,
* VACUUM doesn't complain about tuple count mismatch for partial
* indexes.
*/
if (predicate != NULL)
if (predicate != NIL)
{
if (! tupleIsAlive)
continue;
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
if (!ExecQual((List *) predicate, econtext, false))
if (!ExecQual(predicate, econtext, false))
continue;
}
@@ -1865,7 +1784,7 @@ IndexBuildHeapScan(Relation heapRelation,
heap_endscan(scan);
if (predicate != NULL)
if (predicate != NIL)
ExecDropTupleTable(tupleTable, true);
FreeExprContext(econtext);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.135 2001/07/15 22:48:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.136 2001/07/16 05:06:57 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
@@ -1882,7 +1882,7 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
indexInfo->ii_NumIndexAttrs = 1;
indexInfo->ii_NumKeyAttrs = 1;
indexInfo->ii_KeyAttrNumbers[0] = 1;
indexInfo->ii_Predicate = NULL;
indexInfo->ii_Predicate = NIL;
indexInfo->ii_FuncOid = InvalidOid;
indexInfo->ii_Unique = false;

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");
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.76 2001/07/15 22:48:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.77 2001/07/16 05:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -641,7 +641,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
for (i = 0; i < numIndices; i++)
{
IndexInfo *indexInfo;
Node *predicate;
List *predicate;
InsertIndexResult result;
if (relationDescs[i] == NULL)
@@ -649,10 +649,10 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
indexInfo = indexInfoArray[i];
predicate = indexInfo->ii_Predicate;
if (predicate != NULL)
if (predicate != NIL)
{
/* Skip this index-update if the predicate isn't satisfied */
if (!ExecQual((List *) predicate, econtext, false))
if (!ExecQual(predicate, econtext, false))
continue;
}

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.108 2001/06/25 21:11:43 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.109 2001/07/16 05:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -195,8 +195,13 @@ create_index_paths(Query *root, RelOptInfo *rel)
* 4. Generate an indexscan path if there are relevant restriction
* clauses OR the index ordering is potentially useful for later
* merging or final output ordering.
*
* If there is a predicate, consider it anyway since the index
* predicate has already been found to match the query.
*/
if (restrictclauses != NIL || useful_pathkeys != NIL)
if (restrictclauses != NIL ||
useful_pathkeys != NIL ||
index->indpred != NIL)
add_path(rel, (Path *)
create_index_path(root, rel, index,
restrictclauses,
@@ -974,18 +979,18 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
* clauses (those in restrictinfo_list). --Nels, Dec '92
*/
if (predicate_list == NULL)
if (predicate_list == NIL)
return true; /* no predicate: the index is usable */
if (restrictinfo_list == NULL)
if (restrictinfo_list == NIL)
return false; /* no restriction clauses: the test must
* fail */
foreach(pred, predicate_list)
{
/*
* if any clause is not implied, the whole predicate is not
* implied
* implied. Note that checking for sub-ANDs here is redundant
* if the predicate has been cnfify()-ed.
*/
if (and_clause(lfirst(pred)))
{
@@ -1011,15 +1016,16 @@ pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
static bool
one_pred_test(Expr *predicate, List *restrictinfo_list)
{
RestrictInfo *restrictinfo;
List *item;
Assert(predicate != NULL);
foreach(item, restrictinfo_list)
{
restrictinfo = (RestrictInfo *) lfirst(item);
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(item);
/* if any clause implies the predicate, return true */
if (one_pred_clause_expr_test(predicate, (Node *) restrictinfo->clause))
if (one_pred_clause_expr_test(predicate,
(Node *) restrictinfo->clause))
return true;
}
return false;
@@ -1055,7 +1061,6 @@ one_pred_clause_expr_test(Expr *predicate, Node *clause)
items = ((Expr *) clause)->args;
foreach(item, items)
{
/*
* if any AND item implies the predicate, the whole clause
* does
@@ -1102,7 +1107,6 @@ one_pred_clause_test(Expr *predicate, Node *clause)
items = predicate->args;
foreach(item, items)
{
/*
* if any item is not implied, the whole predicate is not
* implied
@@ -1177,26 +1181,30 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
test_strategy;
Oper *test_oper;
Expr *test_expr;
bool test_result,
isNull;
Datum test_result;
bool isNull;
Relation relation;
HeapScanDesc scan;
HeapTuple tuple;
ScanKeyData entry[3];
Form_pg_amop aform;
ExprContext *econtext;
/* Check the basic form; for now, only allow the simplest case */
/* Note caller already verified is_opclause(predicate) */
if (!is_opclause(clause))
return false;
pred_var = (Var *) get_leftop(predicate);
pred_const = (Const *) get_rightop(predicate);
clause_var = (Var *) get_leftop((Expr *) clause);
clause_const = (Const *) get_rightop((Expr *) clause);
/* Check the basic form; for now, only allow the simplest case */
if (!is_opclause(clause) ||
!IsA(clause_var, Var) ||
if (!IsA(clause_var, Var) ||
clause_const == NULL ||
!IsA(clause_const, Const) ||
!IsA(predicate->oper, Oper) ||
!IsA(pred_var, Var) ||
pred_const == NULL ||
!IsA(pred_const, Const))
return false;
@@ -1211,10 +1219,15 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno;
clause_op = ((Oper *) ((Expr *) clause)->oper)->opno;
/*
* 1. Find a "btree" strategy number for the pred_op
*
* XXX consider using syscache lookups for these searches. Right
* now we don't have caches that match all of the search conditions,
* but reconsider it after upcoming restructuring of pg_opclass.
*/
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_amop_amopid,
F_OIDEQ,
@@ -1225,8 +1238,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
F_OIDEQ,
ObjectIdGetDatum(pred_op));
relation = heap_openr(AccessMethodOperatorRelationName, AccessShareLock);
/*
* The following assumes that any given operator will only be in a
* single btree operator class. This is true at least for all the
@@ -1254,7 +1265,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
heap_endscan(scan);
/*
* 2. From the same opclass, find a strategy num for the clause_op
*/
@@ -1281,13 +1291,12 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
/* Get the restriction clause operator's strategy number (1 to 5) */
clause_strategy = (StrategyNumber) aform->amopstrategy;
heap_endscan(scan);
heap_endscan(scan);
/*
* 3. Look up the "test" strategy number in the implication table
*/
test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
if (test_strategy == 0)
{
@@ -1298,7 +1307,6 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
/*
* 4. From the same opclass, find the operator for the test strategy
*/
ScanKeyEntryInitialize(&entry[2], 0,
Anum_pg_amop_amopstrategy,
F_INT2EQ,
@@ -1329,19 +1337,20 @@ clause_pred_clause_test(Expr *predicate, Node *clause)
InvalidOid, /* opid */
BOOLOID); /* opresulttype */
replace_opid(test_oper);
test_expr = make_opclause(test_oper,
copyObject(clause_const),
copyObject(pred_const));
(Var *) clause_const,
(Var *) pred_const);
test_result = ExecEvalExpr((Node *) test_expr, NULL, &isNull, NULL);
econtext = MakeExprContext(NULL, TransactionCommandContext);
test_result = ExecEvalExpr((Node *) test_expr, econtext, &isNull, NULL);
FreeExprContext(econtext);
if (isNull)
{
elog(DEBUG, "clause_pred_clause_test: null test result");
return false;
}
return test_result;
return DatumGetBool(test_result);
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.74 2001/06/05 05:26:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.75 2001/07/16 05:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -362,6 +362,13 @@ create_index_path(Query *root,
pathnode->alljoinquals = false;
pathnode->rows = rel->rows;
/*
* Not sure if this is necessary, but it should help if the
* statistics are too far off
*/
if (index->indpred && index->tuples < pathnode->rows)
pathnode->rows = index->tuples;
cost_index(&pathnode->path, root, rel, index, indexquals, false);
return pathnode;

View File

@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.192 2001/07/04 17:36:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.193 2001/07/16 05:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -45,7 +45,6 @@ static Query *transformStmt(ParseState *pstate, Node *stmt);
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
@@ -148,10 +147,6 @@ transformStmt(ParseState *pstate, Node *parseTree)
result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
break;
case T_ExtendStmt:
result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
break;
case T_RuleStmt:
result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
break;
@@ -1630,15 +1625,30 @@ static Query *
transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
{
Query *qry;
RangeTblEntry *rte;
qry = makeNode(Query);
qry->commandType = CMD_UTILITY;
/* take care of the where clause */
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
if (stmt->whereClause)
{
/*
* Put the parent table into the rtable so that the WHERE clause can
* refer to its fields without qualification. Note that this only
* works if the parent table already exists --- so we can't easily
* support predicates on indexes created implicitly by CREATE TABLE.
* Fortunately, that's not necessary.
*/
rte = addRangeTableEntry(pstate, stmt->relname, NULL, false, true);
/* no to join list, yes to namespace */
addRTEtoQuery(pstate, rte, false, true);
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
}
qry->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable;
qry->utilityStmt = (Node *) stmt;
@@ -1646,30 +1656,6 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
return qry;
}
/*
* transformExtendStmt -
* transform the qualifications of the Extend Index Statement
*
*/
static Query *
transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
{
Query *qry;
qry = makeNode(Query);
qry->commandType = CMD_UTILITY;
/* take care of the where clause */
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
qry->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable;
qry->utilityStmt = (Node *) stmt;
return qry;
}
/*
* transformRuleStmt -
* transform a Create Rule Statement. The actions is a list of parse

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.236 2001/07/12 18:02:59 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.237 2001/07/16 05:06:58 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -135,7 +135,7 @@ static void doNegateFloat(Value *v);
CreateSchemaStmt, CreateSeqStmt, CreateStmt, CreateTrigStmt,
CreateUserStmt, CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropTrigStmt,
DropUserStmt, DropdbStmt, ExplainStmt, ExtendStmt, FetchStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt,
@@ -345,7 +345,7 @@ static void doNegateFloat(Value *v);
BACKWARD, BEFORE, BINARY, BIT,
CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
DATABASE, DELIMITERS, DO,
EACH, ENCODING, EXCLUSIVE, EXPLAIN, EXTEND,
EACH, ENCODING, EXCLUSIVE, EXPLAIN,
FORCE, FORWARD, FUNCTION, HANDLER,
ILIKE, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL,
LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P,
@@ -450,7 +450,6 @@ stmt : AlterSchemaStmt
| DropPLangStmt
| DropTrigStmt
| DropUserStmt
| ExtendStmt
| ExplainStmt
| FetchStmt
| GrantStmt
@@ -2392,14 +2391,14 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
*
* QUERY:
* create index <indexname> on <relname>
* using <access> "(" (<col> with <op>)+ ")" [with
* <target_list>]
* [ using <access> ] "(" (<col> with <op>)+ ")"
* [ with <parameters> ]
* [ where <predicate> ]
*
* [where <qual>] is not supported anymore
*****************************************************************************/
IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
access_method_clause '(' index_params ')' opt_with
access_method_clause '(' index_params ')' opt_with where_clause
{
IndexStmt *n = makeNode(IndexStmt);
n->unique = $2;
@@ -2408,7 +2407,7 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON relation_name
n->accessMethod = $7;
n->indexParams = $9;
n->withClause = $11;
n->whereClause = NULL;
n->whereClause = $12;
$$ = (Node *)n;
}
;
@@ -2471,22 +2470,6 @@ opt_class: class
;
/*****************************************************************************
*
* QUERY:
* extend index <indexname> [where <qual>]
*
*****************************************************************************/
ExtendStmt: EXTEND INDEX index_name where_clause
{
ExtendStmt *n = makeNode(ExtendStmt);
n->idxname = $3;
n->whereClause = $4;
$$ = (Node *)n;
}
;
/*****************************************************************************
*
* QUERY:
@@ -5775,7 +5758,6 @@ ColLabel: ColId { $$ = $1; }
| EXCEPT { $$ = "except"; }
| EXISTS { $$ = "exists"; }
| EXPLAIN { $$ = "explain"; }
| EXTEND { $$ = "extend"; }
| EXTRACT { $$ = "extract"; }
| FALSE_P { $$ = "false"; }
| FLOAT { $$ = "float"; }

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.93 2001/06/19 22:39:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.94 2001/07/16 05:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -109,7 +109,6 @@ static ScanKeyword ScanKeywords[] = {
{"execute", EXECUTE},
{"exists", EXISTS},
{"explain", EXPLAIN},
{"extend", EXTEND},
{"extract", EXTRACT},
{"false", FALSE_P},
{"fetch", FETCH},

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.114 2001/06/18 16:13:21 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.115 2001/07/16 05:06:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -567,18 +567,6 @@ ProcessUtility(Node *parsetree,
DefineSequence((CreateSeqStmt *) parsetree);
break;
case T_ExtendStmt:
{
ExtendStmt *stmt = (ExtendStmt *) parsetree;
set_ps_display(commandTag = "EXTEND");
ExtendIndex(stmt->idxname, /* index name */
(Expr *) stmt->whereClause, /* where */
stmt->rangetable);
}
break;
case T_RemoveAggrStmt:
{
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;

View File

@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.79 2001/07/10 00:02:02 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.80 2001/07/16 05:06:59 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -40,6 +40,7 @@
#include <unistd.h>
#include <fcntl.h>
#include "catalog/heap.h"
#include "catalog/pg_index.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h"
@@ -554,6 +555,64 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
}
/* ----------
* get_expr - Decompile an expression tree
*
* Input: an expression tree in nodeToString form, and a relation OID
*
* Output: reverse-listed expression
*
* Currently, the expression can only refer to a single relation, namely
* the one specified by the second parameter. This is sufficient for
* partial indexes, column default expressions, etc.
* ----------
*/
Datum
pg_get_expr(PG_FUNCTION_ARGS)
{
text *expr = PG_GETARG_TEXT_P(0);
Oid relid = PG_GETARG_OID(1);
text *result;
Node *node;
List *context;
char *exprstr;
char *relname;
char *str;
/* Get the name for the relation */
relname = get_rel_name(relid);
if (relname == NULL)
PG_RETURN_NULL(); /* should we raise an error? */
/* Convert input TEXT object to C string */
exprstr = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(expr)));
/* Convert expression to node tree */
node = (Node *) stringToNode(exprstr);
/*
* If top level is a List, assume it is an implicit-AND structure,
* and convert to explicit AND. This is needed for partial index
* predicates.
*/
if (node && IsA(node, List))
{
node = (Node *) make_ands_explicit((List *) node);
}
/* Deparse */
context = deparse_context_for(relname, relid);
str = deparse_expression(node, context, false);
/* Pass the result back as TEXT */
result = DatumGetTextP(DirectFunctionCall1(textin,
CStringGetDatum(str)));
PG_RETURN_TEXT_P(result);
}
/* ----------
* get_userbyid - Get a user name by usesysid and
* fallback to 'unknown (UID=n)'

View File

@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.94 2001/06/25 21:11:44 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.95 2001/07/16 05:06:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -86,6 +86,7 @@
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
#include "optimizer/prep.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parsetree.h"
@@ -2950,24 +2951,63 @@ genericcostestimate(Query *root, RelOptInfo *rel,
{
double numIndexTuples;
double numIndexPages;
/* Estimate the fraction of main-table tuples that will be visited */
*indexSelectivity = clauselist_selectivity(root, indexQuals,
lfirsti(rel->relids));
/* Estimate the number of index tuples that will be visited */
numIndexTuples = *indexSelectivity * index->tuples;
/* Estimate the number of index pages that will be retrieved */
numIndexPages = *indexSelectivity * index->pages;
List *selectivityQuals = indexQuals;
/*
* Always estimate at least one tuple and page are touched, even when
* If the index is partial, AND the index predicate with the explicitly
* given indexquals to produce a more accurate idea of the index
* restriction. This may produce redundant clauses, which we hope that
* cnfify and clauselist_selectivity will deal with intelligently.
*
* Note that index->indpred and indexQuals are both in implicit-AND
* form to start with, which we have to make explicit to hand to
* canonicalize_qual, and then we get back implicit-AND form again.
*/
if (index->indpred != NIL)
{
Expr *andedQuals;
andedQuals = make_ands_explicit(nconc(listCopy(index->indpred),
indexQuals));
selectivityQuals = canonicalize_qual(andedQuals, true);
}
/* Estimate the fraction of main-table tuples that will be visited */
*indexSelectivity = clauselist_selectivity(root, selectivityQuals,
lfirsti(rel->relids));
/*
* Estimate the number of tuples that will be visited. We do it in
* this rather peculiar-looking way in order to get the right answer
* for partial indexes. We can bound the number of tuples by the
* index size, in any case.
*/
numIndexTuples = *indexSelectivity * rel->tuples;
if (numIndexTuples > index->tuples)
numIndexTuples = index->tuples;
/*
* Always estimate at least one tuple is touched, even when
* indexSelectivity estimate is tiny.
*/
if (numIndexTuples < 1.0)
numIndexTuples = 1.0;
if (numIndexPages < 1.0)
/*
* Estimate the number of index pages that will be retrieved.
*
* For all currently-supported index types, the first page of the index
* is a metadata page, and we should figure on fetching that plus a
* pro-rated fraction of the remaining pages.
*/
if (index->pages > 1 && index->tuples > 0)
{
numIndexPages = (numIndexTuples / index->tuples) * (index->pages - 1);
numIndexPages += 1; /* count the metapage too */
numIndexPages = ceil(numIndexPages);
}
else
numIndexPages = 1.0;
/*