Index: doc/TODO
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/TODO,v
retrieving revision 1.511
diff -u -r1.511 TODO
--- doc/TODO 2001/07/10 21:36:09 1.511
+++ doc/TODO 2001/07/11 15:01:27
@@ -100,7 +100,7 @@
* Allow CREATE INDEX zman_index ON test (date_trunc( 'day', zman ) datetime_ops)
fails index can't store constant parameters
* Add FILLFACTOR to index creation
-* Re-enable partial indexes
+* -Re-enable partial indexes
* Allow inherited tables to inherit index, UNIQUE constraint, and primary
key, foreign key [inheritance]
* UNIQUE INDEX on base column not honored on inserts from inherited table
Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.18
diff -u -r2.18 catalogs.sgml
--- doc/src/sgml/catalogs.sgml 2001/06/12 05:55:48 2.18
+++ doc/src/sgml/catalogs.sgml 2001/07/11 15:01:27
@@ -1045,7 +1045,7 @@
indpred
text
- Query plan for partial index predicate (not functional)
+ Query plan for partial index predicate
Index: doc/src/sgml/indices.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/indices.sgml,v
retrieving revision 1.19
diff -u -r1.19 indices.sgml
--- doc/src/sgml/indices.sgml 2001/05/30 04:01:11 1.19
+++ doc/src/sgml/indices.sgml 2001/07/11 15:01:28
@@ -606,11 +606,12 @@
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.
+ For a long time partial indices were not supported by
+ PostgreSQL, but they were once supported by
+ its predecessor Postgres, and much of the
+ code was still there. Currently (July 2001) there is some work underway
+ to revive this feature. See the pgsql-general mailing list archives for
+ details.
Index: doc/src/sgml/ref/create_index.sgml
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/doc/src/sgml/ref/create_index.sgml,v
retrieving revision 1.19
diff -u -r1.19 create_index.sgml
--- doc/src/sgml/ref/create_index.sgml 2001/05/17 21:50:18 1.19
+++ doc/src/sgml/ref/create_index.sgml 2001/07/11 15:01:28
@@ -25,8 +25,10 @@
CREATE [ UNIQUE ] INDEX index_name ON table
[ USING acc_name ] ( column [ ops_name ] [, ...] )
+ [ WHERE expr ]
CREATE [ UNIQUE ] INDEX index_name ON table
[ USING acc_name ] ( func_name( column [, ... ]) [ ops_name ] )
+ [ WHERE expr ]
@@ -137,6 +139,15 @@
+
+
+ expr
+
+
+ Defines the expression for a partial index.
+
+
+
@@ -225,6 +236,23 @@
of these access methods are fully dynamic and do not have to be
optimized periodically (as is the case with, for example, static hash
access methods).
+
+
+
+ When the WHERE clause is present, this defines a
+ partial index. A partial index is an index that only covers 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 order 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 is restricted
+ to forms the planner can easily use. Each element can only consist of
+ ATTR OP CONST and these can only be joined by
+ AND and OR operators.
Index: src/backend/access/gist/gist.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/access/gist/gist.c,v
retrieving revision 1.79
diff -u -r1.79 gist.c
--- src/backend/access/gist/gist.c 2001/06/11 05:00:56 1.79
+++ src/backend/access/gist/gist.c 2001/07/11 15:01:28
@@ -217,7 +217,7 @@
*/
if (oldPred != NULL)
{
- slot->val = htup;
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (ExecQual((List *) oldPred, econtext, false))
{
nitups += 1.0;
@@ -231,7 +231,7 @@
*/
if (pred != NULL)
{
- slot->val = htup;
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (!ExecQual((List *) pred, econtext, false))
continue;
}
Index: src/backend/access/hash/hash.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/access/hash/hash.c,v
retrieving revision 1.51
diff -u -r1.51 hash.c
--- src/backend/access/hash/hash.c 2001/05/07 00:43:15 1.51
+++ src/backend/access/hash/hash.c 2001/07/11 15:01:28
@@ -128,7 +128,7 @@
*/
if (oldPred != NULL)
{
- slot->val = htup;
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (ExecQual((List *) oldPred, econtext, false))
{
nitups += 1.0;
@@ -142,7 +142,7 @@
*/
if (pred != NULL)
{
- slot->val = htup;
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (!ExecQual((List *) pred, econtext, false))
continue;
}
Index: src/backend/access/nbtree/nbtree.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v
retrieving revision 1.81
diff -u -r1.81 nbtree.c
--- src/backend/access/nbtree/nbtree.c 2001/05/18 21:24:17 1.81
+++ src/backend/access/nbtree/nbtree.c 2001/07/11 15:01:29
@@ -202,7 +202,8 @@
*/
if (oldPred != NULL)
{
- slot->val = htup;
+ /* Invalid buffer should be ok, index shouldn't go away, i hope */
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (ExecQual((List *) oldPred, econtext, false))
{
nitups += 1.0;
@@ -216,7 +217,8 @@
*/
if (pred != NULL)
{
- slot->val = htup;
+ /* Invalid buffer should be ok, index shouldn't go away, i hope */
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (!ExecQual((List *) pred, econtext, false))
continue;
}
Index: src/backend/access/rtree/rtree.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/access/rtree/rtree.c,v
retrieving revision 1.62
diff -u -r1.62 rtree.c
--- src/backend/access/rtree/rtree.c 2001/05/07 00:43:16 1.62
+++ src/backend/access/rtree/rtree.c 2001/07/11 15:01:29
@@ -182,7 +182,7 @@
*/
if (oldPred != NULL)
{
- slot->val = htup;
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (ExecQual((List *) oldPred, econtext, false))
{
nitups += 1.0;
@@ -196,7 +196,7 @@
*/
if (pred != NULL)
{
- slot->val = htup;
+ ExecStoreTuple( htup, slot, InvalidBuffer, false );
if (!ExecQual((List *) pred, econtext, false))
continue;
}
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.201
diff -u -r1.201 vacuum.c
--- src/backend/commands/vacuum.c 2001/07/02 20:50:46 1.201
+++ src/backend/commands/vacuum.c 2001/07/11 15:01:30
@@ -48,6 +48,8 @@
#include "utils/relcache.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
+#include "executor/executor.h"
+#include "tcop/pquery.h"
#include "pgstat.h"
@@ -153,8 +155,6 @@
static void vpage_insert(VacPageList vacpagelist, VacPage vpnew);
static void get_indices(Relation relation, int *nindices, Relation **Irel);
static void close_indices(int nindices, Relation *Irel);
-static IndexInfo **get_index_desc(Relation onerel, int nindices,
- Relation *Irel);
static void *vac_bsearch(const void *key, const void *base,
size_t nelem, size_t size,
int (*compar) (const void *, const void *));
@@ -1089,10 +1089,7 @@
HeapTupleData tuple,
newtup;
TupleDesc tupdesc;
- IndexInfo **indexInfo = NULL;
- Datum idatum[INDEX_MAX_KEYS];
- char inulls[INDEX_MAX_KEYS];
- InsertIndexResult iresult;
+
VacPageListData Nvacpagelist;
VacPage cur_page = NULL,
last_vacuum_page,
@@ -1112,6 +1109,11 @@
chain_tuple_moved;
VacRUsage ru0;
+ ResultRelInfo *resultRelInfo;
+ EState *estate = CreateExecutorState(); /* for ExecInsertTuples() */
+ TupleTable tupleTable;
+ TupleTableSlot *slot;
+
init_rusage(&ru0);
myXID = GetCurrentTransactionId();
@@ -1119,8 +1121,26 @@
tupdesc = RelationGetDescr(onerel);
- if (Irel != (Relation *) NULL) /* preparation for index' inserts */
- indexInfo = get_index_desc(onerel, nindices, Irel);
+ /*
+ * We need a ResultRelInfo so we can use the regular executor's
+ * index-entry-making machinery. (There used to be a huge amount of
+ * code here that basically duplicated execUtils.c ...)
+ */
+ resultRelInfo = makeNode(ResultRelInfo);
+ resultRelInfo->ri_RangeTableIndex = 1; /* dummy */
+ resultRelInfo->ri_RelationDesc = onerel;
+ /* resultRelInfo->ri_TrigDesc = rel->trigdesc; Don't need this I think */
+
+ ExecOpenIndices(resultRelInfo);
+
+ estate->es_result_relations = resultRelInfo;
+ estate->es_num_result_relations = 1;
+ estate->es_result_relation_info = resultRelInfo;
+
+ /* Set up a dummy tuple table too */
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ ExecSetSlotDescriptor(slot, tupdesc, false);
Nvacpagelist.num_pages = 0;
num_fraged_pages = fraged_pages->num_pages;
@@ -1647,32 +1667,9 @@
if (Irel != (Relation *) NULL)
{
-
- /*
- * XXX using CurrentMemoryContext here means
- * intra-vacuum memory leak for functional
- * indexes. Should fix someday.
- *
- * XXX This code fails to handle partial indexes!
- * Probably should change it to use
- * ExecOpenIndices.
- */
- for (i = 0; i < nindices; i++)
- {
- FormIndexDatum(indexInfo[i],
- &newtup,
- tupdesc,
- CurrentMemoryContext,
- idatum,
- inulls);
- iresult = index_insert(Irel[i],
- idatum,
- inulls,
- &newtup.t_self,
- onerel);
- if (iresult)
- pfree(iresult);
- }
+ ExecStoreTuple(&newtup, slot, InvalidBuffer, false);
+ if (resultRelInfo->ri_NumIndices > 0)
+ ExecInsertIndexTuples(slot, &(newtup.t_self), estate, false);
}
WriteBuffer(cur_buffer);
WriteBuffer(Cbuf);
@@ -1780,32 +1777,12 @@
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
/* insert index' tuples if needed */
+
if (Irel != (Relation *) NULL)
{
-
- /*
- * XXX using CurrentMemoryContext here means intra-vacuum
- * memory leak for functional indexes. Should fix someday.
- *
- * XXX This code fails to handle partial indexes! Probably
- * should change it to use ExecOpenIndices.
- */
- for (i = 0; i < nindices; i++)
- {
- FormIndexDatum(indexInfo[i],
- &newtup,
- tupdesc,
- CurrentMemoryContext,
- idatum,
- inulls);
- iresult = index_insert(Irel[i],
- idatum,
- inulls,
- &newtup.t_self,
- onerel);
- if (iresult)
- pfree(iresult);
- }
+ ExecStoreTuple(&newtup, slot, InvalidBuffer, false);
+ if (resultRelInfo->ri_NumIndices > 0)
+ ExecInsertIndexTuples(slot, &(newtup.t_self), estate, false);
}
} /* walk along page */
@@ -2095,11 +2072,9 @@
vacrelstats->rel_pages = blkno; /* set new number of blocks */
}
- if (Irel != (Relation *) NULL) /* pfree index' allocations */
- {
- close_indices(nindices, Irel);
- pfree(indexInfo);
- }
+ ExecDropTupleTable(tupleTable, true);
+
+ ExecCloseIndices(resultRelInfo);
pfree(vacpage);
if (vacrelstats->vtlinks != NULL)
@@ -2649,35 +2624,6 @@
pfree(Irel);
}
-
-
-/*
- * Obtain IndexInfo data for each index on the rel
- */
-static IndexInfo **
-get_index_desc(Relation onerel, int nindices, Relation *Irel)
-{
- IndexInfo **indexInfo;
- int i;
- HeapTuple cachetuple;
-
- indexInfo = (IndexInfo **) palloc(nindices * sizeof(IndexInfo *));
-
- for (i = 0; i < nindices; i++)
- {
- cachetuple = SearchSysCache(INDEXRELID,
- ObjectIdGetDatum(RelationGetRelid(Irel[i])),
- 0, 0, 0);
- if (!HeapTupleIsValid(cachetuple))
- elog(ERROR, "get_index_desc: index %u not found",
- RelationGetRelid(Irel[i]));
- indexInfo[i] = BuildIndexInfo(cachetuple);
- ReleaseSysCache(cachetuple);
- }
-
- return indexInfo;
-}
-
static bool
enough_space(VacPage vacpage, Size len)
Index: src/backend/optimizer/path/indxpath.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v
retrieving revision 1.108
diff -u -r1.108 indxpath.c
--- src/backend/optimizer/path/indxpath.c 2001/06/25 21:11:43 1.108
+++ src/backend/optimizer/path/indxpath.c 2001/07/11 15:01:31
@@ -195,8 +195,10 @@
* 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 clause may be useful
*/
- 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,
@@ -1185,6 +1187,8 @@
ScanKeyData entry[3];
Form_pg_amop aform;
+ ExprContext *econtext;
+
pred_var = (Var *) get_leftop(predicate);
pred_const = (Const *) get_rightop(predicate);
clause_var = (Var *) get_leftop((Expr *) clause);
@@ -1334,7 +1338,8 @@
copyObject(clause_const),
copyObject(pred_const));
- test_result = ExecEvalExpr((Node *) test_expr, NULL, &isNull, NULL);
+ econtext = MakeExprContext(NULL, TransactionCommandContext);
+ test_result = ExecEvalExpr((Node *) test_expr, econtext, &isNull, NULL);
if (isNull)
{
Index: src/backend/optimizer/util/pathnode.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v
retrieving revision 1.74
diff -u -r1.74 pathnode.c
--- src/backend/optimizer/util/pathnode.c 2001/06/05 05:26:04 1.74
+++ src/backend/optimizer/util/pathnode.c 2001/07/11 15:01:31
@@ -362,6 +362,11 @@
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;
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/analyze.c,v
retrieving revision 1.192
diff -u -r1.192 analyze.c
--- src/backend/parser/analyze.c 2001/07/04 17:36:54 1.192
+++ src/backend/parser/analyze.c 2001/07/11 15:01:33
@@ -1631,6 +1631,12 @@
{
Query *qry;
+ /* Add the table to the range table so that the WHERE clause can use the fields */
+ /* no inheritence, yes we can use fields from relation */
+ RangeTblEntry *rte = addRangeTableEntry( pstate, stmt->relname, NULL, false, true );
+ /* no to join list, yes to namespace */
+ addRTEtoQuery( pstate, rte, false, true );
+
qry = makeNode(Query);
qry->commandType = CMD_UTILITY;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.235
diff -u -r2.235 gram.y
--- src/backend/parser/gram.y 2001/07/10 22:09:28 2.235
+++ src/backend/parser/gram.y 2001/07/11 15:01:34
@@ -135,7 +135,7 @@
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,
@@ -447,7 +447,7 @@
| DropPLangStmt
| DropTrigStmt
| DropUserStmt
- | ExtendStmt
+/* | ExtendStmt */
| ExplainStmt
| FetchStmt
| GrantStmt
@@ -2385,11 +2385,10 @@
* using "(" ( with )+ ")" [with
* ]
*
- * [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;
@@ -2398,7 +2397,7 @@
n->accessMethod = $7;
n->indexParams = $9;
n->withClause = $11;
- n->whereClause = NULL;
+ n->whereClause = $12;
$$ = (Node *)n;
}
;
@@ -2466,8 +2465,9 @@
* QUERY:
* extend index [where ]
*
+ * Removed. No longer supported. (July 2001)
*****************************************************************************/
-
+/*
ExtendStmt: EXTEND INDEX index_name where_clause
{
ExtendStmt *n = makeNode(ExtendStmt);
@@ -2476,7 +2476,7 @@
$$ = (Node *)n;
}
;
-
+*/
/*****************************************************************************
*
* QUERY:
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.79
diff -u -r1.79 ruleutils.c
--- src/backend/utils/adt/ruleutils.c 2001/07/10 00:02:02 1.79
+++ src/backend/utils/adt/ruleutils.c 2001/07/11 15:01:36
@@ -43,6 +43,7 @@
#include "catalog/pg_index.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h"
+#include "catalog/heap.h"
#include "commands/view.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
@@ -551,6 +552,78 @@
elog(ERROR, "get_viewdef: SPI_finish() failed");
PG_RETURN_TEXT_P(indexdef);
+}
+
+/* ----------
+ * get_expr - Turn a node expression into a expression
+ * Used to get the expr used in partial indices
+ * ----------
+ */
+Datum
+pg_get_expr(PG_FUNCTION_ARGS)
+{
+ text *expr = PG_GETARG_TEXT_P(0);
+ text *relname = PG_GETARG_TEXT_P(1);
+
+ StringInfoData buf;
+ text *result;
+ List *list;
+ List *node;
+ char *str;
+ int len;
+ int relid;
+ List *context;
+
+ char *pexpr, *prelname;
+
+ /* I'm surprised there's no pre-canned function for this */
+ prelname = palloc( VARSIZE( relname ) - VARHDRSZ + 1 );
+ bzero( prelname, VARSIZE( relname ) - VARHDRSZ + 1 );
+ memcpy( prelname, VARDATA( relname ), VARSIZE( relname ) - VARHDRSZ );
+
+ /* Get the OID for the given relation */
+ relid = RelnameFindRelid( prelname );
+
+ if( relid == InvalidOid )
+ {
+ pfree( prelname );
+ PG_RETURN_NULL();
+ }
+
+ context = deparse_context_for( prelname, relid );
+
+ initStringInfo(&buf);
+ pexpr = palloc( VARSIZE( expr ) - VARHDRSZ + 1 );
+ bzero( pexpr, VARSIZE( expr ) - VARHDRSZ + 1 );
+ memcpy( pexpr, VARDATA( expr ), VARSIZE( expr ) - VARHDRSZ );
+ list = (List*)stringToNode( pexpr );
+ if( list->type != T_List ) /* Result doesn't match what we're looking for? */
+ {
+ pfree( prelname );
+ pfree( pexpr );
+ PG_RETURN_NULL();
+ }
+
+ /* Deparse each expression in the list and AND them together */
+ foreach( node, list )
+ {
+ str = deparse_expression( lfirst(node), context, false );
+ appendStringInfo( &buf, str );
+ if( node->next )
+ appendStringInfo( &buf, " AND " );
+ }
+
+ /* Pass the result back */
+ len = buf.len + VARHDRSZ;
+ result = palloc(len);
+ VARATT_SIZEP(result) = len;
+ memcpy(VARDATA(result), buf.data, buf.len);
+
+ pfree( buf.data );
+ pfree( prelname );
+ pfree( pexpr );
+
+ PG_RETURN_TEXT_P(result);
}
Index: src/backend/utils/adt/selfuncs.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v
retrieving revision 1.94
diff -u -r1.94 selfuncs.c
--- src/backend/utils/adt/selfuncs.c 2001/06/25 21:11:44 1.94
+++ src/backend/utils/adt/selfuncs.c 2001/07/11 15:01:38
@@ -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,18 +2951,34 @@
{
double numIndexTuples;
double numIndexPages;
+ Selectivity thisIndexSelectivity;
- /* 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;
-
- /*
+ /* Create the list of all relevent clauses by including any index predicates */
+ /* Both indpred and indexQuals are implicit-AND lists */
+ List *selectQuals = cnfify( (Expr *)nconc( listCopy( index->indpred ), indexQuals ), false );
+
+ /* Estimate the fraction of main-table tuples that will be visited */
+ *indexSelectivity = clauselist_selectivity(root, selectQuals,
+ lfirsti(rel->relids));
+
+ /* Estimate the fraction of index tuples to be visited (for partial indexes) */
+ /* This is a simple way of doing it. Should we call clauselist_selectivity again? */
+ thisIndexSelectivity = *indexSelectivity * rel->tuples / index->tuples;
+
+ /* Cap the index selectivity for partial indices */
+ if( thisIndexSelectivity > 1 )
+ {
+ thisIndexSelectivity = 1;
+ *indexSelectivity = (float) index->tuples / (float) rel->tuples;
+ }
+
+ /* Estimate the number of index tuples that will be visited */
+ numIndexTuples = thisIndexSelectivity * index->tuples;
+
+ /* Estimate the number of index pages that will be retrieved */
+ numIndexPages = thisIndexSelectivity * index->pages;
+
+ /*
* Always estimate at least one tuple and page are touched, even when
* indexSelectivity estimate is tiny.
*/
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.213
diff -u -r1.213 pg_dump.c
--- src/bin/pg_dump/pg_dump.c 2001/07/03 20:21:49 1.213
+++ src/bin/pg_dump/pg_dump.c 2001/07/11 15:01:40
@@ -1758,6 +1758,8 @@
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,6 +2889,7 @@
int i_indoid;
int i_oid;
int i_indisprimary;
+ int i_indpred;
/*
* find all the user-defined indexes. We do not handle partial
@@ -2902,7 +2905,7 @@
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 +2941,7 @@
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 +2959,7 @@
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 +4440,45 @@
{
/* 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();
+
+ resetPQExpBuffer(pred);
+ appendPQExpBuffer(pred, "SELECT pg_get_expr('%s','%s') as pred;",
+ indinfo[i].indpred,
+ indinfo[i].indrelname);
+ 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
Index: src/bin/pg_dump/pg_dump.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/bin/pg_dump/pg_dump.h,v
retrieving revision 1.65
diff -u -r1.65 pg_dump.h
--- src/bin/pg_dump/pg_dump.h 2001/07/03 20:21:50 1.65
+++ src/bin/pg_dump/pg_dump.h 2001/07/11 15:01:40
@@ -147,6 +147,7 @@
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
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.195
diff -u -r1.195 pg_proc.h
--- src/include/catalog/pg_proc.h 2001/06/22 19:16:24 1.195
+++ src/include/catalog/pg_proc.h 2001/07/11 15:01:42
@@ -2147,6 +2147,9 @@
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 25" 100 0 0 100 pg_get_expr - ));
+DESCR("deparse an encoded predicate");
+
/* 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 - ));
Index: src/include/utils/builtins.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.156
diff -u -r1.156 builtins.h
--- src/include/utils/builtins.h 2001/06/25 21:11:45 1.156
+++ src/include/utils/builtins.h 2001/07/11 15:01:43
@@ -337,6 +337,7 @@
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);
Index: src/test/regress/sql/create_index.sql
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/test/regress/sql/create_index.sql,v
retrieving revision 1.7
diff -u -r1.7 create_index.sql
--- src/test/regress/sql/create_index.sql 2000/02/17 03:40:02 1.7
+++ src/test/regress/sql/create_index.sql 2001/07/11 15:01:44
@@ -50,20 +50,15 @@
--
-- 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