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;