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 @@
       <entry>indpred</entry>
       <entry><type>text</type></entry>
       <entry></entry>
-      <entry>Query plan for partial index predicate (not functional)</entry>
+      <entry>Query plan for partial index predicate</entry>
      </row>
     </tbody>
    </tgroup>
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>
     <title>Note</title>
     <para>
-     Partial indexes are not currently supported by
-     <productname>PostgreSQL</productname>, but they were once supported
-     by its predecessor <productname>Postgres</productname>, 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
+      <productname>PostgreSQL</productname>, but they were once supported by
+      its predecessor <productname>Postgres</productname>, 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.
     </para>
    </note>
 
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 @@
   <synopsis>
 CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ON <replaceable class="parameter">table</replaceable>
     [ USING <replaceable class="parameter">acc_name</replaceable> ] ( <replaceable class="parameter">column</replaceable> [ <replaceable class="parameter">ops_name</replaceable> ] [, ...] )
+    [ WHERE <replaceable class="parameter">expr</replaceable> ]
 CREATE [ UNIQUE ] INDEX <replaceable class="parameter">index_name</replaceable> ON <replaceable class="parameter">table</replaceable>
     [ USING <replaceable class="parameter">acc_name</replaceable> ] ( <replaceable class="parameter">func_name</replaceable>( <replaceable class="parameter">column</replaceable> [, ... ]) [ <replaceable class="parameter">ops_name</replaceable> ] )
+    [ WHERE <replaceable class="parameter">expr</replaceable> ]
   </synopsis>
 
   <refsect2 id="R2-SQL-CREATEINDEX-1">
@@ -137,6 +139,15 @@
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry>
+      <term><replaceable class="parameter">expr</replaceable></term>
+      <listitem>
+       <para>
+	Defines the expression for a partial index.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </refsect2>
@@ -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).
+  </para>
+
+  <para>
+    When the <command>WHERE</command> 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.
+  </para>
+
+  <para>
+    The expression used in the <command>WHERE</command> clause is restricted
+    to forms the planner can easily use. Each element can only consist of
+    <command>ATTR OP CONST</command> and these can only be joined by
+    <command>AND</command> and <command>OR</command> operators.
   </para>
 
   <para>
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 <access> "(" (<col> with <op>)+ ")" [with
  *				  <target_list>]
  *
- *	[where <qual>] is not supported anymore
  *****************************************************************************/
 
 IndexStmt:	CREATE index_opt_unique INDEX index_name ON relation_name
-			access_method_clause '(' index_params ')' opt_with
+			access_method_clause '(' index_params ')' opt_with where_clause
 				{
 					IndexStmt *n = makeNode(IndexStmt);
 					n->unique = $2;
@@ -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 <indexname> [where <qual>]
  *
+ * 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
