diff options
Diffstat (limited to 'src/backend/optimizer/path/indxpath.c')
-rw-r--r-- | src/backend/optimizer/path/indxpath.c | 168 |
1 files changed, 108 insertions, 60 deletions
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 13bf65e6990..27ae4056d99 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.92 2000/08/08 15:41:30 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.93 2000/08/13 02:50:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -649,7 +649,7 @@ group_clauses_by_ikey_for_joins(RelOptInfo *rel, * a key of an index. * * To match, the clause: - + * * (1a) for a restriction clause: must be in the form (indexkey op const) * or (const op indexkey), or * (1b) for a join clause: must be in the form (indexkey op others) @@ -708,11 +708,11 @@ match_clause_to_indexkey(RelOptInfo *rel, /* * Not considering joins, so check for clauses of the form: * (indexkey operator constant) or (constant operator indexkey). - * We will accept a Param as being constant. + * Anything that is a "pseudo constant" expression will do. */ - if ((IsA(rightop, Const) ||IsA(rightop, Param)) && - match_index_to_operand(indexkey, leftop, rel, index)) + if (match_index_to_operand(indexkey, leftop, rel, index) && + is_pseudo_constant_clause((Node *) rightop)) { if (is_indexable_operator(clause, opclass, index->relam, true)) return true; @@ -726,8 +726,8 @@ match_clause_to_indexkey(RelOptInfo *rel, return true; return false; } - if ((IsA(leftop, Const) ||IsA(leftop, Param)) && - match_index_to_operand(indexkey, rightop, rel, index)) + if (match_index_to_operand(indexkey, rightop, rel, index) && + is_pseudo_constant_clause((Node *) leftop)) { if (is_indexable_operator(clause, opclass, index->relam, false)) return true; @@ -748,29 +748,32 @@ match_clause_to_indexkey(RelOptInfo *rel, /* * Check for an indexqual that could be handled by a nestloop * join. We need the index key to be compared against an - * expression that uses none of the indexed relation's vars. + * expression that uses none of the indexed relation's vars + * and contains no non-cachable functions. */ if (match_index_to_operand(indexkey, leftop, rel, index)) { List *othervarnos = pull_varnos((Node *) rightop); bool isIndexable; - isIndexable = !intMember(lfirsti(rel->relids), othervarnos); + isIndexable = + !intMember(lfirsti(rel->relids), othervarnos) && + !contain_noncachable_functions((Node *) rightop) && + is_indexable_operator(clause, opclass, index->relam, true); freeList(othervarnos); - if (isIndexable && - is_indexable_operator(clause, opclass, index->relam, true)) - return true; + return isIndexable; } else if (match_index_to_operand(indexkey, rightop, rel, index)) { List *othervarnos = pull_varnos((Node *) leftop); bool isIndexable; - isIndexable = !intMember(lfirsti(rel->relids), othervarnos); + isIndexable = + !intMember(lfirsti(rel->relids), othervarnos) && + !contain_noncachable_functions((Node *) leftop) && + is_indexable_operator(clause, opclass, index->relam, false); freeList(othervarnos); - if (isIndexable && - is_indexable_operator(clause, opclass, index->relam, false)) - return true; + return isIndexable; } } @@ -790,7 +793,9 @@ match_clause_to_indexkey(RelOptInfo *rel, * recognizing binary-compatible datatypes. For example, if we have * an expression like "oid = 123", the operator will be oideqint4, * which we need to replace with oideq in order to recognize it as - * matching an oid_ops index on the oid field. + * matching an oid_ops index on the oid field. A variant case is where + * the expression is like "oid::int4 = 123", where the given operator + * will be int4eq and again we need to intuit that we want to use oideq. * * Returns the OID of the matching operator, or InvalidOid if no match. * Note that the returned OID will be different from the one in the given @@ -804,8 +809,13 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam, { Oid expr_op = ((Oper *) clause->oper)->opno; Oid commuted_op; + Operator oldop, + newop; + Form_pg_operator oldopform; + char *opname; Oid ltype, - rtype; + rtype, + indexkeytype; /* Get the commuted operator if necessary */ if (indexkey_on_left) @@ -821,48 +831,72 @@ indexable_operator(Expr *clause, Oid opclass, Oid relam, /* * Maybe the index uses a binary-compatible operator set. + * + * Get the nominal input types of the given operator and the actual + * type (before binary-compatible relabeling) of the index key. */ - ltype = exprType((Node *) get_leftop(clause)); - rtype = exprType((Node *) get_rightop(clause)); + oldop = get_operator_tuple(expr_op); + if (! HeapTupleIsValid(oldop)) + return InvalidOid; /* probably can't happen */ + oldopform = (Form_pg_operator) GETSTRUCT(oldop); + opname = NameStr(oldopform->oprname); + ltype = oldopform->oprleft; + rtype = oldopform->oprright; + + if (indexkey_on_left) + { + Node *leftop = (Node *) get_leftop(clause); + + if (leftop && IsA(leftop, RelabelType)) + leftop = ((RelabelType *) leftop)->arg; + indexkeytype = exprType(leftop); + } + else + { + Node *rightop = (Node *) get_rightop(clause); + + if (rightop && IsA(rightop, RelabelType)) + rightop = ((RelabelType *) rightop)->arg; + indexkeytype = exprType(rightop); + } /* - * make sure we have two different binary-compatible types... + * Make sure we have different but binary-compatible types. */ - if (ltype != rtype && IS_BINARY_COMPATIBLE(ltype, rtype)) - { - char *opname = get_opname(expr_op); - Operator newop; + if (ltype == indexkeytype && rtype == indexkeytype) + return InvalidOid; /* no chance for a different operator */ + if (ltype != indexkeytype && !IS_BINARY_COMPATIBLE(ltype, indexkeytype)) + return InvalidOid; + if (rtype != indexkeytype && !IS_BINARY_COMPATIBLE(rtype, indexkeytype)) + return InvalidOid; - if (opname == NULL) - return InvalidOid; /* probably shouldn't happen */ + /* + * OK, look for operator of the same name with the indexkey's data type. + * (In theory this might find a non-semantically-comparable operator, + * but in practice that seems pretty unlikely for binary-compatible types.) + */ + newop = oper(opname, indexkeytype, indexkeytype, TRUE); - /* Use the datatype of the index key */ - if (indexkey_on_left) - newop = oper(opname, ltype, ltype, TRUE); - else - newop = oper(opname, rtype, rtype, TRUE); + if (HeapTupleIsValid(newop)) + { + Oid new_expr_op = oprid(newop); - if (HeapTupleIsValid(newop)) + if (new_expr_op != expr_op) { - Oid new_expr_op = oprid(newop); - - if (new_expr_op != expr_op) - { - /* - * OK, we found a binary-compatible operator of the same - * name; now does it match the index? - */ - if (indexkey_on_left) - commuted_op = new_expr_op; - else - commuted_op = get_commutator(new_expr_op); - if (commuted_op == InvalidOid) - return InvalidOid; - - if (op_class(commuted_op, opclass, relam)) - return new_expr_op; - } + /* + * OK, we found a binary-compatible operator of the same + * name; now does it match the index? + */ + if (indexkey_on_left) + commuted_op = new_expr_op; + else + commuted_op = get_commutator(new_expr_op); + if (commuted_op == InvalidOid) + return InvalidOid; + + if (op_class(commuted_op, opclass, relam)) + return new_expr_op; } } @@ -1526,13 +1560,22 @@ match_index_to_operand(int indexkey, RelOptInfo *rel, IndexOptInfo *index) { + /* + * Ignore any RelabelType node above the indexkey. This is needed to + * be able to apply indexscanning in binary-compatible-operator cases. + * Note: we can assume there is at most one RelabelType node; + * eval_const_expressions() will have simplified if more than one. + */ + if (operand && IsA(operand, RelabelType)) + operand = (Var *) ((RelabelType *) operand)->arg; + if (index->indproc == InvalidOid) { /* - * Normal index. + * Simple index. */ - if (IsA(operand, Var) && + if (operand && IsA(operand, Var) && lfirsti(rel->relids) == operand->varno && indexkey == operand->varattno) return true; @@ -1541,7 +1584,7 @@ match_index_to_operand(int indexkey, } /* - * functional index check + * Functional index. */ return function_index_operand((Expr *) operand, rel, index); } @@ -1570,18 +1613,23 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index) if (function->funcid != index->indproc) return false; - /* + /*---------- * Check that the arguments correspond to the same arguments used to - * create the functional index. To do this we must check that 1. - * refer to the right relation. 2. the args have the right attr. - * numbers in the right order. + * create the functional index. To do this we must check that + * 1. they refer to the right relation. + * 2. the args have the right attr. numbers in the right order. + * We must ignore RelabelType nodes above the argument Vars in order + * to recognize binary-compatible-function cases correctly. + *---------- */ i = 0; foreach(arg, funcargs) { Var *var = (Var *) lfirst(arg); - if (!IsA(var, Var)) + if (var && IsA(var, RelabelType)) + var = (Var *) ((RelabelType *) var)->arg; + if (var == NULL || !IsA(var, Var)) return false; if (indexKeys[i] == 0) return false; @@ -1643,7 +1691,7 @@ function_index_operand(Expr *funcOpnd, RelOptInfo *rel, IndexOptInfo *index) * additional indexscanable qualifications. * * The given clause is already known to be a binary opclause having - * the form (indexkey OP const/param) or (const/param OP indexkey), + * the form (indexkey OP pseudoconst) or (pseudoconst OP indexkey), * but the OP proved not to be one of the index's opclass operators. * Return 'true' if we can do something with it anyway. */ |