diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/bootstrap/bootstrap.c | 7 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 97 | ||||
-rw-r--r-- | src/backend/commands/command.c | 4 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 169 | ||||
-rw-r--r-- | src/backend/executor/execUtils.c | 8 | ||||
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 67 | ||||
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 9 | ||||
-rw-r--r-- | src/backend/parser/analyze.c | 48 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 34 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 3 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 14 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 61 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 60 |
13 files changed, 220 insertions, 361 deletions
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index ee1a4b7c31f..7fc54779680 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -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; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index f0fa73e83dd..b48a13f9e17 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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, @@ -587,87 +587,6 @@ UpdateIndexRelation(Oid indexoid, } /* ---------------------------------------------------------------- - * 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 * * XXX this is essentially the same as relcache.c's @@ -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); diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 4fcbeeceb6c..744129f726f 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -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; diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 7398b0b0ce5..6a85324bdc0 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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; @@ -219,154 +213,29 @@ 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"); } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 9465604b584..2c76c9b7d98 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -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; } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 477fa6ed5ca..bdff8fe7e73 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -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); } diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 7f1f3b402a4..1377fc06a49 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -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; diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 9d6dfeb69a7..186fa124507 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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,43 +1625,34 @@ 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); - - qry->hasSubLinks = pstate->p_hasSubLinks; - - stmt->rangetable = pstate->p_rtable; - - qry->utilityStmt = (Node *) stmt; - - return qry; -} - -/* - * transformExtendStmt - - * transform the qualifications of the Extend Index Statement - * - */ -static Query * -transformExtendStmt(ParseState *pstate, ExtendStmt *stmt) -{ - Query *qry; + 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); - qry = makeNode(Query); - qry->commandType = CMD_UTILITY; + /* no to join list, yes to namespace */ + addRTEtoQuery(pstate, rte, false, true); - /* take care of the where clause */ - stmt->whereClause = transformWhereClause(pstate, stmt->whereClause); + stmt->whereClause = transformWhereClause(pstate, stmt->whereClause); + } qry->hasSubLinks = pstate->p_hasSubLinks; - stmt->rangetable = pstate->p_rtable; qry->utilityStmt = (Node *) stmt; + return qry; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index b83ca3783fd..99312049a83 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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; } ; @@ -2474,22 +2473,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: * execute recipe <recipeName> * *****************************************************************************/ @@ -5775,7 +5758,6 @@ ColLabel: ColId { $$ = $1; } | EXCEPT { $$ = "except"; } | EXISTS { $$ = "exists"; } | EXPLAIN { $$ = "explain"; } - | EXTEND { $$ = "extend"; } | EXTRACT { $$ = "extract"; } | FALSE_P { $$ = "false"; } | FLOAT { $$ = "float"; } diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index ccdfb88a2e2..014b1198503 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -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}, diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 5be50e7aade..a791a67715e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -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; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 5f7cfead6c1..afc2b63430b 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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" @@ -555,6 +556,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)' * ---------- diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 3ab3881c257..e0cfeefaee4 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -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; + List *selectivityQuals = indexQuals; - /* Estimate the fraction of main-table tuples that will be visited */ - *indexSelectivity = clauselist_selectivity(root, indexQuals, - lfirsti(rel->relids)); + /* + * 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; - /* Estimate the number of index tuples that will be visited */ - numIndexTuples = *indexSelectivity * index->tuples; + andedQuals = make_ands_explicit(nconc(listCopy(index->indpred), + indexQuals)); + selectivityQuals = canonicalize_qual(andedQuals, true); + } - /* Estimate the number of index pages that will be retrieved */ - numIndexPages = *indexSelectivity * index->pages; + /* Estimate the fraction of main-table tuples that will be visited */ + *indexSelectivity = clauselist_selectivity(root, selectivityQuals, + lfirsti(rel->relids)); /* - * Always estimate at least one tuple and page are touched, even when + * 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; /* |