diff --git a/doc/src/sgml/indices.sgml b/doc/src/sgml/indices.sgml index abda7fd77f..d81ce77517 100644 --- a/doc/src/sgml/indices.sgml +++ b/doc/src/sgml/indices.sgml @@ -1,4 +1,4 @@ - + Indexes @@ -603,22 +603,11 @@ CREATE MEMSTORE ON table COLUMNS cols - - Note - - Partial indexes are not currently supported by - PostgreSQL, but they were once supported - by its predecessor Postgres, and much - of the code is still there. We hope to revive support for this - feature someday. - - - A partial index is an index built over a subset of a table; the subset is defined by a predicate. Postgres - supported partial indexes with arbitrary + supports partial indexes with arbitrary predicates. I believe IBM's DB2 for AS/400 supports partial indexes using single-clause predicates. diff --git a/doc/src/sgml/ref/create_index.sgml b/doc/src/sgml/ref/create_index.sgml index bc72fb1993..e5194c255c 100644 --- a/doc/src/sgml/ref/create_index.sgml +++ b/doc/src/sgml/ref/create_index.sgml @@ -1,5 +1,5 @@ @@ -20,13 +20,15 @@ Postgres documentation - 1999-07-20 + 2001-07-15 CREATE [ UNIQUE ] INDEX index_name ON table - [ USING acc_name ] ( column [ ops_name ] [, ...] ) + [ USING acc_method ] ( column [ ops_name ] [, ...] ) + [ WHERE predicate ] CREATE [ UNIQUE ] INDEX index_name ON table - [ USING acc_name ] ( func_name( column [, ... ]) [ ops_name ] ) + [ USING acc_method ] ( func_name( column [, ... ]) [ ops_name ] ) + [ WHERE predicate ] @@ -71,12 +73,12 @@ CREATE [ UNIQUE ] INDEX index_name - acc_name + acc_method The name of the access method to be used for the index. The default access method is BTREE. - Postgres provides three access methods for indexes: + Postgres provides four access methods for indexes: @@ -106,6 +108,15 @@ CREATE [ UNIQUE ] INDEX index_name + + + GIST + + + Generalized Index Search Trees. + + + @@ -137,6 +148,15 @@ CREATE [ UNIQUE ] INDEX index_name + + + predicate + + + Defines the constraint expression for a partial index. + + + @@ -216,7 +236,7 @@ ERROR: Cannot create index: 'index_name' already exists. - Postgres provides btree, rtree and hash access methods for + Postgres provides btree, rtree, hash, and GiST access methods for indexes. The btree access method is an implementation of Lehman-Yao high-concurrency btrees. The rtree access method implements standard rtrees using Guttman's quadratic split algorithm. @@ -227,6 +247,32 @@ ERROR: Cannot create index: 'index_name' already exists. access methods). + + When the WHERE clause is present, a + partial index is created. + A partial index is an index that contains entries for only a portion of + a table, usually a portion that is somehow more interesting than the + rest of the table. For example, if you have a table that contains both + billed and unbilled orders where the unbilled orders take up a small + fraction of the total table and yet that is an often used section, you + can improve performance by creating an index on just that portion. + + + + The expression used in the WHERE clause may refer + only to columns of the underlying table (but it can use all columns, + not only the one(s) being indexed). Currently, the + PostgreSQL planner can only devise query + plans that make use of a partial index when the predicate is built from + AND and OR combinations of + elements of the form + column + operator + constant. + However, more general predicates may still be useful in conjunction + with UNIQUE indexes, to enforce uniqueness over a subset of a table. + + Use to remove an index. @@ -278,9 +324,10 @@ ERROR: Cannot create index: 'index_name' already exists. - Currently, only the btree access method supports multi-column + Currently, only the btree and gist access methods support multi-column indexes. Up to 16 keys may be specified by default (this limit - can be altered when building Postgres). + can be altered when building Postgres). Only btree currently supports + unique indexes. @@ -307,9 +354,9 @@ ERROR: Cannot create index: 'index_name' already exists. The difference between them is that bigbox_ops scales box coordinates down, to avoid floating-point exceptions from doing multiplication, addition, and subtraction on very large - floating-point coordinates. If the field on which your rectangles lie - is about 20,000 units square or larger, you should use - bigbox_ops. + floating-point coordinates. (Note: this was true some time ago, + but currently the two operator classes both use floating point + and are effectively identical.) @@ -319,7 +366,7 @@ ERROR: Cannot create index: 'index_name' already exists. The following query shows all defined operator classes: -SELECT am.amname AS acc_name, +SELECT am.amname AS acc_method, opc.opcname AS ops_name, opr.oprname AS ops_comp FROM pg_am am, pg_amop amop, @@ -327,7 +374,7 @@ SELECT am.amname AS acc_name, WHERE amop.amopid = am.oid AND amop.amopclaid = opc.oid AND amop.amopopr = opr.oid - ORDER BY acc_name, ops_name, ops_comp + ORDER BY acc_method, ops_name, ops_comp diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index ee1a4b7c31..7fc5477968 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 f0fa73e83d..b48a13f9e1 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, @@ -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); diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 4fcbeeceb6..744129f726 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 7398b0b0ce..6a85324bdc 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; @@ -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"); } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 9465604b58..2c76c9b7d9 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 477fa6ed5c..bdff8fe7e7 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 7f1f3b402a..1377fc06a4 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 9d6dfeb69a..186fa12450 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,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 diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index b83ca3783f..99312049a8 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 on - * using "(" ( with )+ ")" [with - * ] + * [ using ] "(" ( with )+ ")" + * [ with ] + * [ where ] * - * [where ] 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 [where ] - * - *****************************************************************************/ - -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"; } diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index ccdfb88a2e..014b119850 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 5be50e7aad..a791a67715 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 5f7cfead6c..afc2b63430 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 #include +#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)' diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 3ab3881c25..e0cfeefaee 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; - - /* 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; /* diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index a73bb7b5c8..531fd9e497 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.213 2001/07/03 20:21:49 petere Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.214 2001/07/16 05:06:59 tgl Exp $ * * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb * @@ -1758,6 +1758,8 @@ clearIndInfo(IndInfo *ind, int numIndexes) free(ind[i].indisunique); if (ind[i].indisprimary) free(ind[i].indisprimary); + if (ind[i].indpred) + free(ind[i].indpred); for (a = 0; a < INDEX_MAX_KEYS; ++a) { if (ind[i].indkey[a]) @@ -2887,10 +2889,10 @@ getIndexes(int *numIndexes) int i_indoid; int i_oid; int i_indisprimary; + int i_indpred; /* - * find all the user-defined indexes. We do not handle partial - * indexes. + * find all the user-defined indexes. * * Notice we skip indexes on system classes * @@ -2902,7 +2904,7 @@ getIndexes(int *numIndexes) appendPQExpBuffer(query, "SELECT i.oid, t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, " "i.indproc, i.indkey, i.indclass, " - "a.amname as indamname, i.indisunique, i.indisprimary " + "a.amname as indamname, i.indisunique, i.indisprimary, i.indpred " "from pg_index i, pg_class t1, pg_class t2, pg_am a " "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid " "and t1.relam = a.oid and i.indexrelid > '%u'::oid " @@ -2938,6 +2940,7 @@ getIndexes(int *numIndexes) i_indclass = PQfnumber(res, "indclass"); i_indisunique = PQfnumber(res, "indisunique"); i_indisprimary = PQfnumber(res, "indisprimary"); + i_indpred = PQfnumber(res, "indpred"); for (i = 0; i < ntups; i++) { @@ -2955,6 +2958,7 @@ getIndexes(int *numIndexes) INDEX_MAX_KEYS); indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique)); indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary)); + indinfo[i].indpred = strdup(PQgetvalue(res, i, i_indpred)); } PQclear(res); return indinfo; @@ -4435,13 +4439,46 @@ dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes, { /* need 2 printf's here cuz fmtId has static return area */ appendPQExpBuffer(q, " %s", fmtId(funcname, false)); - appendPQExpBuffer(q, " (%s) %s );\n", attlist->data, + appendPQExpBuffer(q, " (%s) %s )", attlist->data, fmtId(classname[0], force_quotes)); free(funcname); free(classname[0]); } else - appendPQExpBuffer(q, " %s );\n", attlist->data); + appendPQExpBuffer(q, " %s )", attlist->data); + + if (*indinfo[i].indpred) /* If there is an index predicate */ + { + int numRows; + PQExpBuffer pred = createPQExpBuffer(); + + appendPQExpBuffer(pred, "SELECT pg_get_expr(indpred,indrelid) as pred FROM pg_index WHERE oid = %s", + indinfo[i].oid); + res = PQexec(g_conn, pred->data); + if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) + { + fprintf(stderr, "dumpIndices(): SELECT (indpred) failed. " + "Explanation from backend: '%s'.\n", + PQerrorMessage(g_conn)); + exit_nicely(); + } + + /* Sanity: Check we got only one tuple */ + numRows = PQntuples(res); + if (numRows != 1) + { + fprintf(stderr, "dumpIndices(): SELECT (indpred) for index %s returned %d tuples. Expected 1.\n", + indinfo[i].indrelname, numRows); + exit_nicely(); + } + + appendPQExpBuffer(q, " WHERE %s", + PQgetvalue(res, 0, PQfnumber(res, "pred"))); + + PQclear(res); + destroyPQExpBuffer( pred ); + } + appendPQExpBuffer(q, ";\n"); /* * We make the index belong to the owner of its table, which diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index a1a3bebd39..503d10f63d 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_dump.h,v 1.65 2001/07/03 20:21:50 petere Exp $ + * $Id: pg_dump.h,v 1.66 2001/07/16 05:06:59 tgl Exp $ * * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2 * @@ -147,6 +147,7 @@ typedef struct _indInfo char *indclass[INDEX_MAX_KEYS]; /* opclass of the keys */ char *indisunique; /* is this index unique? */ char *indisprimary; /* is this a PK index? */ + char *indpred; /* index predicate */ } IndInfo; typedef struct _aggInfo diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index f93de9c2e9..0937cf9d92 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: index.h,v 1.36 2001/07/15 22:48:18 tgl Exp $ + * $Id: index.h,v 1.37 2001/07/16 05:06:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,8 +30,6 @@ typedef void (*IndexBuildCallback) (Relation index, extern Form_pg_am AccessMethodObjectIdGetForm(Oid accessMethodObjectId, MemoryContext resultCxt); -extern void UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate); - extern void InitIndexStrategy(int numatts, Relation indexRelation, Oid accessMethodObjectId); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index f249fcf2d9..4acbe30e8e 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_proc.h,v 1.197 2001/07/15 22:48:18 tgl Exp $ + * $Id: pg_proc.h,v 1.198 2001/07/16 05:06:59 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2146,6 +2146,9 @@ DATA(insert OID = 1642 ( pg_get_userbyid PGUID 12 f t f t 1 f 19 "23" 100 0 DESCR("user name by UID (with fallback)"); DATA(insert OID = 1643 ( pg_get_indexdef PGUID 12 f t f t 1 f 25 "26" 100 0 0 100 pg_get_indexdef - )); DESCR("index description"); +DATA(insert OID = 1716 ( pg_get_expr PGUID 12 f t f t 2 f 25 "25 26" 100 0 0 100 pg_get_expr - )); +DESCR("deparse an encoded expression"); + /* Generic referential integrity constraint triggers */ DATA(insert OID = 1644 ( RI_FKey_check_ins PGUID 12 f t f t 0 f 0 "" 100 0 0 100 RI_FKey_check_ins - )); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 98ba76613a..47230e9144 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: defrem.h,v 1.22 2001/01/24 19:43:23 momjian Exp $ + * $Id: defrem.h,v 1.23 2001/07/16 05:07:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ #include "tcop/dest.h" /* - * prototypes in defind.c + * prototypes in indexcmds.c */ extern void DefineIndex(char *heapRelationName, char *indexRelationName, @@ -29,9 +29,6 @@ extern void DefineIndex(char *heapRelationName, bool primary, Expr *predicate, List *rangetable); -extern void ExtendIndex(char *indexRelationName, - Expr *predicate, - List *rangetable); extern void RemoveIndex(char *name); extern void ReindexIndex(const char *indexRelationName, bool force); extern void ReindexTable(const char *relationName, bool force); diff --git a/src/include/config.h.in b/src/include/config.h.in index 941cfe8a06..70e9d6aa92 100644 --- a/src/include/config.h.in +++ b/src/include/config.h.in @@ -8,7 +8,7 @@ * or in config.h afterwards. Of course, if you edit config.h, then your * changes will be overwritten the next time you run configure. * - * $Id: config.h.in,v 1.167 2001/07/11 19:03:07 tgl Exp $ + * $Id: config.h.in,v 1.168 2001/07/16 05:07:00 tgl Exp $ */ #ifndef CONFIG_H @@ -310,7 +310,6 @@ /* #define ACLDEBUG */ /* #define RTDEBUG */ /* #define GISTDEBUG */ -/* #define OMIT_PARTIAL_INDEX */ /* * defining unsafe floats will make float4 and float8 ops faster diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 1dc68c192f..4e1bc683d5 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execnodes.h,v 1.61 2001/06/01 02:41:36 tgl Exp $ + * $Id: execnodes.h,v 1.62 2001/07/16 05:07:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,7 +34,7 @@ * 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 + * Predicate partial-index predicate, or NIL 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? @@ -46,7 +46,7 @@ typedef struct IndexInfo int ii_NumIndexAttrs; int ii_NumKeyAttrs; AttrNumber ii_KeyAttrNumbers[INDEX_MAX_KEYS]; - Node *ii_Predicate; + List *ii_Predicate; Oid ii_FuncOid; FmgrInfo ii_FuncInfo; bool ii_Unique; diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index efb5c3dcb2..150acabc0a 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: builtins.h,v 1.157 2001/07/11 22:14:03 momjian Exp $ + * $Id: builtins.h,v 1.158 2001/07/16 05:07:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -337,6 +337,7 @@ extern Datum pg_get_ruledef(PG_FUNCTION_ARGS); extern Datum pg_get_viewdef(PG_FUNCTION_ARGS); extern Datum pg_get_indexdef(PG_FUNCTION_ARGS); extern Datum pg_get_userbyid(PG_FUNCTION_ARGS); +extern Datum pg_get_expr(PG_FUNCTION_ARGS); extern char *deparse_expression(Node *expr, List *dpcontext, bool forceprefix); extern List *deparse_context_for(char *relname, Oid relid); diff --git a/src/interfaces/ecpg/preproc/keywords.c b/src/interfaces/ecpg/preproc/keywords.c index d7ee1d3455..5792017871 100644 --- a/src/interfaces/ecpg/preproc/keywords.c +++ b/src/interfaces/ecpg/preproc/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.41 2001/06/01 06:23:19 meskes Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/keywords.c,v 1.42 2001/07/16 05:07:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -109,7 +109,6 @@ static ScanKeyword ScanKeywords[] = { {"execute", EXECUTE}, {"exists", EXISTS}, {"explain", EXPLAIN}, - {"extend", EXTEND}, {"extract", EXTRACT}, {"false", FALSE_P}, {"fetch", FETCH}, @@ -265,6 +264,7 @@ static ScanKeyword ScanKeywords[] = { {"type", TYPE_P}, {"union", UNION}, {"unique", UNIQUE}, + {"unknown", UNKNOWN}, {"unlisten", UNLISTEN}, {"until", UNTIL}, {"update", UPDATE}, diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y index 902b177412..88330ad3c1 100644 --- a/src/interfaces/ecpg/preproc/preproc.y +++ b/src/interfaces/ecpg/preproc/preproc.y @@ -193,7 +193,7 @@ make_name(void) SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING, TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR, TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P, - UNION, UNIQUE, UPDATE, USER, USING, + UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING, VALUES, VARCHAR, VARYING, VIEW, WHEN, WHERE, WITH, WITHOUT, WORK, YEAR_P, ZONE @@ -217,7 +217,7 @@ make_name(void) BACKWARD, BEFORE, BINARY, BIT, CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE, DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN, - EXTEND, FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT, + FORCE, FORWARD, FUNCTION, HANDLER, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, LANCOMPILER, LIMIT, LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, @@ -260,7 +260,7 @@ make_name(void) %left Op /* multi-character ops and user-defined operators */ %nonassoc NOTNULL %nonassoc ISNULL -%nonassoc IS NULL_P TRUE_P FALSE_P +%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN %left '+' '-' %left '*' '/' '%' %left '^' @@ -312,7 +312,7 @@ make_name(void) %type RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type %type RuleStmt opt_column opt_name oper_argtypes %type MathOp RemoveFuncStmt aggr_argtype for_update_clause -%type RemoveAggrStmt ExtendStmt opt_procedural select_no_parens +%type RemoveAggrStmt opt_procedural select_no_parens %type RemoveOperStmt RenameStmt all_Op %type VariableSetStmt var_value zone_value VariableShowStmt %type VariableResetStmt AlterTableStmt DropUserStmt from_list @@ -414,7 +414,6 @@ stmt: AlterSchemaStmt { output_statement($1, 0, NULL, connection); } | DropPLangStmt { output_statement($1, 0, NULL, connection); } | DropTrigStmt { output_statement($1, 0, NULL, connection); } | DropUserStmt { output_statement($1, 0, NULL, connection); } - | ExtendStmt { output_statement($1, 0, NULL, connection); } | ExplainStmt { output_statement($1, 0, NULL, connection); } | FetchStmt { output_statement($1, 1, NULL, connection); } | GrantStmt { output_statement($1, 0, NULL, connection); } @@ -1801,18 +1800,16 @@ RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list * * QUERY: * create index on - * using "(" ( with )+ ")" [with - * ] + * [ using ] "(" ( with )+ ")" + * [ with ] + * [ where ] * - * [where ] 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 { - /* should check that access_method is valid, - etc ... but doesn't */ - $$ = cat_str(11, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11); + $$ = cat_str(12, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11, $12); } ; @@ -1866,19 +1863,6 @@ opt_class: class { | /*EMPTY*/ { $$ = EMPTY; } ; -/***************************************************************************** - * - * QUERY: - * extend index [where ] - * - *****************************************************************************/ - -ExtendStmt: EXTEND INDEX index_name where_clause - { - $$ = cat_str(3, make_str("extend index"), $3, $4); - } - ; - /***************************************************************************** * @@ -3324,15 +3308,23 @@ a_expr: c_expr * but let's make them expressions to allow the optimizer * a chance to eliminate them if a_expr is a constant string. * - thomas 1997-12-22 + * + * Created BooleanTest Node type, and changed handling + * for NULL inputs + * - jec 2001-06-18 */ | a_expr IS TRUE_P { $$ = cat2_str($1, make_str("is true")); } - | a_expr IS NOT FALSE_P - { $$ = cat2_str($1, make_str("is not false")); } - | a_expr IS FALSE_P - { $$ = cat2_str($1, make_str("is false")); } | a_expr IS NOT TRUE_P { $$ = cat2_str($1, make_str("is not true")); } + | a_expr IS FALSE_P + { $$ = cat2_str($1, make_str("is false")); } + | a_expr IS NOT FALSE_P + { $$ = cat2_str($1, make_str("is not false")); } + | a_expr IS UNKNOWN + { $$ = cat2_str($1, make_str("is unknown")); } + | a_expr IS NOT UNKNOWN + { $$ = cat2_str($1, make_str("is not unknown")); } | a_expr BETWEEN b_expr AND b_expr %prec BETWEEN { $$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5); @@ -5152,7 +5144,6 @@ ECPGColLabel: ECPGColId { $$ = $1; } | EXCEPT { $$ = make_str("except"); } | EXISTS { $$ = make_str("exists"); } | EXPLAIN { $$ = make_str("explain"); } - | EXTEND { $$ = make_str("extend"); } | EXTRACT { $$ = make_str("extract"); } | FALSE_P { $$ = make_str("false"); } | FOR { $$ = make_str("for"); } @@ -5217,6 +5208,7 @@ ECPGColLabel: ECPGColId { $$ = $1; } | TRIM { $$ = make_str("trim"); } | TRUE_P { $$ = make_str("true"); } | UNIQUE { $$ = make_str("unique"); } + | UNKNOWN { $$ = make_str("unknown"); } | USER { $$ = make_str("user"); } | USING { $$ = make_str("using"); } | VACUUM { $$ = make_str("vacuum"); } diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 3e72751774..06eeeecdd4 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -32,16 +32,13 @@ CREATE INDEX bt_txt_index ON bt_txt_heap USING btree (seqno text_ops); CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops); -- -- BTREE partial indices --- partial indices are not supported in PostgreSQL -- ---CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) --- where onek2.unique1 < 20 or onek2.unique1 > 980; ---CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) --- where onek2.stringu1 < 'B'; --- EXTEND INDEX onek2_u2_prtl where onek2.stringu1 < 'C'; --- EXTEND INDEX onek2_u2_prtl; --- CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops) --- where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K'; +CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) + where unique1 < 20 or unique1 > 980; +CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) + where stringu1 < 'B'; +CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops) + where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K'; -- -- RTREE -- diff --git a/src/test/regress/expected/portals_p2.out b/src/test/regress/expected/portals_p2.out index 558397f5c9..7a9cf69674 100644 --- a/src/test/regress/expected/portals_p2.out +++ b/src/test/regress/expected/portals_p2.out @@ -1,7 +1,6 @@ -- -- PORTALS_P2 -- --- EXTEND INDEX onek2_u1_prtl WHERE onek2.unique1 <= 60; BEGIN; DECLARE foo13 CURSOR FOR SELECT * FROM onek WHERE unique1 = 50; diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index 5f5911c09c..ac0e344c74 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -29,6 +29,7 @@ SELECT relname, relhasindex num_exp_sqrt | t num_exp_sub | t onek | t + onek2 | t pg_aggregate | t pg_am | t pg_amop | t @@ -57,5 +58,5 @@ SELECT relname, relhasindex shighway | t tenk1 | t tenk2 | t -(47 rows) +(48 rows) diff --git a/src/test/regress/expected/select.out b/src/test/regress/expected/select.out index ed6cbac1df..7974d141c5 100644 --- a/src/test/regress/expected/select.out +++ b/src/test/regress/expected/select.out @@ -205,24 +205,88 @@ SELECT onek.unique1, onek.string4 (20 rows) -- --- partial btree index +-- test partial btree indexes +-- +-- As of 7.2, planner probably won't pick an indexscan without stats, +-- so ANALYZE first. +-- +ANALYZE onek2; +-- -- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 -- ---SELECT onek2.* WHERE onek2.unique1 < 10; +SELECT onek2.* WHERE onek2.unique1 < 10; + unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 +---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- + 0 | 998 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | AAAAAA | KMBAAA | OOOOxx + 1 | 214 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 3 | BAAAAA | GIAAAA | OOOOxx + 2 | 326 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | OMAAAA | OOOOxx + 3 | 431 | 1 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 6 | 7 | DAAAAA | PQAAAA | VVVVxx + 4 | 833 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 8 | 9 | EAAAAA | BGBAAA | HHHHxx + 5 | 541 | 1 | 1 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 10 | 11 | FAAAAA | VUAAAA | HHHHxx + 6 | 978 | 0 | 2 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 12 | 13 | GAAAAA | QLBAAA | OOOOxx + 7 | 647 | 1 | 3 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 14 | 15 | HAAAAA | XYAAAA | VVVVxx + 8 | 653 | 0 | 0 | 8 | 8 | 8 | 8 | 8 | 8 | 8 | 16 | 17 | IAAAAA | DZAAAA | HHHHxx + 9 | 49 | 1 | 1 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 18 | 19 | JAAAAA | XBAAAA | HHHHxx +(10 rows) + -- --- partial btree index -- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 -- ---SELECT onek2.unique1, onek2.stringu1 --- WHERE onek2.unique1 < 20 --- ORDER BY unique1 using >; +SELECT onek2.unique1, onek2.stringu1 + WHERE onek2.unique1 < 20 + ORDER BY unique1 using >; + unique1 | stringu1 +---------+---------- + 19 | TAAAAA + 18 | SAAAAA + 17 | RAAAAA + 16 | QAAAAA + 15 | PAAAAA + 14 | OAAAAA + 13 | NAAAAA + 12 | MAAAAA + 11 | LAAAAA + 10 | KAAAAA + 9 | JAAAAA + 8 | IAAAAA + 7 | HAAAAA + 6 | GAAAAA + 5 | FAAAAA + 4 | EAAAAA + 3 | DAAAAA + 2 | CAAAAA + 1 | BAAAAA + 0 | AAAAAA +(20 rows) + -- -- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 -- ---SELECT onek2.unique1, onek2.stringu1 --- WHERE onek2.unique1 > 980 --- ORDER BY stringu1 using <; - +SELECT onek2.unique1, onek2.stringu1 + WHERE onek2.unique1 > 980; + unique1 | stringu1 +---------+---------- + 981 | TLAAAA + 982 | ULAAAA + 983 | VLAAAA + 984 | WLAAAA + 985 | XLAAAA + 986 | YLAAAA + 987 | ZLAAAA + 988 | AMAAAA + 989 | BMAAAA + 990 | CMAAAA + 991 | DMAAAA + 992 | EMAAAA + 993 | FMAAAA + 994 | GMAAAA + 995 | HMAAAA + 996 | IMAAAA + 997 | JMAAAA + 998 | KMAAAA + 999 | LMAAAA +(19 rows) + SELECT two, stringu1, ten, string4 INTO TABLE tmp FROM onek; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index 2ebc7ef3c3..888edafe75 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -50,20 +50,15 @@ CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops); -- -- BTREE partial indices --- partial indices are not supported in PostgreSQL -- ---CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) --- where onek2.unique1 < 20 or onek2.unique1 > 980; +CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops) + where unique1 < 20 or unique1 > 980; ---CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) --- where onek2.stringu1 < 'B'; +CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops) + where stringu1 < 'B'; --- EXTEND INDEX onek2_u2_prtl where onek2.stringu1 < 'C'; - --- EXTEND INDEX onek2_u2_prtl; - --- CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops) --- where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K'; +CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops) + where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K'; -- -- RTREE diff --git a/src/test/regress/sql/portals_p2.sql b/src/test/regress/sql/portals_p2.sql index c1c92e1cf2..12bd903e5f 100644 --- a/src/test/regress/sql/portals_p2.sql +++ b/src/test/regress/sql/portals_p2.sql @@ -2,8 +2,6 @@ -- PORTALS_P2 -- --- EXTEND INDEX onek2_u1_prtl WHERE onek2.unique1 <= 60; - BEGIN; DECLARE foo13 CURSOR FOR diff --git a/src/test/regress/sql/select.sql b/src/test/regress/sql/select.sql index 42b664eaae..ee9389dc59 100644 --- a/src/test/regress/sql/select.sql +++ b/src/test/regress/sql/select.sql @@ -55,26 +55,32 @@ SELECT onek.unique1, onek.string4 ORDER BY unique1 using <, string4 using >; -- --- partial btree index --- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 +-- test partial btree indexes -- ---SELECT onek2.* WHERE onek2.unique1 < 10; +-- As of 7.2, planner probably won't pick an indexscan without stats, +-- so ANALYZE first. +-- +ANALYZE onek2; + +-- +-- awk '{if($1<10){print $0;}else{next;}}' onek.data | sort +0n -1 +-- +SELECT onek2.* WHERE onek2.unique1 < 10; -- --- partial btree index -- awk '{if($1<20){print $1,$14;}else{next;}}' onek.data | sort +0nr -1 -- ---SELECT onek2.unique1, onek2.stringu1 --- WHERE onek2.unique1 < 20 --- ORDER BY unique1 using >; +SELECT onek2.unique1, onek2.stringu1 + WHERE onek2.unique1 < 20 + ORDER BY unique1 using >; -- -- awk '{if($1>980){print $1,$14;}else{next;}}' onek.data | sort +1d -2 -- ---SELECT onek2.unique1, onek2.stringu1 --- WHERE onek2.unique1 > 980 --- ORDER BY stringu1 using <; - +SELECT onek2.unique1, onek2.stringu1 + WHERE onek2.unique1 > 980; + + SELECT two, stringu1, ten, string4 INTO TABLE tmp FROM onek;