diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 31e2791eab..55a16f53b2 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.33 1998/06/15 19:28:19 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.34 1998/08/01 22:12:02 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1349,8 +1349,6 @@ ExecQual(List *qual, ExprContext *econtext) foreach(clause, qual) { - - result = ExecQualClause((Node *) lfirst(clause), econtext); if (result == true) break; diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 51308d4101..0f9be0a129 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.19 1998/07/27 19:37:57 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.20 1998/08/01 22:12:04 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -87,7 +87,6 @@ IndexNext(IndexScan *node) IndexScanState *indexstate; ScanDirection direction; Snapshot snapshot; - int indexPtr; IndexScanDescPtr scanDescs; IndexScanDesc scandesc; Relation heapRelation; @@ -95,7 +94,8 @@ IndexNext(IndexScan *node) HeapTuple tuple; TupleTableSlot *slot; Buffer buffer = InvalidBuffer; - + int numIndices; + /* ---------------- * extract necessary information from index scan node * ---------------- @@ -105,54 +105,66 @@ IndexNext(IndexScan *node) snapshot = estate->es_snapshot; scanstate = node->scan.scanstate; indexstate = node->indxstate; - indexPtr = indexstate->iss_IndexPtr; scanDescs = indexstate->iss_ScanDescs; - scandesc = scanDescs[indexPtr]; heapRelation = scanstate->css_currentRelation; - + numIndices = indexstate->iss_NumIndices; slot = scanstate->css_ScanTupleSlot; /* ---------------- * ok, now that we have what we need, fetch an index tuple. - * ---------------- - */ - - /* ---------------- * if scanning this index succeeded then return the * appropriate heap tuple.. else return NULL. * ---------------- */ - while ((result = index_getnext(scandesc, direction)) != NULL) + while (indexstate->iss_IndexPtr < numIndices) { - tuple = heap_fetch(heapRelation, snapshot, - &result->heap_iptr, &buffer); - /* be tidy */ - pfree(result); + scandesc = scanDescs[indexstate->iss_IndexPtr]; + while ((result = index_getnext(scandesc, direction)) != NULL) + { + tuple = heap_fetch(heapRelation, snapshot, + &result->heap_iptr, &buffer); + /* be tidy */ + pfree(result); - if (tuple != NULL) - { - /* ---------------- - * store the scanned tuple in the scan tuple slot of - * the scan state. Eventually we will only do this and not - * return a tuple. Note: we pass 'false' because tuples - * returned by amgetnext are pointers onto disk pages and - * were not created with palloc() and so should not be pfree()'d. - * ---------------- - */ - ExecStoreTuple(tuple, /* tuple to store */ - slot, /* slot to store in */ - buffer, /* buffer associated with tuple */ - false); /* don't pfree */ - - return slot; - } - else - { + if (tuple != NULL) + { + bool prev_matches = false; + int prev_index; + + /* ---------------- + * store the scanned tuple in the scan tuple slot of + * the scan state. Eventually we will only do this and not + * return a tuple. Note: we pass 'false' because tuples + * returned by amgetnext are pointers onto disk pages and + * were not created with palloc() and so should not be pfree()'d. + * ---------------- + */ + ExecStoreTuple(tuple, /* tuple to store */ + slot, /* slot to store in */ + buffer, /* buffer associated with tuple */ + false); /* don't pfree */ + + for (prev_index = 0; prev_index < indexstate->iss_IndexPtr; + prev_index++) + { + if (ExecQual(nth(prev_index, node->indxqual), + scanstate->cstate.cs_ExprContext)) + { + prev_matches = true; + break; + } + } + if (!prev_matches) + return slot; + else + ExecClearTuple(slot); + } if (BufferIsValid(buffer)) ReleaseBuffer(buffer); } + if (indexstate->iss_IndexPtr < numIndices) + indexstate->iss_IndexPtr++; } - /* ---------------- * if we get here it means the index scan failed so we * are at the end of the scan.. @@ -218,7 +230,6 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent) int i; Pointer *runtimeKeyInfo; - int indexPtr; int *numScanKeys; List *indxqual; List *qual; @@ -238,69 +249,62 @@ ExecIndexReScan(IndexScan *node, ExprContext *exprCtxt, Plan *parent) numIndices = indexstate->iss_NumIndices; scanDescs = indexstate->iss_ScanDescs; scanKeys = indexstate->iss_ScanKeys; - runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo; + indxqual = node->indxqual; + numScanKeys = indexstate->iss_NumScanKeys; + indexstate->iss_IndexPtr = 0; + + /* it's possible in subselects */ + if (exprCtxt == NULL) + exprCtxt = node->scan.scanstate->cstate.cs_ExprContext; - if (runtimeKeyInfo != NULL) - { - - /* - * get the index qualifications and recalculate the appropriate - * values - */ - indexPtr = indexstate->iss_IndexPtr; - indxqual = node->indxqual; - qual = nth(indexPtr, indxqual); - numScanKeys = indexstate->iss_NumScanKeys; - n_keys = numScanKeys[indexPtr]; - run_keys = (int *) runtimeKeyInfo[indexPtr]; - scan_keys = (ScanKey) scanKeys[indexPtr]; + if (exprCtxt != NULL) + node->scan.scanstate->cstate.cs_ExprContext->ecxt_outertuple = + exprCtxt->ecxt_outertuple; - /* it's possible in subselects */ - if (exprCtxt == NULL) - exprCtxt = node->scan.scanstate->cstate.cs_ExprContext; - - for (j = 0; j < n_keys; j++) - { - - /* - * If we have a run-time key, then extract the run-time - * expression and evaluate it with respect to the current - * outer tuple. We then stick the result into the scan key. - */ - if (run_keys[j] != NO_OP) - { - clause = nth(j, qual); - scanexpr = (run_keys[j] == RIGHT_OP) ? - (Node *) get_rightop(clause) : (Node *) get_leftop(clause); - - /* - * pass in isDone but ignore it. We don't iterate in - * quals - */ - scanvalue = (Datum) - ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone); - scan_keys[j].sk_argument = scanvalue; - if (isNull) - scan_keys[j].sk_flags |= SK_ISNULL; - else - scan_keys[j].sk_flags &= ~SK_ISNULL; - } - } - } - /* - * rescans all indices - * - * note: AMrescan assumes only one scan key. This may have to change if - * we ever decide to support multiple keys. + * get the index qualifications and recalculate the appropriate + * values */ for (i = 0; i < numIndices; i++) { - sdesc = scanDescs[i]; - skey = scanKeys[i]; - index_rescan(sdesc, direction, skey); - } + if (runtimeKeyInfo && runtimeKeyInfo[i] != NULL) + { + qual = nth(i, indxqual); + n_keys = numScanKeys[i]; + run_keys = (int *) runtimeKeyInfo[i]; + scan_keys = (ScanKey) scanKeys[i]; + + for (j = 0; j < n_keys; j++) + { + /* + * If we have a run-time key, then extract the run-time + * expression and evaluate it with respect to the current + * outer tuple. We then stick the result into the scan key. + */ + if (run_keys[j] != NO_OP) + { + clause = nth(j, qual); + scanexpr = (run_keys[j] == RIGHT_OP) ? + (Node *) get_rightop(clause) : (Node *) get_leftop(clause); + + /* + * pass in isDone but ignore it. We don't iterate in + * quals + */ + scanvalue = (Datum) + ExecEvalExpr(scanexpr, exprCtxt, &isNull, &isDone); + scan_keys[j].sk_argument = scanvalue; + if (isNull) + scan_keys[j].sk_flags |= SK_ISNULL; + else + scan_keys[j].sk_flags &= ~SK_ISNULL; + } + } + sdesc = scanDescs[i]; + skey = scanKeys[i]; + index_rescan(sdesc, direction, skey); + } /* ---------------- * perhaps return something meaningful @@ -322,19 +326,23 @@ ExecEndIndexScan(IndexScan *node) { CommonScanState *scanstate; IndexScanState *indexstate; + Pointer *runtimeKeyInfo; ScanKey *scanKeys; + int *numScanKeys; int numIndices; int i; scanstate = node->scan.scanstate; indexstate = node->indxstate; - + runtimeKeyInfo = (Pointer *) indexstate->iss_RuntimeKeyInfo; + /* ---------------- * extract information from the node * ---------------- */ numIndices = indexstate->iss_NumIndices; scanKeys = indexstate->iss_ScanKeys; + numScanKeys = indexstate->iss_NumScanKeys; /* ---------------- * Free the projection info and the scan attribute info @@ -362,7 +370,24 @@ ExecEndIndexScan(IndexScan *node) if (scanKeys[i] != NULL) pfree(scanKeys[i]); } + pfree(scanKeys); + pfree(numScanKeys); + if (runtimeKeyInfo) + { + for (i = 0; i < numIndices; i++) + { + List *qual; + int n_keys; + + qual = nth(i, indxqual); + n_keys = length(qual); + if (n_keys > 0) + pfree(runtimeKeyInfo[i]); + } + pfree(runtimeKeyInfo); + } + /* ---------------- * clear out tuple table slots * ---------------- @@ -430,7 +455,7 @@ ExecIndexRestrPos(IndexScan *node) /* ---------------------------------------------------------------- * ExecInitIndexScan - * + * * Initializes the index scan's state information, creates * scan keys, and opens the base and index relations. * @@ -886,20 +911,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent) if (have_runtime_keys) indexstate->iss_RuntimeKeyInfo = (Pointer) runtimeKeyInfo; else - { indexstate->iss_RuntimeKeyInfo = NULL; - for (i = 0; i < numIndices; i++) - { - List *qual; - int n_keys; - - qual = nth(i, indxqual); - n_keys = length(qual); - if (n_keys > 0) - pfree(runtimeKeyInfo[i]); - } - pfree(runtimeKeyInfo); - } /* ---------------- * get the range table and direction information @@ -991,6 +1003,5 @@ int ExecCountSlotsIndexScan(IndexScan *node) { return ExecCountSlotsNode(outerPlan((Plan *) node)) + - ExecCountSlotsNode(innerPlan((Plan *) node)) + - INDEXSCAN_NSLOTS; + ExecCountSlotsNode(innerPlan((Plan *) node)) + INDEXSCAN_NSLOTS; } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 518b6f553d..fbaa1298c3 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -1,4 +1,4 @@ -/*------------------------------------------------------------------------- + /*------------------------------------------------------------------------- * * copyfuncs.c-- * Copy functions for Postgres tree nodes. @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.44 1998/07/18 04:22:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.45 1998/08/01 22:12:05 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -990,16 +990,16 @@ _copyArrayRef(ArrayRef *from) */ /* ---------------- - * _copyRel + * _copyRelOptInfo * ---------------- */ /* - ** when you change this, also make sure to fix up xfunc_copyRel in + ** when you change this, also make sure to fix up xfunc_copyRelOptInfo in ** planner/path/xfunc.c accordingly!!! ** -- JMH, 8/2/93 */ static RelOptInfo * -_copyRel(RelOptInfo *from) +_copyRelOptInfo(RelOptInfo *from) { RelOptInfo *newnode = makeNode(RelOptInfo); int i, @@ -1735,7 +1735,7 @@ copyObject(void *from) * RELATION NODES */ case T_RelOptInfo: - retval = _copyRel(from); + retval = _copyRelOptInfo(from); break; case T_Path: retval = _copyPath(from); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 3c6bbe4d30..675cb856bc 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.16 1998/02/26 04:32:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.17 1998/08/01 22:12:07 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -302,6 +302,19 @@ _equalCInfo(CInfo *a, CInfo *b) (b->indexids))); } +/* + * RelOptInfo is a subclass of Node. + */ +static bool +_equalRelOptInfo(RelOptInfo *a, RelOptInfo *b) +{ + Assert(IsA(a, RelOptInfo)); + Assert(IsA(b, RelOptInfo)); + + return (equal((a->relids), + (b->relids))); +} + static bool _equalJoinMethod(JoinMethod *a, JoinMethod *b) { @@ -663,6 +676,9 @@ equal(void *a, void *b) case T_CInfo: retval = _equalCInfo(a, b); break; + case T_RelOptInfo: + retval = _equalRelOptInfo(a, b); + break; case T_JoinMethod: retval = _equalJoinMethod(a, b); break; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index aaa726740f..693039405a 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.41 1998/07/18 04:22:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.42 1998/08/01 22:12:08 momjian Exp $ * * NOTES * Every (plan) node in POSTGRES has an associated "out" routine which @@ -990,7 +990,7 @@ _outEState(StringInfo str, EState *node) * Stuff from relation.h */ static void -_outRel(StringInfo str, RelOptInfo *node) +_outRelOptInfo(StringInfo str, RelOptInfo *node) { char buf[500]; @@ -1788,7 +1788,7 @@ _outNode(StringInfo str, void *obj) _outEState(str, obj); break; case T_RelOptInfo: - _outRel(str, obj); + _outRelOptInfo(str, obj); break; case T_TargetEntry: _outTargetEntry(str, obj); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 39201e2613..61032aaaa5 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.33 1998/07/18 04:22:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.34 1998/08/01 22:12:09 momjian Exp $ * * NOTES * Most of the read functions for plan nodes are tested. (In fact, they @@ -1218,11 +1218,11 @@ _readEState() */ /* ---------------- - * _readRel + * _readRelOptInfo * ---------------- */ static RelOptInfo * -_readRel() +_readRelOptInfo() { RelOptInfo *local_node; char *token; @@ -1991,7 +1991,7 @@ parsePlanString(void) else if (!strncmp(token, "ESTATE", length)) return_value = _readEState(); else if (!strncmp(token, "RELOPTINFO", length)) - return_value = _readRel(); + return_value = _readRelOptInfo(); else if (!strncmp(token, "TARGETENTRY", length)) return_value = _readTargetEntry(); else if (!strncmp(token, "RTE", length)) diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index c372b6ce64..5f495d92a7 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.9 1998/07/18 04:22:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.10 1998/08/01 22:12:11 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -159,19 +159,8 @@ set_rest_selec(Query *root, List *clauseinfo_list) Cost compute_clause_selec(Query *root, Node *clause, List *or_selectivities) { - if (!is_opclause(clause)) - { - - /* - * if it's not an operator clause, then it is a boolean clause - * -jolly - */ - - /* - * Boolean variables get a selectivity of 1/2. - */ - return (0.1); - } + if (is_opclause (clause)) + return compute_selec(root, lcons(clause,NIL), or_selectivities); else if (not_clause(clause)) { diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 3722688a21..b557d9d59b 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.19 1998/07/31 15:10:40 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.20 1998/08/01 22:12:12 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "access/nbtree.h" #include "catalog/catname.h" #include "catalog/pg_amop.h" +#include "catalog/pg_type.h" #include "executor/executor.h" #include "fmgr.h" #include "nodes/makefuncs.h" @@ -77,10 +78,7 @@ create_index_paths(Query *root, RelOptInfo *rel, RelOptInfo *index, List *clausegroup_list, bool join); static List *add_index_paths(List *indexpaths, List *new_indexpaths); static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index); -static bool SingleAttributeIndex(RelOptInfo *index); -/* If Spyros can use a constant PRS2_BOOL_TYPEID, I can use this */ -#define BOOL_TYPEID ((Oid) 16) /* * find-index-paths-- @@ -121,91 +119,82 @@ find_index_paths(Query *root, List *joinclausegroups = NIL; List *joinpaths = NIL; List *retval = NIL; - - if (indices == NIL) - return (NULL); - - index = (RelOptInfo *) lfirst(indices); - - retval = find_index_paths(root, - rel, - lnext(indices), - clauseinfo_list, - joininfo_list); - - /* If this is a partial index, return if it fails the predicate test */ - if (index->indpred != NIL) - if (!pred_test(index->indpred, clauseinfo_list, joininfo_list)) - return retval; - - /* - * 1. If this index has only one key, try matching it against - * subclauses of an 'or' clause. The fields of the clauseinfo nodes - * are marked with lists of the matching indices no path are actually - * created. - * - * XXX NOTE: Currently btrees dos not support indices with > 1 key, so - * the following test will always be true for now but we have decided - * not to support index-scans on disjunction . -- lp - */ - if (SingleAttributeIndex(index)) + List *ilist; + + foreach(ilist, indices) { + index = (RelOptInfo *) lfirst(ilist); + + /* If this is a partial index, return if it fails the predicate test */ + if (index->indpred != NIL) + if (!pred_test(index->indpred, clauseinfo_list, joininfo_list)) + continue; + + /* + * 1. Try matching the index against subclauses of an 'or' clause. + * The fields of the clauseinfo nodes are marked with lists of the + * matching indices. No path are actually created. We currently + * only look to match the first key. We don't find multi-key index + * cases where an AND matches the first key, and the OR matches the + * second key. + */ match_index_orclauses(rel, - index, - index->indexkeys[0], - index->classlist[0], - clauseinfo_list); + index, + index->indexkeys[0], + index->classlist[0], + clauseinfo_list); + } + + /* + * 2. If the keys of this index match any of the available restriction + * clauses, then create pathnodes corresponding to each group of + * usable clauses. + */ + scanclausegroups = group_clauses_by_indexkey(rel, + index, + index->indexkeys, + index->classlist, + clauseinfo_list); + + scanpaths = NIL; + if (scanclausegroups != NIL) + scanpaths = create_index_paths(root, + rel, + index, + scanclausegroups, + false); + + /* + * 3. If this index can be used with any join clause, then create + * pathnodes for each group of usable clauses. An index can be used + * with a join clause if its ordering is useful for a mergejoin, or if + * the index can possibly be used for scanning the inner relation of a + * nestloop join. + */ + joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list); + joinpaths = NIL; + + if (joinclausegroups != NIL) + { + List *new_join_paths = create_index_paths(root, rel, + index, + joinclausegroups, + true); + List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index); + + rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths); + joinpaths = new_join_paths; + } + + /* + * Some sanity checks to make sure that the indexpath is valid. + */ + if (joinpaths != NULL) + retval = add_index_paths(joinpaths, retval); + if (scanpaths != NULL) + retval = add_index_paths(scanpaths, retval); } - - /* - * 2. If the keys of this index match any of the available restriction - * clauses, then create pathnodes corresponding to each group of - * usable clauses. - */ - scanclausegroups = group_clauses_by_indexkey(rel, - index, - index->indexkeys, - index->classlist, - clauseinfo_list); - - scanpaths = NIL; - if (scanclausegroups != NIL) - scanpaths = create_index_paths(root, - rel, - index, - scanclausegroups, - false); - - /* - * 3. If this index can be used with any join clause, then create - * pathnodes for each group of usable clauses. An index can be used - * with a join clause if its ordering is useful for a mergejoin, or if - * the index can possibly be used for scanning the inner relation of a - * nestloop join. - */ - joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, clauseinfo_list); - joinpaths = NIL; - - if (joinclausegroups != NIL) - { - List *new_join_paths = create_index_paths(root, rel, - index, - joinclausegroups, - true); - List *innerjoin_paths = index_innerjoin(root, rel, joinclausegroups, index); - - rel->innerjoin = nconc(rel->innerjoin, innerjoin_paths); - joinpaths = new_join_paths; - } - - /* - * Some sanity checks to make sure that the indexpath is valid. - */ - if (joinpaths != NULL) - retval = add_index_paths(joinpaths, retval); - if (scanpaths != NULL) - retval = add_index_paths(scanpaths, retval); - + return retval; } @@ -297,7 +286,7 @@ match_index_to_operand(int indexkey, * (1) the operator within the subclause can be used with one * of the index's operator classes, and * (2) there is a usable key that matches the variable within a - * sargable clause. + * searchable clause. * * 'or-clauses' are the remaining subclauses within the 'or' clause * 'other-matching-indices' is the list of information on other indices @@ -322,30 +311,31 @@ match_index_orclause(RelOptInfo *rel, List *matched_indices = other_matching_indices; List *index_list = NIL; List *clist; - List *ind; - if (!matched_indices) - matched_indices = lcons(NIL, NIL); - - for (clist = or_clauses, ind = matched_indices; - clist; - clist = lnext(clist), ind = lnext(ind)) + foreach(clist, or_clauses) { clause = lfirst(clist); if (is_opclause(clause) && op_class(((Oper *) ((Expr *) clause)->oper)->opno, xclass, index->relam) && - match_index_to_operand(indexkey, + ((match_index_to_operand(indexkey, (Expr *) get_leftop((Expr *) clause), rel, index) && - IsA(get_rightop((Expr *) clause), Const)) + IsA(get_rightop((Expr *) clause), Const)) || + (match_index_to_operand(indexkey, + (Expr *) get_leftop((Expr *) clause), + rel, + index) && + IsA(get_rightop((Expr *) clause), Const)))) { - matched_indices = lcons(index, matched_indices); - index_list = lappend(index_list, - matched_indices); } + index_list = lappend(index_list, matched_indices); + + /* for the first index, we are creating the indexids list */ + if (matched_indices) + matched_indices = lnext(matched_indices); } return (index_list); @@ -1061,7 +1051,7 @@ clause_pred_clause_test(Expr *predicate, Node *clause) */ test_oper = makeOper(test_op, /* opno */ InvalidOid, /* opid */ - BOOL_TYPEID, /* opresulttype */ + BOOLOID, /* opresulttype */ 0, /* opsize */ NULL); /* op_fcache */ replace_opid(test_oper); @@ -1176,7 +1166,8 @@ extract_restrict_clauses(List *clausegroup) * */ static List * -index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list, RelOptInfo *index) +index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list, + RelOptInfo *index) { List *clausegroup = NIL; List *cg_list = NIL; @@ -1366,29 +1357,3 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index) return true; } - -static bool -SingleAttributeIndex(RelOptInfo *index) -{ - - /* - * return false for now as I don't know if we support index scans on - * disjunction and the code doesn't work - */ - return (false); - -#if 0 - - /* - * Non-functional indices. - */ - if (index->indproc == InvalidOid) - return (index->indexkeys[0] != 0 && - index->indexkeys[1] == 0); - - /* - * We have a functional index which is a single attr index - */ - return true; -#endif -} diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c index c697078e1b..7f220fc54b 100644 --- a/src/backend/optimizer/path/orindxpath.c +++ b/src/backend/optimizer/path/orindxpath.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.7 1998/07/18 04:22:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.8 1998/08/01 22:12:13 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -55,10 +55,11 @@ create_or_index_paths(Query *root, RelOptInfo *rel, List *clauses) { List *t_list = NIL; + List *clist; - if (clauses != NIL) + foreach(clist, clauses) { - CInfo *clausenode = (CInfo *) (lfirst(clauses)); + CInfo *clausenode = (CInfo *) (lfirst(clist)); /* * Check to see if this clause is an 'or' clause, and, if so, @@ -77,8 +78,11 @@ create_or_index_paths(Query *root, index_list = clausenode->indexids; foreach(temp, index_list) { - if (!temp) + if (!lfirst(temp)) + { index_flag = false; + break; + } } if (index_flag) { /* used to be a lisp every function */ @@ -100,8 +104,7 @@ create_or_index_paths(Query *root, pathnode->path.pathtype = T_IndexScan; pathnode->path.parent = rel; - pathnode->indexqual = - lcons(clausenode, NIL); + pathnode->indexqual = lcons(clausenode, NIL); pathnode->indexid = indexids; pathnode->path.path_cost = cost; @@ -110,9 +113,8 @@ create_or_index_paths(Query *root, * processing -- JMH, 7/7/92 */ pathnode->path.locclauseinfo = - set_difference(clauses, - copyObject((Node *) - rel->clauseinfo)); + set_difference(copyObject((Node *)rel->clauseinfo), + lcons(clausenode,NIL)); #if 0 /* fix xfunc */ /* add in cost for expensive functions! -- JMH, 7/7/92 */ @@ -123,12 +125,8 @@ create_or_index_paths(Query *root, } #endif clausenode->selectivity = (Cost) floatVal(selecs); - t_list = - lcons(pathnode, - create_or_index_paths(root, rel, lnext(clauses))); + t_list = lappend(t_list, pathnode); } - else - t_list = create_or_index_paths(root, rel, lnext(clauses)); } } @@ -167,32 +165,28 @@ best_or_subclause_indices(Query *root, Cost *cost, /* return value */ List **selecs) /* return value */ { - if (subclauses == NIL) - { - *indexids = nreverse(examined_indexids); - *cost = subcost; - *selecs = nreverse(selectivities); - } - else + List *slist; + + foreach (slist, subclauses) { int best_indexid; Cost best_cost; Cost best_selec; - best_or_subclause_index(root, rel, lfirst(subclauses), lfirst(indices), + best_or_subclause_index(root, rel, lfirst(slist), lfirst(indices), &best_indexid, &best_cost, &best_selec); + + examined_indexids = lappendi(examined_indexids, best_indexid); + subcost += best_cost; + selectivities = lappend(selectivities, makeFloat(best_selec)); - best_or_subclause_indices(root, - rel, - lnext(subclauses), - lnext(indices), - lconsi(best_indexid, examined_indexids), - subcost + best_cost, - lcons(makeFloat(best_selec), selectivities), - indexids, - cost, - selecs); + indices = lnext(indices); } + + *indexids = examined_indexids; + *cost = subcost; + *selecs = selectivities; + return; } @@ -219,20 +213,21 @@ best_or_subclause_index(Query *root, Cost *retCost, /* return value */ Cost *retSelec) /* return value */ { - if (indices != NIL) + List *ilist; + bool first_run = true; + + foreach (ilist, indices) { + RelOptInfo *index = (RelOptInfo *) lfirst(ilist); + Datum value; int flag = 0; Cost subcost; - RelOptInfo *index = (RelOptInfo *) lfirst(indices); AttrNumber attno = (get_leftop(subclause))->varattno; Oid opno = ((Oper *) subclause->oper)->opno; bool constant_on_right = non_null((Expr *) get_rightop(subclause)); float npages, selec; - int subclause_indexid; - Cost subclause_cost; - Cost subclause_selec; if (constant_on_right) value = ((Const *) get_rightop(subclause))->constvalue; @@ -242,6 +237,7 @@ best_or_subclause_index(Query *root, flag = (_SELEC_IS_CONSTANT_ || _SELEC_CONSTANT_RIGHT_); else flag = _SELEC_CONSTANT_RIGHT_; + index_selectivity(lfirsti(index->relids), index->classlist, lconsi(opno, NIL), @@ -262,26 +258,22 @@ best_or_subclause_index(Query *root, index->pages, index->tuples, false); - best_or_subclause_index(root, - rel, - subclause, - lnext(indices), - &subclause_indexid, - &subclause_cost, - &subclause_selec); - if (subclause_indexid == 0 || subcost < subclause_cost) + if (first_run || subcost < *retCost) { *retIndexid = lfirsti(index->relids); *retCost = subcost; *retSelec = selec; + first_run = false; } - else - { - *retIndexid = 0; - *retCost = 0.0; - *retSelec = 0.0; - } + } + + /* we didn't get any indexes, so zero return values */ + if (first_run) + { + *retIndexid = 0; + *retCost = 0.0; + *retSelec = 0.0; } return; }