indxpath.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:38k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * indxpath.c
  4.  *   Routines to determine which indices are usable for scanning a
  5.  *   given relation
  6.  *
  7.  * Copyright (c) 1994, Regents of the University of California
  8.  *
  9.  *
  10.  * IDENTIFICATION
  11.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.57.2.1 1999/09/14 20:26:02 tgl Exp $
  12.  *
  13.  *-------------------------------------------------------------------------
  14.  */
  15. #include <math.h>
  16. #include "postgres.h"
  17. #include "access/attnum.h"
  18. #include "access/heapam.h"
  19. #include "access/nbtree.h"
  20. #include "catalog/catname.h"
  21. #include "catalog/pg_amop.h"
  22. #include "catalog/pg_type.h"
  23. #include "executor/executor.h"
  24. #include "fmgr.h"
  25. #include "nodes/makefuncs.h"
  26. #include "nodes/nodeFuncs.h"
  27. #include "nodes/pg_list.h"
  28. #include "nodes/relation.h"
  29. #include "optimizer/clauses.h"
  30. #include "optimizer/restrictinfo.h"
  31. #include "optimizer/cost.h"
  32. #include "optimizer/internal.h"
  33. #include "optimizer/keys.h"
  34. #include "optimizer/ordering.h"
  35. #include "optimizer/paths.h"
  36. #include "optimizer/plancat.h"
  37. #include "optimizer/pathnode.h"
  38. #include "optimizer/xfunc.h"
  39. #include "parser/parsetree.h" /* for getrelid() */
  40. #include "parser/parse_expr.h" /* for exprType() */
  41. #include "parser/parse_oper.h" /* for oprid() and oper() */
  42. #include "parser/parse_coerce.h"/* for IS_BINARY_COMPATIBLE() */
  43. #include "utils/lsyscache.h"
  44. static void match_index_orclauses(RelOptInfo *rel, RelOptInfo *index, int indexkey,
  45.   int xclass, List *restrictinfo_list);
  46. static bool match_index_to_operand(int indexkey, Expr *operand,
  47.    RelOptInfo *rel, RelOptInfo *index);
  48. static List *match_index_orclause(RelOptInfo *rel, RelOptInfo *index, int indexkey,
  49.  int xclass, List *or_clauses, List *other_matching_indices);
  50. static List *group_clauses_by_indexkey(RelOptInfo *rel, RelOptInfo *index,
  51.   int *indexkeys, Oid *classes, List *restrictinfo_list);
  52. static List *group_clauses_by_ikey_for_joins(RelOptInfo *rel, RelOptInfo *index,
  53. int *indexkeys, Oid *classes, List *join_cinfo_list, List *restr_cinfo_list);
  54. static RestrictInfo *match_clause_to_indexkey(RelOptInfo *rel, RelOptInfo *index, int indexkey,
  55.   int xclass, RestrictInfo *restrictInfo, bool join);
  56. static bool pred_test(List *predicate_list, List *restrictinfo_list,
  57.   List *joininfo_list);
  58. static bool one_pred_test(Expr *predicate, List *restrictinfo_list);
  59. static bool one_pred_clause_expr_test(Expr *predicate, Node *clause);
  60. static bool one_pred_clause_test(Expr *predicate, Node *clause);
  61. static bool clause_pred_clause_test(Expr *predicate, Node *clause);
  62. static List *indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
  63.   List *joininfo_list, List *restrictinfo_list);
  64. static List *index_innerjoin(Query *root, RelOptInfo *rel,
  65. List *clausegroup_list, RelOptInfo *index);
  66. static List *create_index_path_group(Query *root, RelOptInfo *rel, RelOptInfo *index,
  67. List *clausegroup_list, bool join);
  68. static List *add_index_paths(List *indexpaths, List *new_indexpaths);
  69. static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index);
  70. /* find_index_paths()
  71.  *   Finds all possible index paths by determining which indices in the
  72.  *   list 'indices' are usable.
  73.  *
  74.  *   To be usable, an index must match against either a set of
  75.  *   restriction clauses or join clauses.
  76.  *
  77.  *   Note that the current implementation requires that there exist
  78.  *   matching clauses for every key in the index (i.e., no partial
  79.  *   matches are allowed).
  80.  *
  81.  *   If an index can't be used with restriction clauses, but its keys
  82.  *   match those of the result sort order (according to information stored
  83.  *   within 'sortkeys'), then the index is also considered.
  84.  *
  85.  * 'rel' is the relation entry to which these index paths correspond
  86.  * 'indices' is a list of possible index paths
  87.  * 'restrictinfo_list' is a list of restriction restrictinfo nodes for 'rel'
  88.  * 'joininfo_list' is a list of joininfo nodes for 'rel'
  89.  * 'sortkeys' is a node describing the result sort order (from
  90.  * (find_sortkeys))
  91.  *
  92.  * Returns a list of index nodes.
  93.  *
  94.  */
  95. List *
  96. create_index_paths(Query *root,
  97.    RelOptInfo *rel,
  98.    List *indices,
  99.    List *restrictinfo_list,
  100.    List *joininfo_list)
  101. {
  102. List    *scanclausegroups = NIL;
  103. List    *scanpaths = NIL;
  104. RelOptInfo *index = (RelOptInfo *) NULL;
  105. List    *joinclausegroups = NIL;
  106. List    *joinpaths = NIL;
  107. List    *retval = NIL;
  108. List    *ilist;
  109. foreach(ilist, indices)
  110. {
  111. index = (RelOptInfo *) lfirst(ilist);
  112. /*
  113.  * If this is a partial index, return if it fails the predicate
  114.  * test
  115.  */
  116. if (index->indpred != NIL)
  117. if (!pred_test(index->indpred, restrictinfo_list, joininfo_list))
  118. continue;
  119. /*
  120.  * 1. Try matching the index against subclauses of an 'or' clause.
  121.  * The fields of the restrictinfo nodes are marked with lists of
  122.  * the matching indices.  No path are actually created.  We
  123.  * currently only look to match the first key. We don't find
  124.  * multi-key index cases where an AND matches the first key, and
  125.  * the OR matches the second key.
  126.  */
  127. match_index_orclauses(rel,
  128.   index,
  129.   index->indexkeys[0],
  130.   index->classlist[0],
  131.   restrictinfo_list);
  132. /*
  133.  * 2. If the keys of this index match any of the available
  134.  * restriction clauses, then create pathnodes corresponding to
  135.  * each group of usable clauses.
  136.  */
  137. scanclausegroups = group_clauses_by_indexkey(rel,
  138.  index,
  139.  index->indexkeys,
  140.  index->classlist,
  141.  restrictinfo_list);
  142. scanpaths = NIL;
  143. if (scanclausegroups != NIL)
  144. scanpaths = create_index_path_group(root,
  145. rel,
  146. index,
  147. scanclausegroups,
  148. false);
  149. /*
  150.  * 3. If this index can be used with any join clause, then create
  151.  * pathnodes for each group of usable clauses. An index can be
  152.  * used with a join clause if its ordering is useful for a
  153.  * mergejoin, or if the index can possibly be used for scanning
  154.  * the inner relation of a nestloop join.
  155.  */
  156. joinclausegroups = indexable_joinclauses(rel, index, joininfo_list, restrictinfo_list);
  157. joinpaths = NIL;
  158. if (joinclausegroups != NIL)
  159. {
  160. joinpaths = create_index_path_group(root, rel,
  161. index,
  162. joinclausegroups,
  163. true);
  164. rel->innerjoin = nconc(rel->innerjoin,
  165.    index_innerjoin(root, rel,
  166.    joinclausegroups, index));
  167. }
  168. /*
  169.  * Some sanity checks to make sure that the indexpath is valid.
  170.  */
  171. if (joinpaths != NULL)
  172. retval = add_index_paths(joinpaths, retval);
  173. if (scanpaths != NULL)
  174. retval = add_index_paths(scanpaths, retval);
  175. }
  176. return retval;
  177. }
  178. /****************************************************************************
  179.  * ----  ROUTINES TO MATCH 'OR' CLAUSES  ----
  180.  ****************************************************************************/
  181. /*
  182.  * match_index_orclauses
  183.  *   Attempt to match an index against subclauses within 'or' clauses.
  184.  *   If the index does match, then the clause is marked with information
  185.  *   about the index.
  186.  *
  187.  *   Essentially, this adds 'index' to the list of indices in the
  188.  *   RestrictInfo field of each of the clauses which it matches.
  189.  *
  190.  * 'rel' is the node of the relation on which the index is defined.
  191.  * 'index' is the index node.
  192.  * 'indexkey' is the (single) key of the index
  193.  * 'class' is the class of the operator corresponding to 'indexkey'.
  194.  * 'restrictinfo_list' is the list of available restriction clauses.
  195.  *
  196.  * Returns nothing.
  197.  *
  198.  */
  199. static void
  200. match_index_orclauses(RelOptInfo *rel,
  201.   RelOptInfo *index,
  202.   int indexkey,
  203.   int xclass,
  204.   List *restrictinfo_list)
  205. {
  206. RestrictInfo *restrictinfo = (RestrictInfo *) NULL;
  207. List    *i = NIL;
  208. foreach(i, restrictinfo_list)
  209. {
  210. restrictinfo = (RestrictInfo *) lfirst(i);
  211. if (valid_or_clause(restrictinfo))
  212. {
  213. /*
  214.  * Mark the 'or' clause with a list of indices which match
  215.  * each of its subclauses. The list is generated by adding
  216.  * 'index' to the existing list where appropriate.
  217.  */
  218. restrictinfo->indexids = match_index_orclause(rel, index, indexkey,
  219.   xclass,
  220.   restrictinfo->clause->args,
  221.  restrictinfo->indexids);
  222. }
  223. }
  224. }
  225. /* match_index_to_operand()
  226.  *   Generalize test for a match between an existing index's key
  227.  *   and the operand on the rhs of a restriction clause.  Now check
  228.  *   for functional indices as well.
  229.  */
  230. static bool
  231. match_index_to_operand(int indexkey,
  232.    Expr *operand,
  233.    RelOptInfo *rel,
  234.    RelOptInfo *index)
  235. {
  236. bool result;
  237. /*
  238.  * Normal index.
  239.  */
  240. if (index->indproc == InvalidOid)
  241. {
  242. result = match_indexkey_operand(indexkey, (Var *) operand, rel);
  243. return result;
  244. }
  245. /*
  246.  * functional index check
  247.  */
  248. result = function_index_operand(operand, rel, index);
  249. return result;
  250. }
  251. /*
  252.  * match_index_orclause
  253.  *   Attempts to match an index against the subclauses of an 'or' clause.
  254.  *
  255.  *   A match means that:
  256.  *   (1) the operator within the subclause can be used with one
  257.  * of the index's operator classes, and
  258.  *   (2) there is a usable key that matches the variable within a
  259.  * searchable clause.
  260.  *
  261.  * 'or_clauses' are the remaining subclauses within the 'or' clause
  262.  * 'other_matching_indices' is the list of information on other indices
  263.  * that have already been matched to subclauses within this
  264.  * particular 'or' clause (i.e., a list previously generated by
  265.  * this routine)
  266.  *
  267.  * Returns a list of the form ((a b c) (d e f) nil (g h) ...) where
  268.  * a,b,c are nodes of indices that match the first subclause in
  269.  * 'or-clauses', d,e,f match the second subclause, no indices
  270.  * match the third, g,h match the fourth, etc.
  271.  */
  272. static List *
  273. match_index_orclause(RelOptInfo *rel,
  274.  RelOptInfo *index,
  275.  int indexkey,
  276.  int xclass,
  277.  List *or_clauses,
  278.  List *other_matching_indices)
  279. {
  280. Node    *clause = NULL;
  281. List    *matching_indices = other_matching_indices;
  282. List    *index_list = NIL;
  283. List    *clist;
  284. /* first time through, we create index list */
  285. if (!other_matching_indices)
  286. {
  287. foreach(clist, or_clauses)
  288. matching_indices = lcons(NIL, matching_indices);
  289. }
  290. else
  291. matching_indices = other_matching_indices;
  292. index_list = matching_indices;
  293. foreach(clist, or_clauses)
  294. {
  295. clause = lfirst(clist);
  296. if (is_opclause(clause))
  297. {
  298. Expr    *left = (Expr *) get_leftop((Expr *) clause);
  299. Expr    *right = (Expr *) get_rightop((Expr *) clause);
  300. if (left && right &&
  301. op_class(((Oper *) ((Expr *) clause)->oper)->opno,
  302.  xclass, index->relam) &&
  303. ((IsA(right, Const) &&
  304.   match_index_to_operand(indexkey, left, rel, index)) ||
  305.  (IsA(left, Const) &&
  306.   match_index_to_operand(indexkey, right, rel, index))))
  307. lfirst(matching_indices) = lcons(index,
  308.    lfirst(matching_indices));
  309. }
  310. matching_indices = lnext(matching_indices);
  311. }
  312. return index_list;
  313. }
  314. /****************************************************************************
  315.  * ----  ROUTINES TO CHECK RESTRICTIONS  ----
  316.  ****************************************************************************/
  317. /*
  318.  * DoneMatchingIndexKeys() - MACRO
  319.  *
  320.  * Determine whether we should continue matching index keys in a clause.
  321.  * Depends on if there are more to match or if this is a functional index.
  322.  * In the latter case we stop after the first match since the there can
  323.  * be only key (i.e. the function's return value) and the attributes in
  324.  * keys list represent the arguments to the function.  -mer 3 Oct. 1991
  325.  */
  326. #define DoneMatchingIndexKeys(indexkeys, index) 
  327. (indexkeys[0] == 0 || 
  328.  (index->indproc != InvalidOid))
  329. /*
  330.  * group_clauses_by_indexkey
  331.  *   Determines whether there are clauses which will match each and every
  332.  *   one of the remaining keys of an index.
  333.  *
  334.  * 'rel' is the node of the relation corresponding to the index.
  335.  * 'indexkeys' are the remaining index keys to be matched.
  336.  * 'classes' are the classes of the index operators on those keys.
  337.  * 'clauses' is either:
  338.  * (1) the list of available restriction clauses on a single
  339.  * relation, or
  340.  * (2) a list of join clauses between 'rel' and a fixed set of
  341.  * relations,
  342.  * depending on the value of 'join'.
  343.  *
  344.  * NOTE: it works now for restriction clauses only. - vadim 03/18/97
  345.  *
  346.  * Returns all possible groups of clauses that will match (given that
  347.  * one or more clauses can match any of the remaining keys).
  348.  * E.g., if you have clauses A, B, and C, ((A B) (A C)) might be
  349.  * returned for an index with 2 keys.
  350.  *
  351.  */
  352. static List *
  353. group_clauses_by_indexkey(RelOptInfo *rel,
  354.   RelOptInfo *index,
  355.   int *indexkeys,
  356.   Oid *classes,
  357.   List *restrictinfo_list)
  358. {
  359. List    *curCinfo = NIL;
  360. RestrictInfo *matched_clause = (RestrictInfo *) NULL;
  361. List    *clausegroup = NIL;
  362. int curIndxKey;
  363. Oid curClass;
  364. if (restrictinfo_list == NIL || indexkeys[0] == 0)
  365. return NIL;
  366. do
  367. {
  368. List    *tempgroup = NIL;
  369. curIndxKey = indexkeys[0];
  370. curClass = classes[0];
  371. foreach(curCinfo, restrictinfo_list)
  372. {
  373. RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo);
  374. matched_clause = match_clause_to_indexkey(rel,
  375.   index,
  376.   curIndxKey,
  377.   curClass,
  378.   temp,
  379.   false);
  380. if (!matched_clause)
  381. continue;
  382. tempgroup = lappend(tempgroup, matched_clause);
  383. }
  384. if (tempgroup == NIL)
  385. break;
  386. clausegroup = nconc(clausegroup, tempgroup);
  387. indexkeys++;
  388. classes++;
  389. } while (!DoneMatchingIndexKeys(indexkeys, index));
  390. /* clausegroup holds all matched clauses ordered by indexkeys */
  391. if (clausegroup != NIL)
  392. return lcons(clausegroup, NIL);
  393. return NIL;
  394. }
  395. /*
  396.  * group_clauses_by_ikey_for_joins
  397.  *   special edition of group_clauses_by_indexkey - will
  398.  *   match join & restriction clauses. See comment in indexable_joinclauses.
  399.  * - vadim 03/18/97
  400.  *
  401.  */
  402. static List *
  403. group_clauses_by_ikey_for_joins(RelOptInfo *rel,
  404. RelOptInfo *index,
  405. int *indexkeys,
  406. Oid *classes,
  407. List *join_cinfo_list,
  408. List *restr_cinfo_list)
  409. {
  410. List    *curCinfo = NIL;
  411. RestrictInfo *matched_clause = (RestrictInfo *) NULL;
  412. List    *clausegroup = NIL;
  413. int curIndxKey;
  414. Oid curClass;
  415. bool jfound = false;
  416. if (join_cinfo_list == NIL || indexkeys[0] == 0)
  417. return NIL;
  418. do
  419. {
  420. List    *tempgroup = NIL;
  421. curIndxKey = indexkeys[0];
  422. curClass = classes[0];
  423. foreach(curCinfo, join_cinfo_list)
  424. {
  425. RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo);
  426. matched_clause = match_clause_to_indexkey(rel,
  427.   index,
  428.   curIndxKey,
  429.   curClass,
  430.   temp,
  431.   true);
  432. if (!matched_clause)
  433. continue;
  434. tempgroup = lappend(tempgroup, matched_clause);
  435. jfound = true;
  436. }
  437. foreach(curCinfo, restr_cinfo_list)
  438. {
  439. RestrictInfo *temp = (RestrictInfo *) lfirst(curCinfo);
  440. matched_clause = match_clause_to_indexkey(rel,
  441.   index,
  442.   curIndxKey,
  443.   curClass,
  444.   temp,
  445.   false);
  446. if (!matched_clause)
  447. continue;
  448. tempgroup = lappend(tempgroup, matched_clause);
  449. }
  450. if (tempgroup == NIL)
  451. break;
  452. clausegroup = nconc(clausegroup, tempgroup);
  453. indexkeys++;
  454. classes++;
  455. } while (!DoneMatchingIndexKeys(indexkeys, index));
  456. /* clausegroup holds all matched clauses ordered by indexkeys */
  457. if (clausegroup != NIL)
  458. {
  459. /*
  460.  * if no one join clause was matched then there ain't clauses for
  461.  * joins at all.
  462.  */
  463. if (!jfound)
  464. {
  465. freeList(clausegroup);
  466. return NIL;
  467. }
  468. return lcons(clausegroup, NIL);
  469. }
  470. return NIL;
  471. }
  472. /*
  473.  * IndexScanableClause ()  MACRO
  474.  *
  475.  * Generalize condition on which we match a clause with an index.
  476.  * Now we can match with functional indices.
  477.  */
  478. #define IndexScanableOperand(opnd, indkeys, rel, index) 
  479. ((index->indproc == InvalidOid) ? 
  480. match_indexkey_operand(indkeys, opnd, rel) : 
  481. function_index_operand((Expr*)opnd,rel,index))
  482. /*
  483.  * There was
  484.  * equal_indexkey_var(indkeys,opnd) : 
  485.  * above, and now
  486.  * match_indexkey_operand(indkeys, opnd, rel) : 
  487.  * - vadim 01/22/97
  488.  */
  489. /* match_clause_to_indexkey()
  490.  *   Finds the first of a relation's available restriction clauses that
  491.  *   matches a key of an index.
  492.  *
  493.  *   To match, the clause must:
  494.  *   (1) be in the form (op var const) if the clause is a single-
  495.  * relation clause, and
  496.  *   (2) contain an operator which is in the same class as the index
  497.  * operator for this key.
  498.  *
  499.  *   If the clause being matched is a join clause, then 'join' is t.
  500.  *
  501.  * Returns a single restrictinfo node corresponding to the matching
  502.  * clause.
  503.  *
  504.  * NOTE:  returns nil if clause is an or_clause.
  505.  *
  506.  */
  507. static RestrictInfo *
  508. match_clause_to_indexkey(RelOptInfo *rel,
  509.  RelOptInfo *index,
  510.  int indexkey,
  511.  int xclass,
  512.  RestrictInfo *restrictInfo,
  513.  bool join)
  514. {
  515. Expr    *clause = restrictInfo->clause;
  516. Var    *leftop,
  517.    *rightop;
  518. Oid join_op = InvalidOid;
  519. Oid restrict_op = InvalidOid;
  520. bool isIndexable = false;
  521. /* Clause must be a binary opclause. */
  522. if (! is_opclause((Node *) clause))
  523. return NULL;
  524. leftop = get_leftop(clause);
  525. rightop = get_rightop(clause);
  526. if (! leftop || ! rightop)
  527. return NULL;
  528. /*
  529.  * If this is not a join clause, check for clauses of the form:
  530.  * (operator var/func constant) and (operator constant var/func)
  531.  */
  532. if (!join)
  533. {
  534. /*
  535.  * Check for standard s-argable clause
  536.  */
  537. if ((rightop && IsA(rightop, Const)) ||
  538. (rightop && IsA(rightop, Param)))
  539. {
  540. restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
  541. isIndexable = (op_class(restrict_op, xclass, index->relam) &&
  542.    IndexScanableOperand(leftop,
  543. indexkey,
  544. rel,
  545. index));
  546. #ifndef IGNORE_BINARY_COMPATIBLE_INDICES
  547. /*
  548.  * Didn't find an index? Then maybe we can find another
  549.  * binary-compatible index instead... thomas 1998-08-14
  550.  */
  551. if (!isIndexable)
  552. {
  553. Oid ltype;
  554. Oid rtype;
  555. ltype = exprType((Node *) leftop);
  556. rtype = exprType((Node *) rightop);
  557. /*
  558.  * make sure we have two different binary-compatible
  559.  * types...
  560.  */
  561. if ((ltype != rtype)
  562. && IS_BINARY_COMPATIBLE(ltype, rtype))
  563. {
  564. char    *opname;
  565. Operator newop;
  566. opname = get_opname(restrict_op);
  567. if (opname != NULL)
  568. newop = oper(opname, ltype, ltype, TRUE);
  569. else
  570. newop = NULL;
  571. /* actually have a different operator to try? */
  572. if (HeapTupleIsValid(newop) && (oprid(newop) != restrict_op))
  573. {
  574. restrict_op = oprid(newop);
  575. isIndexable = (op_class(restrict_op, xclass, index->relam) &&
  576.    IndexScanableOperand(leftop,
  577. indexkey,
  578. rel,
  579. index));
  580. if (isIndexable)
  581. ((Oper *) ((Expr *) clause)->oper)->opno = restrict_op;
  582. }
  583. }
  584. }
  585. #endif
  586. }
  587. /*
  588.  * Must try to commute the clause to standard s-arg format.
  589.  */
  590. else if ((leftop && IsA(leftop, Const)) ||
  591.  (leftop && IsA(leftop, Param)))
  592. {
  593. restrict_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
  594. isIndexable = ((restrict_op != InvalidOid) &&
  595.    op_class(restrict_op, xclass, index->relam) &&
  596.    IndexScanableOperand(rightop,
  597. indexkey, rel, index));
  598. #ifndef IGNORE_BINARY_COMPATIBLE_INDICES
  599. if (!isIndexable)
  600. {
  601. Oid ltype;
  602. Oid rtype;
  603. ltype = exprType((Node *) leftop);
  604. rtype = exprType((Node *) rightop);
  605. if ((ltype != rtype)
  606. && IS_BINARY_COMPATIBLE(ltype, rtype))
  607. {
  608. char    *opname;
  609. Operator newop;
  610. restrict_op = ((Oper *) ((Expr *) clause)->oper)->opno;
  611. opname = get_opname(restrict_op);
  612. if (opname != NULL)
  613. newop = oper(opname, rtype, rtype, TRUE);
  614. else
  615. newop = NULL;
  616. if (HeapTupleIsValid(newop) && (oprid(newop) != restrict_op))
  617. {
  618. restrict_op = get_commutator(oprid(newop));
  619. isIndexable = ((restrict_op != InvalidOid) &&
  620.    op_class(restrict_op, xclass, index->relam) &&
  621.    IndexScanableOperand(rightop,
  622. indexkey,
  623. rel,
  624. index));
  625. if (isIndexable)
  626. ((Oper *) ((Expr *) clause)->oper)->opno = oprid(newop);
  627. }
  628. }
  629. }
  630. #endif
  631. if (isIndexable)
  632. {
  633. /*
  634.  * In place list modification. (op const var/func) -> (op
  635.  * var/func const)
  636.  */
  637. CommuteClause((Node *) clause);
  638. }
  639. }
  640. }
  641. /*
  642.  * Check for an indexable scan on one of the join relations. clause is
  643.  * of the form (operator var/func var/func)
  644.  */
  645. else
  646. {
  647. if (rightop
  648. && match_index_to_operand(indexkey, (Expr *) rightop, rel, index))
  649. {
  650. join_op = get_commutator(((Oper *) ((Expr *) clause)->oper)->opno);
  651. }
  652. else if (leftop
  653.  && match_index_to_operand(indexkey,
  654.    (Expr *) leftop, rel, index))
  655. join_op = ((Oper *) ((Expr *) clause)->oper)->opno;
  656. if (join_op && op_class(join_op, xclass, index->relam) &&
  657. is_joinable((Node *) clause))
  658. {
  659. isIndexable = true;
  660. /*
  661.  * If we're using the operand's commutator we must commute the
  662.  * clause.
  663.  */
  664. if (join_op != ((Oper *) ((Expr *) clause)->oper)->opno)
  665. CommuteClause((Node *) clause);
  666. }
  667. }
  668. if (isIndexable)
  669. return restrictInfo;
  670. return NULL;
  671. }
  672. /****************************************************************************
  673.  * ----  ROUTINES TO DO PARTIAL INDEX PREDICATE TESTS ----
  674.  ****************************************************************************/
  675. /*
  676.  * pred_test
  677.  *   Does the "predicate inclusion test" for partial indexes.
  678.  *
  679.  *   Recursively checks whether the clauses in restrictinfo_list imply
  680.  *   that the given predicate is true.
  681.  *
  682.  *   This routine (together with the routines it calls) iterates over
  683.  *   ANDs in the predicate first, then reduces the qualification
  684.  *   clauses down to their constituent terms, and iterates over ORs
  685.  *   in the predicate last.  This order is important to make the test
  686.  *   succeed whenever possible (assuming the predicate has been
  687.  *   successfully cnfify()-ed). --Nels, Jan '93
  688.  */
  689. static bool
  690. pred_test(List *predicate_list, List *restrictinfo_list, List *joininfo_list)
  691. {
  692. List    *pred,
  693.    *items,
  694.    *item;
  695. /*
  696.  * Note: if Postgres tried to optimize queries by forming equivalence
  697.  * classes over equi-joined attributes (i.e., if it recognized that a
  698.  * qualification such as "where a.b=c.d and a.b=5" could make use of
  699.  * an index on c.d), then we could use that equivalence class info
  700.  * here with joininfo_list to do more complete tests for the usability
  701.  * of a partial index. For now, the test only uses restriction
  702.  * clauses (those in restrictinfo_list). --Nels, Dec '92
  703.  */
  704. if (predicate_list == NULL)
  705. return true; /* no predicate: the index is usable */
  706. if (restrictinfo_list == NULL)
  707. return false; /* no restriction clauses: the test must
  708.  * fail */
  709. foreach(pred, predicate_list)
  710. {
  711. /*
  712.  * if any clause is not implied, the whole predicate is not
  713.  * implied
  714.  */
  715. if (and_clause(lfirst(pred)))
  716. {
  717. items = ((Expr *) lfirst(pred))->args;
  718. foreach(item, items)
  719. {
  720. if (!one_pred_test(lfirst(item), restrictinfo_list))
  721. return false;
  722. }
  723. }
  724. else if (!one_pred_test(lfirst(pred), restrictinfo_list))
  725. return false;
  726. }
  727. return true;
  728. }
  729. /*
  730.  * one_pred_test
  731.  *   Does the "predicate inclusion test" for one conjunct of a predicate
  732.  *   expression.
  733.  */
  734. static bool
  735. one_pred_test(Expr *predicate, List *restrictinfo_list)
  736. {
  737. RestrictInfo *restrictinfo;
  738. List    *item;
  739. Assert(predicate != NULL);
  740. foreach(item, restrictinfo_list)
  741. {
  742. restrictinfo = (RestrictInfo *) lfirst(item);
  743. /* if any clause implies the predicate, return true */
  744. if (one_pred_clause_expr_test(predicate, (Node *) restrictinfo->clause))
  745. return true;
  746. }
  747. return false;
  748. }
  749. /*
  750.  * one_pred_clause_expr_test
  751.  *   Does the "predicate inclusion test" for a general restriction-clause
  752.  *   expression.
  753.  */
  754. static bool
  755. one_pred_clause_expr_test(Expr *predicate, Node *clause)
  756. {
  757. List    *items,
  758.    *item;
  759. if (is_opclause(clause))
  760. return one_pred_clause_test(predicate, clause);
  761. else if (or_clause(clause))
  762. {
  763. items = ((Expr *) clause)->args;
  764. foreach(item, items)
  765. {
  766. /* if any OR item doesn't imply the predicate, clause doesn't */
  767. if (!one_pred_clause_expr_test(predicate, lfirst(item)))
  768. return false;
  769. }
  770. return true;
  771. }
  772. else if (and_clause(clause))
  773. {
  774. items = ((Expr *) clause)->args;
  775. foreach(item, items)
  776. {
  777. /*
  778.  * if any AND item implies the predicate, the whole clause
  779.  * does
  780.  */
  781. if (one_pred_clause_expr_test(predicate, lfirst(item)))
  782. return true;
  783. }
  784. return false;
  785. }
  786. else
  787. {
  788. /* unknown clause type never implies the predicate */
  789. return false;
  790. }
  791. }
  792. /*
  793.  * one_pred_clause_test
  794.  *   Does the "predicate inclusion test" for one conjunct of a predicate
  795.  *   expression for a simple restriction clause.
  796.  */
  797. static bool
  798. one_pred_clause_test(Expr *predicate, Node *clause)
  799. {
  800. List    *items,
  801.    *item;
  802. if (is_opclause((Node *) predicate))
  803. return clause_pred_clause_test(predicate, clause);
  804. else if (or_clause((Node *) predicate))
  805. {
  806. items = predicate->args;
  807. foreach(item, items)
  808. {
  809. /* if any item is implied, the whole predicate is implied */
  810. if (one_pred_clause_test(lfirst(item), clause))
  811. return true;
  812. }
  813. return false;
  814. }
  815. else if (and_clause((Node *) predicate))
  816. {
  817. items = predicate->args;
  818. foreach(item, items)
  819. {
  820. /*
  821.  * if any item is not implied, the whole predicate is not
  822.  * implied
  823.  */
  824. if (!one_pred_clause_test(lfirst(item), clause))
  825. return false;
  826. }
  827. return true;
  828. }
  829. else
  830. {
  831. elog(DEBUG, "Unsupported predicate type, index will not be used");
  832. return false;
  833. }
  834. }
  835. /*
  836.  * Define an "operator implication table" for btree operators ("strategies").
  837.  * The "strategy numbers" are: (1) < (2) <=  (3) =  (4) >=   (5) >
  838.  *
  839.  * The interpretation of:
  840.  *
  841.  * test_op = BT_implic_table[given_op-1][target_op-1]
  842.  *
  843.  * where test_op, given_op and target_op are strategy numbers (from 1 to 5)
  844.  * of btree operators, is as follows:
  845.  *
  846.  *  If you know, for some ATTR, that "ATTR given_op CONST1" is true, and you
  847.  *  want to determine whether "ATTR target_op CONST2" must also be true, then
  848.  *  you can use "CONST1 test_op CONST2" as a test.  If this test returns true,
  849.  *  then the target expression must be true; if the test returns false, then
  850.  *  the target expression may be false.
  851.  *
  852.  * An entry where test_op==0 means the implication cannot be determined, i.e.,
  853.  * this test should always be considered false.
  854.  */
  855. StrategyNumber BT_implic_table[BTMaxStrategyNumber][BTMaxStrategyNumber] = {
  856. {2, 2, 0, 0, 0},
  857. {1, 2, 0, 0, 0},
  858. {1, 2, 3, 4, 5},
  859. {0, 0, 0, 4, 5},
  860. {0, 0, 0, 4, 4}
  861. };
  862. /*
  863.  * clause_pred_clause_test
  864.  *   Use operator class info to check whether clause implies predicate.
  865.  *
  866.  *   Does the "predicate inclusion test" for a "simple clause" predicate
  867.  *   for a single "simple clause" restriction.  Currently, this only handles
  868.  *   (binary boolean) operators that are in some btree operator class.
  869.  *   Eventually, rtree operators could also be handled by defining an
  870.  *   appropriate "RT_implic_table" array.
  871.  */
  872. static bool
  873. clause_pred_clause_test(Expr *predicate, Node *clause)
  874. {
  875. Var    *pred_var,
  876.    *clause_var;
  877. Const    *pred_const,
  878.    *clause_const;
  879. Oid pred_op,
  880. clause_op,
  881. test_op;
  882. Oid opclass_id;
  883. StrategyNumber pred_strategy,
  884. clause_strategy,
  885. test_strategy;
  886. Oper    *test_oper;
  887. Expr    *test_expr;
  888. bool test_result,
  889. isNull;
  890. Relation relation;
  891. HeapScanDesc scan;
  892. HeapTuple tuple;
  893. ScanKeyData entry[3];
  894. Form_pg_amop aform;
  895. pred_var = (Var *) get_leftop(predicate);
  896. pred_const = (Const *) get_rightop(predicate);
  897. clause_var = (Var *) get_leftop((Expr *) clause);
  898. clause_const = (Const *) get_rightop((Expr *) clause);
  899. /* Check the basic form; for now, only allow the simplest case */
  900. if (!is_opclause(clause) ||
  901. !IsA(clause_var, Var) ||
  902. clause_const == NULL ||
  903. !IsA(clause_const, Const) ||
  904. !IsA(predicate->oper, Oper) ||
  905. !IsA(pred_var, Var) ||
  906. !IsA(pred_const, Const))
  907. return false;
  908. /*
  909.  * The implication can't be determined unless the predicate and the
  910.  * clause refer to the same attribute.
  911.  */
  912. if (clause_var->varattno != pred_var->varattno)
  913. return false;
  914. /* Get the operators for the two clauses we're comparing */
  915. pred_op = ((Oper *) ((Expr *) predicate)->oper)->opno;
  916. clause_op = ((Oper *) ((Expr *) clause)->oper)->opno;
  917. /*
  918.  * 1. Find a "btree" strategy number for the pred_op
  919.  */
  920. ScanKeyEntryInitialize(&entry[0], 0,
  921.    Anum_pg_amop_amopid,
  922.    F_OIDEQ,
  923.    ObjectIdGetDatum(BTREE_AM_OID));
  924. ScanKeyEntryInitialize(&entry[1], 0,
  925.    Anum_pg_amop_amopopr,
  926.    F_OIDEQ,
  927.    ObjectIdGetDatum(pred_op));
  928. relation = heap_openr(AccessMethodOperatorRelationName);
  929. /*
  930.  * The following assumes that any given operator will only be in a
  931.  * single btree operator class.  This is true at least for all the
  932.  * pre-defined operator classes.  If it isn't true, then whichever
  933.  * operator class happens to be returned first for the given operator
  934.  * will be used to find the associated strategy numbers for the test.
  935.  * --Nels, Jan '93
  936.  */
  937. scan = heap_beginscan(relation, false, SnapshotNow, 2, entry);
  938. tuple = heap_getnext(scan, 0);
  939. if (!HeapTupleIsValid(tuple))
  940. {
  941. elog(DEBUG, "clause_pred_clause_test: unknown pred_op");
  942. return false;
  943. }
  944. aform = (Form_pg_amop) GETSTRUCT(tuple);
  945. /* Get the predicate operator's strategy number (1 to 5) */
  946. pred_strategy = (StrategyNumber) aform->amopstrategy;
  947. /* Remember which operator class this strategy number came from */
  948. opclass_id = aform->amopclaid;
  949. heap_endscan(scan);
  950. /*
  951.  * 2. From the same opclass, find a strategy num for the clause_op
  952.  */
  953. ScanKeyEntryInitialize(&entry[1], 0,
  954.    Anum_pg_amop_amopclaid,
  955.    F_OIDEQ,
  956.    ObjectIdGetDatum(opclass_id));
  957. ScanKeyEntryInitialize(&entry[2], 0,
  958.    Anum_pg_amop_amopopr,
  959.    F_OIDEQ,
  960.    ObjectIdGetDatum(clause_op));
  961. scan = heap_beginscan(relation, false, SnapshotNow, 3, entry);
  962. tuple = heap_getnext(scan, 0);
  963. if (!HeapTupleIsValid(tuple))
  964. {
  965. elog(DEBUG, "clause_pred_clause_test: unknown clause_op");
  966. return false;
  967. }
  968. aform = (Form_pg_amop) GETSTRUCT(tuple);
  969. /* Get the restriction clause operator's strategy number (1 to 5) */
  970. clause_strategy = (StrategyNumber) aform->amopstrategy;
  971. heap_endscan(scan);
  972. /*
  973.  * 3. Look up the "test" strategy number in the implication table
  974.  */
  975. test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1];
  976. if (test_strategy == 0)
  977. return false; /* the implication cannot be determined */
  978. /*
  979.  * 4. From the same opclass, find the operator for the test strategy
  980.  */
  981. ScanKeyEntryInitialize(&entry[2], 0,
  982.    Anum_pg_amop_amopstrategy,
  983.    F_INT2EQ,
  984.    Int16GetDatum(test_strategy));
  985. scan = heap_beginscan(relation, false, SnapshotNow, 3, entry);
  986. tuple = heap_getnext(scan, 0);
  987. if (!HeapTupleIsValid(tuple))
  988. {
  989. elog(DEBUG, "clause_pred_clause_test: unknown test_op");
  990. return false;
  991. }
  992. aform = (Form_pg_amop) GETSTRUCT(tuple);
  993. /* Get the test operator */
  994. test_op = aform->amopopr;
  995. heap_endscan(scan);
  996. /*
  997.  * 5. Evaluate the test
  998.  */
  999. test_oper = makeOper(test_op, /* opno */
  1000.  InvalidOid, /* opid */
  1001.  BOOLOID, /* opresulttype */
  1002.  0, /* opsize */
  1003.  NULL); /* op_fcache */
  1004. replace_opid(test_oper);
  1005. test_expr = make_opclause(test_oper,
  1006.   copyObject(clause_const),
  1007.   copyObject(pred_const));
  1008. #ifndef OMIT_PARTIAL_INDEX
  1009. test_result = ExecEvalExpr((Node *) test_expr, NULL, &isNull, NULL);
  1010. #endif  /* OMIT_PARTIAL_INDEX */
  1011. if (isNull)
  1012. {
  1013. elog(DEBUG, "clause_pred_clause_test: null test result");
  1014. return false;
  1015. }
  1016. return test_result;
  1017. }
  1018. /****************************************************************************
  1019.  * ----  ROUTINES TO CHECK JOIN CLAUSES  ----
  1020.  ****************************************************************************/
  1021. /*
  1022.  * indexable_joinclauses
  1023.  *   Finds all groups of join clauses from among 'joininfo_list' that can
  1024.  *   be used in conjunction with 'index'.
  1025.  *
  1026.  *   The first clause in the group is marked as having the other relation
  1027.  *   in the join clause as its outer join relation.
  1028.  *
  1029.  * Returns a list of these clause groups.
  1030.  *
  1031.  *   Added: restrictinfo_list - list of restriction RestrictInfos. It's to
  1032.  * support multi-column indices in joins and for cases
  1033.  * when a key is in both join & restriction clauses. - vadim 03/18/97
  1034.  *
  1035.  */
  1036. static List *
  1037. indexable_joinclauses(RelOptInfo *rel, RelOptInfo *index,
  1038.   List *joininfo_list, List *restrictinfo_list)
  1039. {
  1040. JoinInfo   *joininfo = (JoinInfo *) NULL;
  1041. List    *cg_list = NIL;
  1042. List    *i = NIL;
  1043. List    *clausegroups = NIL;
  1044. foreach(i, joininfo_list)
  1045. {
  1046. joininfo = (JoinInfo *) lfirst(i);
  1047. if (joininfo->jinfo_restrictinfo == NIL)
  1048. continue;
  1049. clausegroups = group_clauses_by_ikey_for_joins(rel,
  1050.    index,
  1051.    index->indexkeys,
  1052.    index->classlist,
  1053. joininfo->jinfo_restrictinfo,
  1054.    restrictinfo_list);
  1055. if (clausegroups != NIL)
  1056. {
  1057. List    *clauses = lfirst(clausegroups);
  1058. ((RestrictInfo *) lfirst(clauses))->restrictinfojoinid = joininfo->unjoined_relids;
  1059. }
  1060. cg_list = nconc(cg_list, clausegroups);
  1061. }
  1062. return cg_list;
  1063. }
  1064. /****************************************************************************
  1065.  * ----  PATH CREATION UTILITIES  ----
  1066.  ****************************************************************************/
  1067. /*
  1068.  * extract_restrict_clauses -
  1069.  *   the list of clause info contains join clauses and restriction clauses.
  1070.  *   This routine returns the restriction clauses only.
  1071.  */
  1072. #ifdef NOT_USED
  1073. static List *
  1074. extract_restrict_clauses(List *clausegroup)
  1075. {
  1076. List    *restrict_cls = NIL;
  1077. List    *l;
  1078. foreach(l, clausegroup)
  1079. {
  1080. RestrictInfo *cinfo = lfirst(l);
  1081. if (!is_joinable((Node *) cinfo->clause))
  1082. restrict_cls = lappend(restrict_cls, cinfo);
  1083. }
  1084. return restrict_cls;
  1085. }
  1086. #endif
  1087. /*
  1088.  * index_innerjoin
  1089.  *   Creates index path nodes corresponding to paths to be used as inner
  1090.  *   relations in nestloop joins.
  1091.  *
  1092.  * 'clausegroup-list' is a list of list of restrictinfo nodes which can use
  1093.  * 'index' on their inner relation.
  1094.  *
  1095.  * Returns a list of index pathnodes.
  1096.  *
  1097.  */
  1098. static List *
  1099. index_innerjoin(Query *root, RelOptInfo *rel, List *clausegroup_list,
  1100. RelOptInfo *index)
  1101. {
  1102. List    *clausegroup = NIL;
  1103. List    *cg_list = NIL;
  1104. List    *i = NIL;
  1105. IndexPath  *pathnode = (IndexPath *) NULL;
  1106. Cost temp_selec;
  1107. float temp_pages;
  1108. foreach(i, clausegroup_list)
  1109. {
  1110. List    *attnos,
  1111.    *values,
  1112.    *flags;
  1113. clausegroup = lfirst(i);
  1114. pathnode = makeNode(IndexPath);
  1115. get_joinvars(lfirsti(rel->relids), clausegroup,
  1116.  &attnos, &values, &flags);
  1117. index_selectivity(lfirsti(index->relids),
  1118.   index->classlist,
  1119.   get_opnos(clausegroup),
  1120.   getrelid(lfirsti(rel->relids),
  1121.    root->rtable),
  1122.   attnos,
  1123.   values,
  1124.   flags,
  1125.   length(clausegroup),
  1126.   &temp_pages,
  1127.   &temp_selec);
  1128. pathnode->path.pathtype = T_IndexScan;
  1129. pathnode->path.parent = rel;
  1130. pathnode->path.pathorder = makeNode(PathOrder);
  1131. pathnode->path.pathorder->ordtype = SORTOP_ORDER;
  1132. pathnode->path.pathorder->ord.sortop = index->ordering;
  1133. pathnode->path.pathkeys = NIL;
  1134. pathnode->indexid = index->relids;
  1135. pathnode->indexkeys = index->indexkeys;
  1136. pathnode->indexqual = clausegroup;
  1137. pathnode->path.joinid = ((RestrictInfo *) lfirst(clausegroup))->restrictinfojoinid;
  1138. pathnode->path.path_cost = cost_index((Oid) lfirsti(index->relids),
  1139.   (int) temp_pages,
  1140.   temp_selec,
  1141.   rel->pages,
  1142.   rel->tuples,
  1143.   index->pages,
  1144.   index->tuples,
  1145.   true);
  1146. /*
  1147.  * copy restrictinfo list into path for expensive function
  1148.  * processing -- JMH, 7/7/92
  1149.  */
  1150. pathnode->path.loc_restrictinfo = set_difference(copyObject((Node *) rel->restrictinfo),
  1151.  clausegroup);
  1152. #ifdef NOT_USED /* fix xfunc */
  1153. /* add in cost for expensive functions!  -- JMH, 7/7/92 */
  1154. if (XfuncMode != XFUNC_OFF)
  1155. ((Path *) pathnode)->path_cost += xfunc_get_path_cost((Path *) pathnode);
  1156. #endif
  1157. cg_list = lappend(cg_list, pathnode);
  1158. }
  1159. return cg_list;
  1160. }
  1161. /*
  1162.  * create_index_path_group
  1163.  *   Creates a list of index path nodes for each group of clauses
  1164.  *   (restriction or join) that can be used in conjunction with an index.
  1165.  *
  1166.  * 'rel' is the relation for which 'index' is defined
  1167.  * 'clausegroup-list' is the list of clause groups (lists of restrictinfo
  1168.  * nodes) grouped by mergejoinorder
  1169.  * 'join' is a flag indicating whether or not the clauses are join
  1170.  * clauses
  1171.  *
  1172.  * Returns a list of new index path nodes.
  1173.  *
  1174.  */
  1175. static List *
  1176. create_index_path_group(Query *root,
  1177. RelOptInfo *rel,
  1178. RelOptInfo *index,
  1179. List *clausegroup_list,
  1180. bool join)
  1181. {
  1182. List    *clausegroup = NIL;
  1183. List    *ip_list = NIL;
  1184. List    *i = NIL;
  1185. List    *j = NIL;
  1186. IndexPath  *temp_path;
  1187. foreach(i, clausegroup_list)
  1188. {
  1189. RestrictInfo *restrictinfo;
  1190. bool temp = true;
  1191. clausegroup = lfirst(i);
  1192. foreach(j, clausegroup)
  1193. {
  1194. restrictinfo = (RestrictInfo *) lfirst(j);
  1195. if (!(is_joinable((Node *) restrictinfo->clause) &&
  1196.   equal_path_merge_ordering(index->ordering,
  1197.   restrictinfo->mergejoinorder)))
  1198. temp = false;
  1199. }
  1200. if (!join || temp)
  1201. { /* restriction, ordering scan */
  1202. temp_path = create_index_path(root, rel, index, clausegroup, join);
  1203. ip_list = lappend(ip_list, temp_path);
  1204. }
  1205. }
  1206. return ip_list;
  1207. }
  1208. static List *
  1209. add_index_paths(List *indexpaths, List *new_indexpaths)
  1210. {
  1211. return nconc(indexpaths, new_indexpaths);
  1212. }
  1213. static bool
  1214. function_index_operand(Expr *funcOpnd, RelOptInfo *rel, RelOptInfo *index)
  1215. {
  1216. Oid heapRelid = (Oid) lfirsti(rel->relids);
  1217. Func    *function;
  1218. List    *funcargs;
  1219. int    *indexKeys = index->indexkeys;
  1220. List    *arg;
  1221. int i;
  1222. /*
  1223.  * sanity check, make sure we know what we're dealing with here.
  1224.  */
  1225. if (funcOpnd == NULL ||
  1226. nodeTag(funcOpnd) != T_Expr || funcOpnd->opType != FUNC_EXPR ||
  1227. funcOpnd->oper == NULL || indexKeys == NULL)
  1228. return false;
  1229. function = (Func *) funcOpnd->oper;
  1230. funcargs = funcOpnd->args;
  1231. if (function->funcid != index->indproc)
  1232. return false;
  1233. /*
  1234.  * Check that the arguments correspond to the same arguments used to
  1235.  * create the functional index.  To do this we must check that 1.
  1236.  * refer to the right relatiion. 2. the args have the right attr.
  1237.  * numbers in the right order.
  1238.  *
  1239.  *
  1240.  * Check all args refer to the correct relation (i.e. the one with the
  1241.  * functional index defined on it (rel).  To do this we can simply
  1242.  * compare range table entry numbers, they must be the same.
  1243.  */
  1244. foreach(arg, funcargs)
  1245. {
  1246. if (heapRelid != ((Var *) lfirst(arg))->varno)
  1247. return false;
  1248. }
  1249. /*
  1250.  * check attr numbers and order.
  1251.  */
  1252. i = 0;
  1253. foreach(arg, funcargs)
  1254. {
  1255. if (indexKeys[i] == 0)
  1256. return false;
  1257. if (((Var *) lfirst(arg))->varattno != indexKeys[i])
  1258. return false;
  1259. i++;
  1260. }
  1261. return true;
  1262. }