diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 0ece6c6702f43d218f20b9e4cc27c6579624d66e..3a489b361c64742b0abd17e7c04a2b4f8113e503 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.88 2003/12/30 20:05:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.89 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -99,7 +99,9 @@ IndexNext(IndexScanState *node)
 	ExprContext *econtext;
 	ScanDirection direction;
 	IndexScanDescPtr scanDescs;
+	List	  **lossyQuals;
 	IndexScanDesc scandesc;
+	List	   *lossyQual;
 	Index		scanrelid;
 	HeapTuple	tuple;
 	TupleTableSlot *slot;
@@ -120,6 +122,7 @@ IndexNext(IndexScanState *node)
 			direction = ForwardScanDirection;
 	}
 	scanDescs = node->iss_ScanDescs;
+	lossyQuals = node->iss_LossyQuals;
 	numIndices = node->iss_NumIndices;
 	econtext = node->ss.ps.ps_ExprContext;
 	slot = node->ss.ss_ScanTupleSlot;
@@ -188,6 +191,8 @@ IndexNext(IndexScanState *node)
 	while (indexNumber < numIndices)
 	{
 		scandesc = scanDescs[node->iss_IndexPtr];
+		lossyQual = lossyQuals[node->iss_IndexPtr];
+
 		while ((tuple = index_getnext(scandesc, direction)) != NULL)
 		{
 			/*
@@ -201,6 +206,22 @@ IndexNext(IndexScanState *node)
 						   scandesc->xs_cbuf,	/* buffer containing tuple */
 						   false);		/* don't pfree */
 
+			/*
+			 * If any of the index operators involved in this scan are lossy,
+			 * recheck them by evaluating the original operator clauses.
+			 */
+			if (lossyQual)
+			{
+				econtext->ecxt_scantuple = slot;
+				ResetExprContext(econtext);
+				if (!ExecQual(lossyQual, econtext, false))
+				{
+					/* Fails lossy op, so drop it and loop back for another */
+					ExecClearTuple(slot);
+					continue;
+				}
+			}
+
 			/*
 			 * If it's a multiple-index scan, make sure not to double-report
 			 * a tuple matched by more than one index.  (See notes above.)
@@ -615,6 +636,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 	List	   *indxqual;
 	List	   *indxstrategy;
 	List	   *indxsubtype;
+	List	   *indxlossy;
 	List	   *indxid;
 	int			i;
 	int			numIndices;
@@ -623,6 +645,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 	int		   *numScanKeys;
 	RelationPtr indexDescs;
 	IndexScanDescPtr scanDescs;
+	List	  **lossyQuals;
 	ExprState ***runtimeKeyInfo;
 	bool		have_runtime_keys;
 	RangeTblEntry *rtentry;
@@ -680,6 +703,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 	indexstate->iss_RuntimeKeysReady = false;
 	indexstate->iss_RelationDescs = NULL;
 	indexstate->iss_ScanDescs = NULL;
+	indexstate->iss_LossyQuals = NULL;
 
 	/*
 	 * get the index node information
@@ -699,6 +723,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 	scanKeys = (ScanKey *) palloc(numIndices * sizeof(ScanKey));
 	indexDescs = (RelationPtr) palloc(numIndices * sizeof(Relation));
 	scanDescs = (IndexScanDescPtr) palloc(numIndices * sizeof(IndexScanDesc));
+	lossyQuals = (List **) palloc0(numIndices * sizeof(List *));
 
 	/*
 	 * initialize space for runtime key info (may not be needed)
@@ -712,11 +737,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 	indxqual = node->indxqual;
 	indxstrategy = node->indxstrategy;
 	indxsubtype = node->indxsubtype;
+	indxlossy = node->indxlossy;
 	for (i = 0; i < numIndices; i++)
 	{
 		List	   *quals;
 		List	   *strategies;
 		List	   *subtypes;
+		List	   *lossyflags;
 		int			n_keys;
 		ScanKey		scan_keys;
 		ExprState **run_keys;
@@ -728,6 +755,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 		indxstrategy = lnext(indxstrategy);
 		subtypes = lfirst(indxsubtype);
 		indxsubtype = lnext(indxsubtype);
+		lossyflags = lfirst(indxlossy);
+		indxlossy = lnext(indxlossy);
 		n_keys = length(quals);
 		scan_keys = (n_keys <= 0) ? (ScanKey) NULL :
 			(ScanKey) palloc(n_keys * sizeof(ScanKeyData));
@@ -747,6 +776,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 			AttrNumber	varattno;		/* att number used in scan */
 			StrategyNumber strategy;	/* op's strategy number */
 			Oid			subtype;		/* op's strategy subtype */
+			int			lossy;			/* op's recheck flag */
 			RegProcedure opfuncid;		/* operator proc id used in scan */
 			Datum		scanvalue;		/* value used in scan (if const) */
 
@@ -759,6 +789,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 			strategies = lnext(strategies);
 			subtype = lfirsto(subtypes);
 			subtypes = lnext(subtypes);
+			lossy = lfirsti(lossyflags);
+			lossyflags = lnext(lossyflags);
 
 			if (!IsA(clause, OpExpr))
 				elog(ERROR, "indxqual is not an OpExpr");
@@ -839,6 +871,20 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 								   subtype,		/* strategy subtype */
 								   opfuncid,	/* reg proc to use */
 								   scanvalue);	/* constant */
+
+			/*
+			 * If this operator is lossy, add its indxqualorig expression
+			 * to the list of quals to recheck.  The nth() calls here could
+			 * be avoided by chasing the lists in parallel to all the other
+			 * lists, but since lossy operators are very uncommon, it's
+			 * probably a waste of time to do so.
+			 */
+			if (lossy)
+			{
+				lossyQuals[i] = lappend(lossyQuals[i],
+										nth(j,
+											(List *) nth(i, indexstate->indxqualorig)));
+			}
 		}
 
 		/*
@@ -928,6 +974,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
 
 	indexstate->iss_RelationDescs = indexDescs;
 	indexstate->iss_ScanDescs = scanDescs;
+	indexstate->iss_LossyQuals = lossyQuals;
 
 	/*
 	 * Initialize result tuple type and projection info.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 75c2fa898d9f190df2f63033b776a36a985e57ba..18a8a369e69ce07cd231dd4105e71cb586e445c6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.273 2004/01/05 05:07:35 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.274 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -284,6 +284,17 @@ _copyIndexScan(IndexScan *from)
 		}
 		newnode->indxsubtype = newsubtype;
 	}
+	/* this can become COPY_NODE_FIELD when intlists are normal objects: */
+	{
+		List	*newstrat = NIL;
+		List    *tmp;
+
+		foreach(tmp, from->indxlossy)
+		{
+			newstrat = lappend(newstrat, listCopy(lfirst(tmp)));
+		}
+		newnode->indxlossy = newstrat;
+	}
 	COPY_SCALAR_FIELD(indxorderdir);
 
 	return newnode;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 1a78769e8f2d768b86ebd5fc825805249ef5ac45..ce80cae4bdbf8e6478a8f4a4be97d53596a0a708 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.228 2004/01/05 23:39:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.229 2004/01/06 04:31:01 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -356,6 +356,16 @@ _outIndexScan(StringInfo str, IndexScan *node)
 			_outOidList(str, lfirst(tmp));
 		}
 	}
+	/* this can become WRITE_NODE_FIELD when intlists are normal objects: */
+	{
+		List    *tmp;
+
+		appendStringInfo(str, " :indxlossy ");
+		foreach(tmp, node->indxlossy)
+		{
+			_outIntList(str, lfirst(tmp));
+		}
+	}
 	WRITE_ENUM_FIELD(indxorderdir, ScanDirection);
 }
 
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 7353e73462b01bc013d5eb9c519a69b68cc447e7..3f9416c20ac3a26f3bb793f9d1e8c1e071b99372 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -49,7 +49,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.121 2004/01/05 23:39:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.122 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -384,10 +384,6 @@ cost_index(Path *path, Query *root,
 	 * some of the indexquals are join clauses and shouldn't be
 	 * subtracted. Rather than work out exactly how much to subtract, we
 	 * don't subtract anything.
-	 *
-	 * XXX For a lossy index, not all the quals will be removed and so we
-	 * really shouldn't subtract their costs; but detecting that seems
-	 * more expensive than it's worth.
 	 */
 	startup_cost += baserel->baserestrictcost.startup;
 	cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;
@@ -397,6 +393,7 @@ cost_index(Path *path, Query *root,
 		QualCost	index_qual_cost;
 
 		cost_qual_eval(&index_qual_cost, indexQuals);
+		/* any startup cost still has to be paid ... */
 		cpu_per_tuple -= index_qual_cost.per_tuple;
 	}
 
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 591cf47f8c63723212c2d0268858b6521395be51..a1030c8779c9f550ddcfd2c82af4284ca99a06ce 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.164 2004/01/05 23:39:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.165 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,16 +62,16 @@ static HashJoin *create_hashjoin_plan(Query *root, HashPath *best_path,
 					 Plan *outer_plan, Plan *inner_plan);
 static void fix_indxqual_references(List *indexquals, IndexPath *index_path,
 						List **fixed_indexquals,
-						List **recheck_indexquals,
 						List **indxstrategy,
-						List **indxsubtype);
+						List **indxsubtype,
+						List **indxlossy);
 static void fix_indxqual_sublist(List *indexqual,
 					 Relids baserelids, int baserelid,
 					 IndexOptInfo *index,
 					 List **fixed_quals,
-					 List **recheck_quals,
 					 List **strategy,
-					 List **subtype);
+					 List **subtype,
+					 List **lossy);
 static Node *fix_indxqual_operand(Node *node, int baserelid,
 					 IndexOptInfo *index,
 					 Oid *opclass);
@@ -82,7 +82,7 @@ static void copy_plan_costsize(Plan *dest, Plan *src);
 static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
 static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
 			   List *indxid, List *indxqual, List *indxqualorig,
-			   List *indxstrategy, List *indxsubtype,
+			   List *indxstrategy, List *indxsubtype, List *indxlossy,
 			   ScanDirection indexscandir);
 static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
 			 List *tideval);
@@ -718,9 +718,9 @@ create_indexscan_plan(Query *root,
 	Expr	   *indxqual_or_expr = NULL;
 	List	   *stripped_indxquals;
 	List	   *fixed_indxquals;
-	List	   *recheck_indxquals;
 	List	   *indxstrategy;
 	List	   *indxsubtype;
+	List	   *indxlossy;
 	FastList	indexids;
 	List	   *i;
 	IndexScan  *scan_plan;
@@ -735,8 +735,8 @@ create_indexscan_plan(Query *root,
 	 * value is just the rel's baserestrictinfo list).  We must add these
 	 * clauses to scan_clauses to ensure they get checked.  In most cases
 	 * we will remove the join clauses again below, but if a join clause
-	 * contains a lossy or special operator, we need to make sure it gets
-	 * into scan_clauses.
+	 * contains a special operator, we need to make sure it gets into the
+	 * scan_clauses.
 	 */
 	if (best_path->isjoininner)
 	{
@@ -780,22 +780,19 @@ create_indexscan_plan(Query *root,
 
 	/*
 	 * The qpqual list must contain all restrictions not automatically
-	 * handled by the index.  Normally the predicates in the indexquals are
-	 * checked fully by the index, but if the index is "lossy" for a
-	 * particular operator (as signaled by the amopreqcheck flag in
-	 * pg_amop), then we need to double-check that predicate in qpqual,
-	 * because the index may return more tuples than match the predicate.
-	 *
-	 * Since the indexquals were generated from the restriction clauses given
-	 * by scan_clauses, there will normally be duplications between the lists.
-	 * We get rid of the duplicates, then add back if lossy.
+	 * handled by the index.  All the predicates in the indexquals will
+	 * be checked (either by the index itself, or by nodeIndexscan.c), but
+	 * if there are any "special" operators involved then they must be
+	 * added to qpqual.  The upshot is that qpquals must contain scan_clauses
+	 * minus whatever appears in indxquals.
 	 */
 	if (length(indxquals) > 1)
 	{
 		/*
 		 * Build an expression representation of the indexqual, expanding
 		 * the implicit OR and AND semantics of the first- and
-		 * second-level lists.
+		 * second-level lists.  (The odds that this will exactly match any
+		 * scan_clause are not great; perhaps we need more smarts here.)
 		 */
 		indxqual_or_expr = make_expr_from_indexclauses(indxquals);
 		qpqual = set_difference(scan_clauses, makeList1(indxqual_or_expr));
@@ -814,34 +811,11 @@ create_indexscan_plan(Query *root,
 	/*
 	 * The executor needs a copy with the indexkey on the left of each
 	 * clause and with index attr numbers substituted for table ones. This
-	 * pass also looks for "lossy" operators.
+	 * pass also gets strategy info and looks for "lossy" operators.
 	 */
 	fix_indxqual_references(indxquals, best_path,
-							&fixed_indxquals, &recheck_indxquals,
-							&indxstrategy, &indxsubtype);
-
-	/*
-	 * If there were any "lossy" operators, need to add back the
-	 * appropriate qual clauses to the qpqual.	When there is just one
-	 * indexscan being performed (ie, we have simple AND semantics), we
-	 * can just add the lossy clauses themselves to qpqual.  If we have
-	 * OR-of-ANDs, we'd better add the entire original indexquals to make
-	 * sure that the semantics are correct.
-	 */
-	if (recheck_indxquals != NIL)
-	{
-		if (indxqual_or_expr)
-		{
-			/* Better do a deep copy of the original scanclauses */
-			qpqual = lappend(qpqual, copyObject(indxqual_or_expr));
-		}
-		else
-		{
-			/* Subroutine already copied quals, so just append to list */
-			Assert(length(recheck_indxquals) == 1);
-			qpqual = nconc(qpqual, (List *) lfirst(recheck_indxquals));
-		}
-	}
+							&fixed_indxquals,
+							&indxstrategy, &indxsubtype, &indxlossy);
 
 	/* Finally ready to build the plan node */
 	scan_plan = make_indexscan(tlist,
@@ -852,6 +826,7 @@ create_indexscan_plan(Query *root,
 							   stripped_indxquals,
 							   indxstrategy,
 							   indxsubtype,
+							   indxlossy,
 							   best_path->indexscandir);
 
 	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
@@ -1197,76 +1172,64 @@ create_hashjoin_plan(Query *root,
  *	  Adjust indexqual clauses to the form the executor's indexqual
  *	  machinery needs, and check for recheckable (lossy) index conditions.
  *
- * We have five tasks here:
+ * We have four tasks here:
  *	* Remove RestrictInfo nodes from the input clauses.
  *	* Index keys must be represented by Var nodes with varattno set to the
  *	  index's attribute number, not the attribute number in the original rel.
  *	* If the index key is on the right, commute the clause to put it on the
  *	  left.  (Someday the executor might not need this, but for now it does.)
- *	* If the indexable operator is marked 'amopreqcheck' in pg_amop, then
- *	  the index is "lossy" for this operator: it may return more tuples than
- *	  actually satisfy the operator condition.	For each such operator, we
- *	  must add (the original form of) the indexqual clause to the "qpquals"
- *	  of the indexscan node, where the operator will be re-evaluated to
- *	  ensure it passes.
- *	* We must construct lists of operator strategy numbers and subtypes for
- *	  the top-level operators of each index clause.
+ *	* We must construct lists of operator strategy numbers, subtypes, and
+ *	  recheck (lossy-operator) flags for the top-level operators of each
+ *	  index clause.
  *
- * Both the input list and the output lists have the form of lists of sublists
- * of qual clauses --- the top-level list has one entry for each indexscan
- * to be performed.  The semantics are OR-of-ANDs.  Note however that the
- * input list contains RestrictInfos, while the output lists do not.
+ * Both the input list and the "fixed" output list have the form of lists of
+ * sublists of qual clauses --- the top-level list has one entry for each
+ * indexscan to be performed.  The semantics are OR-of-ANDs.  Note however
+ * that the input list contains RestrictInfos, while the output list doesn't.
  *
  * fixed_indexquals receives a modified copy of the indexqual list --- the
  * original is not changed.  Note also that the copy shares no substructure
  * with the original; this is needed in case there is a subplan in it (we need
  * two separate copies of the subplan tree, or things will go awry).
  *
- * recheck_indexquals similarly receives a copy of whichever clauses
- * need rechecking.
- *
  * indxstrategy receives a list of integer sublists of strategy numbers.
  * indxsubtype receives a list of OID sublists of strategy subtypes.
+ * indxlossy receives a list of integer sublists of lossy-operator booleans.
  */
 static void
 fix_indxqual_references(List *indexquals, IndexPath *index_path,
-						List **fixed_indexquals, List **recheck_indexquals,
-						List **indxstrategy, List **indxsubtype)
+						List **fixed_indexquals,
+						List **indxstrategy,
+						List **indxsubtype,
+						List **indxlossy)
 {
-	FastList	fixed_quals;
-	FastList	recheck_quals;
 	Relids		baserelids = index_path->path.parent->relids;
 	int			baserelid = index_path->path.parent->relid;
 	List	   *ixinfo = index_path->indexinfo;
 	List	   *i;
 
-	FastListInit(&fixed_quals);
-	FastListInit(&recheck_quals);
+	*fixed_indexquals = NIL;
 	*indxstrategy = NIL;
 	*indxsubtype = NIL;
+	*indxlossy = NIL;
 	foreach(i, indexquals)
 	{
 		List	   *indexqual = lfirst(i);
 		IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
 		List	   *fixed_qual;
-		List	   *recheck_qual;
 		List	   *strategy;
 		List	   *subtype;
+		List	   *lossy;
 
 		fix_indxqual_sublist(indexqual, baserelids, baserelid, index,
-							 &fixed_qual, &recheck_qual,
-							 &strategy, &subtype);
-		FastAppend(&fixed_quals, fixed_qual);
-		if (recheck_qual != NIL)
-			FastAppend(&recheck_quals, recheck_qual);
+							 &fixed_qual, &strategy, &subtype, &lossy);
+		*fixed_indexquals = lappend(*fixed_indexquals, fixed_qual);
 		*indxstrategy = lappend(*indxstrategy, strategy);
 		*indxsubtype = lappend(*indxsubtype, subtype);
+		*indxlossy = lappend(*indxlossy, lossy);
 
 		ixinfo = lnext(ixinfo);
 	}
-
-	*fixed_indexquals = FastListValue(&fixed_quals);
-	*recheck_indexquals = FastListValue(&recheck_quals);
 }
 
 /*
@@ -1274,34 +1237,30 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
  *
  * For each qual clause, commute if needed to put the indexkey operand on the
  * left, and then fix its varattno.  (We do not need to change the other side
- * of the clause.)	Also change the operator if necessary, check for
- * lossy index behavior, and determine the operator's strategy number and
- * subtype number.
+ * of the clause.)  Then determine the operator's strategy number and subtype
+ * number, and check for lossy index behavior.
  *
  * Returns four lists:
  *		the list of fixed indexquals
- *		the list (usually empty) of original clauses that must be rechecked
- *			as qpquals because the index is lossy for this operator type
  *		the integer list of strategy numbers
  *		the OID list of strategy subtypes
+ *		the integer list of lossiness flags (1/0)
  */
 static void
 fix_indxqual_sublist(List *indexqual,
 					 Relids baserelids, int baserelid,
 					 IndexOptInfo *index,
 					 List **fixed_quals,
-					 List **recheck_quals,
 					 List **strategy,
-					 List **subtype)
+					 List **subtype,
+					 List **lossy)
 {
-	FastList	fixed_qual;
-	FastList	recheck_qual;
 	List	   *i;
 
-	FastListInit(&fixed_qual);
-	FastListInit(&recheck_qual);
+	*fixed_quals = NIL;
 	*strategy = NIL;
 	*subtype = NIL;
+	*lossy = NIL;
 	foreach(i, indexqual)
 	{
 		RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
@@ -1344,29 +1303,20 @@ fix_indxqual_sublist(List *indexqual,
 													   index,
 													   &opclass);
 
-		FastAppend(&fixed_qual, newclause);
+		*fixed_quals = lappend(*fixed_quals, newclause);
 
 		/*
-		 * Look up the operator in the operator class to get its strategy
-		 * numbers and the recheck indicator.  This also double-checks that
-		 * we found an operator matching the index.
+		 * Look up the (possibly commuted) operator in the operator class to
+		 * get its strategy numbers and the recheck indicator.  This also
+		 * double-checks that we found an operator matching the index.
 		 */
 		get_op_opclass_properties(newclause->opno, opclass,
 								  &stratno, &stratsubtype, &recheck);
 
 		*strategy = lappendi(*strategy, stratno);
 		*subtype = lappendo(*subtype, stratsubtype);
-
-		/*
-		 * If index is lossy for this operator, add (a copy of) original form
-		 * of clause to recheck list.
-		 */
-		if (recheck)
-			FastAppend(&recheck_qual, copyObject((Node *) clause));
+		*lossy = lappendi(*lossy, (int) recheck);
 	}
-
-	*fixed_quals = FastListValue(&fixed_qual);
-	*recheck_quals = FastListValue(&recheck_qual);
 }
 
 static Node *
@@ -1612,6 +1562,7 @@ make_indexscan(List *qptlist,
 			   List *indxqualorig,
 			   List *indxstrategy,
 			   List *indxsubtype,
+			   List *indxlossy,
 			   ScanDirection indexscandir)
 {
 	IndexScan  *node = makeNode(IndexScan);
@@ -1628,6 +1579,7 @@ make_indexscan(List *qptlist,
 	node->indxqualorig = indxqualorig;
 	node->indxstrategy = indxstrategy;
 	node->indxsubtype = indxsubtype;
+	node->indxlossy = indxlossy;
 	node->indxorderdir = indexscandir;
 
 	return node;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 8f64ef1488e2ca8842fe5777cbb884ca16ae3c1b..faf4eb29bee3e3ce50b702509bf0071c1c3a297a 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.99 2003/11/29 19:51:50 pgsql Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.100 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -362,8 +362,8 @@ set_join_references(Join *join, List *rtable)
 
 				/*
 				 * We must fix the inner qpqual too, if it has join
-				 * clauses (this could happen if the index is lossy: some
-				 * indxquals may get rechecked as qpquals).
+				 * clauses (this could happen if special operators are
+				 * involved: some indxquals may get rechecked as qpquals).
 				 */
 				if (NumRelids((Node *) inner_plan->qual) > 1)
 					inner_plan->qual = join_references(inner_plan->qual,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 48385d16f31a4d81fc5dfc341ab9f6cf4202cfe2..21d32dec857c917cd08dcff98d958f5026cdb0f2 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.109 2003/12/18 22:23:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.110 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -776,6 +776,7 @@ typedef ScanState SeqScanState;
  *		RuntimeKeysReady   true if runtime Skeys have been computed
  *		RelationDescs	   ptr to array of relation descriptors
  *		ScanDescs		   ptr to array of scan descriptors
+ *		LossyQuals		   ptr to array of qual lists for lossy operators
  *		DupHash			   hashtable for recognizing dups in multiple scan
  *		MaxHash			   max # entries we will allow in hashtable
  * ----------------
@@ -795,6 +796,7 @@ typedef struct IndexScanState
 	bool		iss_RuntimeKeysReady;
 	RelationPtr iss_RelationDescs;
 	IndexScanDescPtr iss_ScanDescs;
+	List	  **iss_LossyQuals;
 	HTAB	   *iss_DupHash;
 	long		iss_MaxHash;
 } IndexScanState;
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 580b9dec1929e597646b0e6ad2ea8643ceb3f784..be8b121e2516f86856a6d7741c4fe9adbb7c9722 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.72 2003/11/29 22:41:06 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.73 2004/01/06 04:31:01 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -166,6 +166,7 @@ typedef struct IndexScan
 	List	   *indxqualorig;	/* the same in original form */
 	List	   *indxstrategy;	/* list of sublists of strategy numbers */
 	List	   *indxsubtype;	/* list of sublists of strategy subtypes */
+	List	   *indxlossy;		/* list of sublists of lossy flags (ints) */
 	ScanDirection indxorderdir;	/* forward or backward or don't care */
 } IndexScan;