LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - joininfo.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 43 43 100.0 %
Date: 2025-01-18 04:15:08 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-2025, 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      336246 : have_relevant_joinclause(PlannerInfo *root,
      40             :                          RelOptInfo *rel1, RelOptInfo *rel2)
      41             : {
      42      336246 :     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      336246 :     if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
      52             :     {
      53      254484 :         joininfo = rel1->joininfo;
      54      254484 :         other_relids = rel2->relids;
      55             :     }
      56             :     else
      57             :     {
      58       81762 :         joininfo = rel2->joininfo;
      59       81762 :         other_relids = rel1->relids;
      60             :     }
      61             : 
      62      360578 :     foreach(l, joininfo)
      63             :     {
      64      159322 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
      65             : 
      66      159322 :         if (bms_overlap(other_relids, rinfo->required_relids))
      67             :         {
      68      134990 :             result = true;
      69      134990 :             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      336246 :     if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
      78      153708 :         result = have_relevant_eclass_joinclause(root, rel1, rel2);
      79             : 
      80      336246 :     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       61718 : 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       61718 :     if (restriction_is_always_true(root, restrictinfo))
     106          24 :         return;
     107             : 
     108             :     /*
     109             :      * Substitute the origin qual with constant-FALSE if it is provably always
     110             :      * false.
     111             :      *
     112             :      * Note that we need to keep the same rinfo_serial, since it is in
     113             :      * practice the same condition.  We also need to reset the
     114             :      * last_rinfo_serial counter, which is essential to ensure that the
     115             :      * RestrictInfos for the "same" qual condition get identical serial
     116             :      * numbers (see deconstruct_distribute_oj_quals).
     117             :      */
     118       61694 :     if (restriction_is_always_false(root, restrictinfo))
     119             :     {
     120          18 :         int         save_rinfo_serial = restrictinfo->rinfo_serial;
     121          18 :         int         save_last_rinfo_serial = root->last_rinfo_serial;
     122             : 
     123          18 :         restrictinfo = make_restrictinfo(root,
     124          18 :                                          (Expr *) makeBoolConst(false, false),
     125          18 :                                          restrictinfo->is_pushed_down,
     126          18 :                                          restrictinfo->has_clone,
     127          18 :                                          restrictinfo->is_clone,
     128          18 :                                          restrictinfo->pseudoconstant,
     129             :                                          0, /* security_level */
     130             :                                          restrictinfo->required_relids,
     131             :                                          restrictinfo->incompatible_relids,
     132             :                                          restrictinfo->outer_relids);
     133          18 :         restrictinfo->rinfo_serial = save_rinfo_serial;
     134          18 :         root->last_rinfo_serial = save_last_rinfo_serial;
     135             :     }
     136             : 
     137       61694 :     cur_relid = -1;
     138      198884 :     while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
     139             :     {
     140      137190 :         RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
     141             : 
     142             :         /* We only need to add the clause to baserels */
     143      137190 :         if (rel == NULL)
     144        8154 :             continue;
     145      129036 :         rel->joininfo = lappend(rel->joininfo, restrictinfo);
     146             :     }
     147             : }
     148             : 
     149             : /*
     150             :  * remove_join_clause_from_rels
     151             :  *    Delete 'restrictinfo' from all the joininfo lists it is in
     152             :  *
     153             :  * This reverses the effect of add_join_clause_to_rels.  It's used when we
     154             :  * discover that a relation need not be joined at all.
     155             :  *
     156             :  * 'restrictinfo' describes the join clause
     157             :  * 'join_relids' is the set of relations participating in the join clause
     158             :  *               (some of these could be outer joins)
     159             :  */
     160             : void
     161        9914 : remove_join_clause_from_rels(PlannerInfo *root,
     162             :                              RestrictInfo *restrictinfo,
     163             :                              Relids join_relids)
     164             : {
     165             :     int         cur_relid;
     166             : 
     167        9914 :     cur_relid = -1;
     168       30118 :     while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
     169             :     {
     170       20204 :         RelOptInfo *rel = find_base_rel_ignore_join(root, cur_relid);
     171             : 
     172             :         /* We would only have added the clause to baserels */
     173       20204 :         if (rel == NULL)
     174         256 :             continue;
     175             : 
     176             :         /*
     177             :          * Remove the restrictinfo from the list.  Pointer comparison is
     178             :          * sufficient.
     179             :          */
     180             :         Assert(list_member_ptr(rel->joininfo, restrictinfo));
     181       19948 :         rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
     182             :     }
     183        9914 : }

Generated by: LCOV version 1.14