LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - joininfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17beta1 Lines: 41 41 100.0 %
Date: 2024-05-29 11:10:47 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * joininfo.c
       4             :  *    joininfo list manipulation routines
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/optimizer/util/joininfo.c
      12             :  *
      13             :  *-------------------------------------------------------------------------
      14             :  */
      15             : #include "postgres.h"
      16             : 
      17             : #include "nodes/makefuncs.h"
      18             : #include "optimizer/joininfo.h"
      19             : #include "optimizer/pathnode.h"
      20             : #include "optimizer/paths.h"
      21             : #include "optimizer/planmain.h"
      22             : #include "optimizer/restrictinfo.h"
      23             : 
      24             : 
      25             : /*
      26             :  * have_relevant_joinclause
      27             :  *      Detect whether there is a joinclause that involves
      28             :  *      the two given relations.
      29             :  *
      30             :  * Note: the joinclause does not have to be evaluable with only these two
      31             :  * relations.  This is intentional.  For example consider
      32             :  *      SELECT * FROM a, b, c WHERE a.x = (b.y + c.z)
      33             :  * If a is much larger than the other tables, it may be worthwhile to
      34             :  * cross-join b and c and then use an inner indexscan on a.x.  Therefore
      35             :  * we should consider this joinclause as reason to join b to c, even though
      36             :  * it can't be applied at that join step.
      37             :  */
      38             : bool
      39      318510 : have_relevant_joinclause(PlannerInfo *root,
      40             :                          RelOptInfo *rel1, RelOptInfo *rel2)
      41             : {
      42      318510 :     bool        result = false;
      43             :     List       *joininfo;
      44             :     Relids      other_relids;
      45             :     ListCell   *l;
      46             : 
      47             :     /*
      48             :      * We could scan either relation's joininfo list; may as well use the
      49             :      * shorter one.
      50             :      */
      51      318510 :     if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
      52             :     {
      53      236944 :         joininfo = rel1->joininfo;
      54      236944 :         other_relids = rel2->relids;
      55             :     }
      56             :     else
      57             :     {
      58       81566 :         joininfo = rel2->joininfo;
      59       81566 :         other_relids = rel1->relids;
      60             :     }
      61             : 
      62      350792 :     foreach(l, joininfo)
      63             :     {
      64      165866 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
      65             : 
      66      165866 :         if (bms_overlap(other_relids, rinfo->required_relids))
      67             :         {
      68      133584 :             result = true;
      69      133584 :             break;
      70             :         }
      71             :     }
      72             : 
      73             :     /*
      74             :      * We also need to check the EquivalenceClass data structure, which might
      75             :      * contain relationships not emitted into the joininfo lists.
      76             :      */
      77      318510 :     if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
      78      136778 :         result = have_relevant_eclass_joinclause(root, rel1, rel2);
      79             : 
      80      318510 :     return result;
      81             : }
      82             : 
      83             : 
      84             : /*
      85             :  * add_join_clause_to_rels
      86             :  *    Add 'restrictinfo' to the joininfo list of each relation it requires.
      87             :  *
      88             :  * Note that the same copy of the restrictinfo node is linked to by all the
      89             :  * lists it is in.  This allows us to exploit caching of information about
      90             :  * the restriction clause (but we must be careful that the information does
      91             :  * not depend on context).
      92             :  *
      93             :  * 'restrictinfo' describes the join clause
      94             :  * 'join_relids' is the set of relations participating in the join clause
      95             :  *               (some of these could be outer joins)
      96             :  */
      97             : void
      98       59354 : add_join_clause_to_rels(PlannerInfo *root,
      99             :                         RestrictInfo *restrictinfo,
     100             :                         Relids join_relids)
     101             : {
     102             :     int         cur_relid;
     103             : 
     104             :     /* Don't add the clause if it is always true */
     105       59354 :     if (restriction_is_always_true(root, restrictinfo))
     106          24 :         return;
     107             : 
     108             :     /*
     109             :      * Substitute constant-FALSE for the origin qual if it is always false.
     110             :      * Note that we keep the same rinfo_serial.
     111             :      */
     112       59330 :     if (restriction_is_always_false(root, restrictinfo))
     113             :     {
     114          12 :         int         save_rinfo_serial = restrictinfo->rinfo_serial;
     115             : 
     116          12 :         restrictinfo = make_restrictinfo(root,
     117          12 :                                          (Expr *) makeBoolConst(false, false),
     118          12 :                                          restrictinfo->is_pushed_down,
     119          12 :                                          restrictinfo->has_clone,
     120          12 :                                          restrictinfo->is_clone,
     121          12 :                                          restrictinfo->pseudoconstant,
     122             :                                          0, /* security_level */
     123             :                                          restrictinfo->required_relids,
     124             :                                          restrictinfo->incompatible_relids,
     125             :                                          restrictinfo->outer_relids);
     126          12 :         restrictinfo->rinfo_serial = save_rinfo_serial;
     127             :     }
     128             : 
     129       59330 :     cur_relid = -1;
     130      191070 :     while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
     131             :     {
     132      131740 :         RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
     133             : 
     134             :         /* We only need to add the clause to baserels */
     135      131740 :         if (rel == NULL)
     136        8080 :             continue;
     137      123660 :         rel->joininfo = lappend(rel->joininfo, restrictinfo);
     138             :     }
     139             : }
     140             : 
     141             : /*
     142             :  * remove_join_clause_from_rels
     143             :  *    Delete 'restrictinfo' from all the joininfo lists it is in
     144             :  *
     145             :  * This reverses the effect of add_join_clause_to_rels.  It's used when we
     146             :  * discover that a relation need not be joined at all.
     147             :  *
     148             :  * 'restrictinfo' describes the join clause
     149             :  * 'join_relids' is the set of relations participating in the join clause
     150             :  *               (some of these could be outer joins)
     151             :  */
     152             : void
     153        8926 : remove_join_clause_from_rels(PlannerInfo *root,
     154             :                              RestrictInfo *restrictinfo,
     155             :                              Relids join_relids)
     156             : {
     157             :     int         cur_relid;
     158             : 
     159        8926 :     cur_relid = -1;
     160       27104 :     while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
     161             :     {
     162       18178 :         RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
     163             : 
     164             :         /* We would only have added the clause to baserels */
     165       18178 :         if (rel == NULL)
     166         230 :             continue;
     167             : 
     168             :         /*
     169             :          * Remove the restrictinfo from the list.  Pointer comparison is
     170             :          * sufficient.
     171             :          */
     172             :         Assert(list_member_ptr(rel->joininfo, restrictinfo));
     173       17948 :         rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
     174             :     }
     175        8926 : }

Generated by: LCOV version 1.14