88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.88 2003/12/30 20:05:05 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/executor/nodeIndexscan.c,v 1.89 2004/01/06 04:31:01 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -99,7 +99,9 @@ IndexNext(IndexScanState *node)
9999ExprContext * econtext ;
100100ScanDirection direction ;
101101IndexScanDescPtr scanDescs ;
102+ List * * lossyQuals ;
102103IndexScanDesc scandesc ;
104+ List * lossyQual ;
103105Index scanrelid ;
104106HeapTuple tuple ;
105107TupleTableSlot * slot ;
@@ -120,6 +122,7 @@ IndexNext(IndexScanState *node)
120122direction = ForwardScanDirection ;
121123}
122124scanDescs = node -> iss_ScanDescs ;
125+ lossyQuals = node -> iss_LossyQuals ;
123126numIndices = node -> iss_NumIndices ;
124127econtext = node -> ss .ps .ps_ExprContext ;
125128slot = node -> ss .ss_ScanTupleSlot ;
@@ -188,6 +191,8 @@ IndexNext(IndexScanState *node)
188191while (indexNumber < numIndices )
189192{
190193scandesc = scanDescs [node -> iss_IndexPtr ];
194+ lossyQual = lossyQuals [node -> iss_IndexPtr ];
195+
191196while ((tuple = index_getnext (scandesc ,direction ))!= NULL )
192197{
193198/*
@@ -201,6 +206,22 @@ IndexNext(IndexScanState *node)
201206scandesc -> xs_cbuf ,/* buffer containing tuple */
202207 false);/* don't pfree */
203208
209+ /*
210+ * If any of the index operators involved in this scan are lossy,
211+ * recheck them by evaluating the original operator clauses.
212+ */
213+ if (lossyQual )
214+ {
215+ econtext -> ecxt_scantuple = slot ;
216+ ResetExprContext (econtext );
217+ if (!ExecQual (lossyQual ,econtext , false))
218+ {
219+ /* Fails lossy op, so drop it and loop back for another */
220+ ExecClearTuple (slot );
221+ continue ;
222+ }
223+ }
224+
204225/*
205226 * If it's a multiple-index scan, make sure not to double-report
206227 * a tuple matched by more than one index. (See notes above.)
@@ -615,6 +636,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
615636List * indxqual ;
616637List * indxstrategy ;
617638List * indxsubtype ;
639+ List * indxlossy ;
618640List * indxid ;
619641int i ;
620642int numIndices ;
@@ -623,6 +645,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
623645int * numScanKeys ;
624646RelationPtr indexDescs ;
625647IndexScanDescPtr scanDescs ;
648+ List * * lossyQuals ;
626649ExprState * * * runtimeKeyInfo ;
627650bool have_runtime_keys ;
628651RangeTblEntry * rtentry ;
@@ -680,6 +703,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
680703indexstate -> iss_RuntimeKeysReady = false;
681704indexstate -> iss_RelationDescs = NULL ;
682705indexstate -> iss_ScanDescs = NULL ;
706+ indexstate -> iss_LossyQuals = NULL ;
683707
684708/*
685709 * get the index node information
@@ -699,6 +723,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
699723scanKeys = (ScanKey * )palloc (numIndices * sizeof (ScanKey ));
700724indexDescs = (RelationPtr )palloc (numIndices * sizeof (Relation ));
701725scanDescs = (IndexScanDescPtr )palloc (numIndices * sizeof (IndexScanDesc ));
726+ lossyQuals = (List * * )palloc0 (numIndices * sizeof (List * ));
702727
703728/*
704729 * initialize space for runtime key info (may not be needed)
@@ -712,11 +737,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
712737indxqual = node -> indxqual ;
713738indxstrategy = node -> indxstrategy ;
714739indxsubtype = node -> indxsubtype ;
740+ indxlossy = node -> indxlossy ;
715741for (i = 0 ;i < numIndices ;i ++ )
716742{
717743List * quals ;
718744List * strategies ;
719745List * subtypes ;
746+ List * lossyflags ;
720747int n_keys ;
721748ScanKey scan_keys ;
722749ExprState * * run_keys ;
@@ -728,6 +755,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
728755indxstrategy = lnext (indxstrategy );
729756subtypes = lfirst (indxsubtype );
730757indxsubtype = lnext (indxsubtype );
758+ lossyflags = lfirst (indxlossy );
759+ indxlossy = lnext (indxlossy );
731760n_keys = length (quals );
732761scan_keys = (n_keys <=0 ) ? (ScanKey )NULL :
733762(ScanKey )palloc (n_keys * sizeof (ScanKeyData ));
@@ -747,6 +776,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
747776AttrNumber varattno ;/* att number used in scan */
748777StrategyNumber strategy ;/* op's strategy number */
749778Oid subtype ;/* op's strategy subtype */
779+ int lossy ;/* op's recheck flag */
750780RegProcedure opfuncid ;/* operator proc id used in scan */
751781Datum scanvalue ;/* value used in scan (if const) */
752782
@@ -759,6 +789,8 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
759789strategies = lnext (strategies );
760790subtype = lfirsto (subtypes );
761791subtypes = lnext (subtypes );
792+ lossy = lfirsti (lossyflags );
793+ lossyflags = lnext (lossyflags );
762794
763795if (!IsA (clause ,OpExpr ))
764796elog (ERROR ,"indxqual is not an OpExpr" );
@@ -839,6 +871,20 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
839871subtype ,/* strategy subtype */
840872opfuncid ,/* reg proc to use */
841873scanvalue );/* constant */
874+
875+ /*
876+ * If this operator is lossy, add its indxqualorig expression
877+ * to the list of quals to recheck. The nth() calls here could
878+ * be avoided by chasing the lists in parallel to all the other
879+ * lists, but since lossy operators are very uncommon, it's
880+ * probably a waste of time to do so.
881+ */
882+ if (lossy )
883+ {
884+ lossyQuals [i ]= lappend (lossyQuals [i ],
885+ nth (j ,
886+ (List * )nth (i ,indexstate -> indxqualorig )));
887+ }
842888}
843889
844890/*
@@ -928,6 +974,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
928974
929975indexstate -> iss_RelationDescs = indexDescs ;
930976indexstate -> iss_ScanDescs = scanDescs ;
977+ indexstate -> iss_LossyQuals = lossyQuals ;
931978
932979/*
933980 * Initialize result tuple type and projection info.