99 *
1010 *
1111 * IDENTIFICATION
12- * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.203 2006/04/08 21:32:17 tgl Exp $
12+ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.204 2006/04/09 18:18:41 tgl Exp $
1313 *
1414 *-------------------------------------------------------------------------
1515 */
@@ -53,6 +53,7 @@ static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
5353static Path * choose_bitmap_and (PlannerInfo * root ,RelOptInfo * rel ,List * paths );
5454static int bitmap_path_comparator (const void * a ,const void * b );
5555static Cost bitmap_and_cost_est (PlannerInfo * root ,RelOptInfo * rel ,List * paths );
56+ static List * pull_indexpath_quals (Path * bitmapqual );
5657static bool lists_intersect_ptr (List * list1 ,List * list2 );
5758static bool match_clause_to_indexcol (IndexOptInfo * index ,
5859int indexcol ,Oid opclass ,
@@ -253,10 +254,6 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
253254List * all_clauses = NIL ;/* not computed till needed */
254255ListCell * ilist ;
255256
256- /* quick exit if no available clauses */
257- if (clauses == NIL )
258- return NIL ;
259-
260257foreach (ilist ,rel -> indexlist )
261258{
262259IndexOptInfo * index = (IndexOptInfo * )lfirst (ilist );
@@ -581,9 +578,10 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
581578 * lower estimated cost.
582579 *
583580 * We also make some effort to detect directly redundant input paths, as
584- * can happen if there are multiple possibly usable indexes. For this we
585- * look only at plain IndexPath and single-element BitmapOrPath inputs
586- * (the latter can arise in the presence of ScalarArrayOpExpr quals). We
581+ * can happen if there are multiple possibly usable indexes. (Another
582+ * way it can happen is that best_inner_indexscan will find the same OR
583+ * join clauses that create_or_index_quals has pulled OR restriction
584+ * clauses out of, and then both versions show up as duplicate paths.) We
587585 * consider an index redundant if any of its index conditions were already
588586 * used by earlier indexes. (We could use predicate_implied_by to have a
589587 * more intelligent, but much more expensive, check --- but in most cases
@@ -620,53 +618,31 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel, List *paths)
620618
621619paths = list_make1 (patharray [0 ]);
622620costsofar = bitmap_and_cost_est (root ,rel ,paths );
623- qualsofar = NIL ;
624- if (IsA (patharray [0 ],IndexPath ))
625- qualsofar = list_copy (((IndexPath * )patharray [0 ])-> indexclauses );
626- else if (IsA (patharray [0 ],BitmapOrPath ))
627- {
628- List * orquals = ((BitmapOrPath * )patharray [0 ])-> bitmapquals ;
629-
630- if (list_length (orquals )== 1 &&
631- IsA (linitial (orquals ),IndexPath ))
632- qualsofar = list_copy (((IndexPath * )linitial (orquals ))-> indexclauses );
633- }
621+ qualsofar = pull_indexpath_quals (patharray [0 ]);
634622lastcell = list_head (paths );/* for quick deletions */
635623
636624for (i = 1 ;i < npaths ;i ++ )
637625{
638626Path * newpath = patharray [i ];
639- List * newqual = NIL ;
627+ List * newqual ;
640628Cost newcost ;
641629
642- if (IsA (newpath ,IndexPath ))
643- {
644- newqual = ((IndexPath * )newpath )-> indexclauses ;
645- if (lists_intersect_ptr (newqual ,qualsofar ))
646- continue ;/* redundant */
647- }
648- else if (IsA (newpath ,BitmapOrPath ))
649- {
650- List * orquals = ((BitmapOrPath * )newpath )-> bitmapquals ;
651-
652- if (list_length (orquals )== 1 &&
653- IsA (linitial (orquals ),IndexPath ))
654- newqual = ((IndexPath * )linitial (orquals ))-> indexclauses ;
655- if (lists_intersect_ptr (newqual ,qualsofar ))
656- continue ;/* redundant */
657- }
658-
630+ newqual = pull_indexpath_quals (newpath );
631+ if (lists_intersect_ptr (newqual ,qualsofar ))
632+ continue ;/* consider it redundant */
633+ /* tentatively add newpath to paths, so we can estimate cost */
659634paths = lappend (paths ,newpath );
660635newcost = bitmap_and_cost_est (root ,rel ,paths );
661636if (newcost < costsofar )
662637{
638+ /* keep newpath in paths, update subsidiary variables */
663639costsofar = newcost ;
664- if (newqual )
665- qualsofar = list_concat (qualsofar ,list_copy (newqual ));
640+ qualsofar = list_concat (qualsofar ,newqual );
666641lastcell = lnext (lastcell );
667642}
668643else
669644{
645+ /* reject newpath, remove it from paths list */
670646paths = list_delete_cell (paths ,lnext (lastcell ),lastcell );
671647}
672648Assert (lnext (lastcell )== NULL );
@@ -733,6 +709,62 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths)
733709return bpath .total_cost ;
734710}
735711
712+ /*
713+ * pull_indexpath_quals
714+ *
715+ * Given the Path structure for a plain or bitmap indexscan, extract a
716+ * list of RestrictInfo nodes for all the indexquals used in the Path.
717+ *
718+ * This is sort of a simplified version of make_restrictinfo_from_bitmapqual;
719+ * here, we are not trying to produce an accurate representation of the AND/OR
720+ * semantics of the Path, but just find out all the base conditions used.
721+ *
722+ * The result list contains pointers to the RestrictInfos used in the Path,
723+ * but all the list cells are freshly built, so it's safe to destructively
724+ * modify the list (eg, by concat'ing it with other lists).
725+ */
726+ static List *
727+ pull_indexpath_quals (Path * bitmapqual )
728+ {
729+ List * result = NIL ;
730+ ListCell * l ;
731+
732+ if (IsA (bitmapqual ,BitmapAndPath ))
733+ {
734+ BitmapAndPath * apath = (BitmapAndPath * )bitmapqual ;
735+
736+ foreach (l ,apath -> bitmapquals )
737+ {
738+ List * sublist ;
739+
740+ sublist = pull_indexpath_quals ((Path * )lfirst (l ));
741+ result = list_concat (result ,sublist );
742+ }
743+ }
744+ else if (IsA (bitmapqual ,BitmapOrPath ))
745+ {
746+ BitmapOrPath * opath = (BitmapOrPath * )bitmapqual ;
747+
748+ foreach (l ,opath -> bitmapquals )
749+ {
750+ List * sublist ;
751+
752+ sublist = pull_indexpath_quals ((Path * )lfirst (l ));
753+ result = list_concat (result ,sublist );
754+ }
755+ }
756+ else if (IsA (bitmapqual ,IndexPath ))
757+ {
758+ IndexPath * ipath = (IndexPath * )bitmapqual ;
759+
760+ result = list_copy (ipath -> indexclauses );
761+ }
762+ else
763+ elog (ERROR ,"unrecognized node type: %d" ,nodeTag (bitmapqual ));
764+
765+ return result ;
766+ }
767+
736768
737769/*
738770 * lists_intersect_ptr
@@ -1374,20 +1406,24 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
13741406}
13751407
13761408/*
1377- * Find all the relevant join clauses.
1409+ * Find all the relevant restriction and join clauses.
1410+ *
1411+ * Note: because we include restriction clauses, we will find indexscans
1412+ * that could be plain indexscans, ie, they don't require the join context
1413+ * at all. This may seem redundant, but we need to include those scans in
1414+ * the input given to choose_bitmap_and() to be sure we find optimal AND
1415+ * combinations of join and non-join scans. The worst case is that we
1416+ * might return a "best inner indexscan" that's really just a plain
1417+ * indexscan, causing some redundant effort in joinpath.c.
13781418 */
13791419clause_list = find_clauses_for_join (root ,rel ,outer_relids ,isouterjoin );
13801420
13811421/*
13821422 * Find all the index paths that are usable for this join, except for
1383- * stuff involving OR and ScalarArrayOpExpr clauses. We can use both
1384- * join and restriction clauses as indexquals, but we insist the path
1385- * use at least one join clause (else it'd not be an "inner indexscan"
1386- * but a plain indexscan, and those have already been considered).
1423+ * stuff involving OR and ScalarArrayOpExpr clauses.
13871424 */
13881425indexpaths = find_usable_indexes (root ,rel ,
1389- clause_list ,
1390- rel -> baserestrictinfo ,
1426+ clause_list ,NIL ,
13911427 false, true,
13921428outer_relids ,
13931429SAOP_FORBID );
@@ -1397,8 +1433,7 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
13971433 * clauses present in the clause list.
13981434 */
13991435bitindexpaths = generate_bitmap_or_paths (root ,rel ,
1400- clause_list ,
1401- rel -> baserestrictinfo ,
1436+ clause_list ,NIL ,
14021437 true,
14031438outer_relids );
14041439
@@ -1448,12 +1483,13 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
14481483
14491484/*
14501485 * find_clauses_for_join
1451- * Generate a list ofjoin clauses that are potentially useful for
1486+ * Generate a list of clauses that are potentially useful for
14521487 * scanning rel as the inner side of a nestloop join.
14531488 *
1454- * Any joinclause that uses only otherrels in the specified outer_relids is
1455- * fair game. Note that restriction clauses on rel can also be used in
1456- * forming index conditions, but we do not include those here.
1489+ * We consider both join and restriction clauses. Any joinclause that uses
1490+ * only otherrels in the specified outer_relids is fair game. But there must
1491+ * be at least one such joinclause in the final list, otherwise we return NIL
1492+ * indicating that there isn't any potential win here.
14571493 */
14581494static List *
14591495find_clauses_for_join (PlannerInfo * root ,RelOptInfo * rel ,
@@ -1481,28 +1517,28 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
14811517
14821518bms_free (join_relids );
14831519
1484- /*quick exit if no join clause was matched */
1520+ /* if no join clause was matched then forget it, per comments above */
14851521if (clause_list == NIL )
14861522return NIL ;
14871523
1524+ /*
1525+ * We can also use any plain restriction clauses for the rel. We put
1526+ * these at the front of the clause list for the convenience of
1527+ * remove_redundant_join_clauses, which can never remove non-join clauses
1528+ * and hence won't be able to get rid of a non-join clause if it appears
1529+ * after a join clause it is redundant with.
1530+ */
1531+ clause_list = list_concat (list_copy (rel -> baserestrictinfo ),clause_list );
1532+
14881533/*
14891534 * We may now have clauses that are known redundant. Get rid of 'em.
14901535 */
14911536if (list_length (clause_list )> 1 )
1537+ {
14921538clause_list = remove_redundant_join_clauses (root ,
14931539clause_list ,
14941540isouterjoin );
1495-
1496- /*
1497- * We might have found join clauses that are known redundant with
1498- * restriction clauses on rel (due to conclusions drawn by implied
1499- * equality deduction; without that, this would obviously never happen).
1500- * Get rid of them too.
1501- */
1502- if (rel -> baserestrictinfo != NIL )
1503- clause_list = select_nonredundant_join_clauses (root ,clause_list ,
1504- rel -> baserestrictinfo ,
1505- isouterjoin );
1541+ }
15061542
15071543return clause_list ;
15081544}