LCOV - code coverage report
Current view: top level - src/backend/optimizer/plan - analyzejoins.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 97.6 % 754 736
Test Date: 2026-07-11 18:15:35 Functions: 100.0 % 29 29
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 88.9 % 702 624

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * analyzejoins.c
       4                 :             :  *    Routines for simplifying joins after initial query analysis
       5                 :             :  *
       6                 :             :  * While we do a great deal of join simplification in prep/prepjointree.c,
       7                 :             :  * certain optimizations cannot be performed at that stage for lack of
       8                 :             :  * detailed information about the query.  The routines here are invoked
       9                 :             :  * after initsplan.c has done its work, and can do additional join removal
      10                 :             :  * and simplification steps based on the information extracted.  The penalty
      11                 :             :  * is that we have to work harder to clean up after ourselves when we modify
      12                 :             :  * the query, since the derived data structures have to be updated too.
      13                 :             :  *
      14                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      15                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      16                 :             :  *
      17                 :             :  *
      18                 :             :  * IDENTIFICATION
      19                 :             :  *    src/backend/optimizer/plan/analyzejoins.c
      20                 :             :  *
      21                 :             :  *-------------------------------------------------------------------------
      22                 :             :  */
      23                 :             : #include "postgres.h"
      24                 :             : 
      25                 :             : #include "catalog/pg_class.h"
      26                 :             : #include "nodes/nodeFuncs.h"
      27                 :             : #include "optimizer/joininfo.h"
      28                 :             : #include "optimizer/optimizer.h"
      29                 :             : #include "optimizer/pathnode.h"
      30                 :             : #include "optimizer/paths.h"
      31                 :             : #include "optimizer/placeholder.h"
      32                 :             : #include "optimizer/planmain.h"
      33                 :             : #include "optimizer/restrictinfo.h"
      34                 :             : #include "parser/parse_agg.h"
      35                 :             : #include "rewrite/rewriteManip.h"
      36                 :             : #include "utils/lsyscache.h"
      37                 :             : 
      38                 :             : /*
      39                 :             :  * Utility structure.  A sorting procedure is needed to simplify the search
      40                 :             :  * of SJE-candidate baserels referencing the same database relation.  Having
      41                 :             :  * collected all baserels from the query jointree, the planner sorts them
      42                 :             :  * according to the reloid value, groups them with the next pass and attempts
      43                 :             :  * to remove self-joins.
      44                 :             :  *
      45                 :             :  * Preliminary sorting prevents quadratic behavior that can be harmful in the
      46                 :             :  * case of numerous joins.
      47                 :             :  */
      48                 :             : typedef struct
      49                 :             : {
      50                 :             :     int         relid;
      51                 :             :     Oid         reloid;
      52                 :             : } SelfJoinCandidate;
      53                 :             : 
      54                 :             : bool        enable_self_join_elimination;
      55                 :             : 
      56                 :             : /* local functions */
      57                 :             : static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo);
      58                 :             : static void remove_leftjoinrel_from_query(PlannerInfo *root, int relid,
      59                 :             :                                           SpecialJoinInfo *sjinfo);
      60                 :             : static void remove_rel_from_query(PlannerInfo *root, int relid,
      61                 :             :                                   int subst, SpecialJoinInfo *sjinfo,
      62                 :             :                                   Relids joinrelids);
      63                 :             : static void remove_rel_from_restrictinfo(RestrictInfo *rinfo,
      64                 :             :                                          int relid, int ojrelid);
      65                 :             : static void remove_rel_from_eclass(PlannerInfo *root, EquivalenceClass *ec,
      66                 :             :                                    int relid, int ojrelid);
      67                 :             : static Node *remove_rel_from_phvs(Node *node, int relid, int ojrelid);
      68                 :             : static Node *remove_rel_from_phvs_mutator(Node *node, Relids removable);
      69                 :             : static List *remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved);
      70                 :             : static bool rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel);
      71                 :             : static bool rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel,
      72                 :             :                                 List *clause_list, List **extra_clauses);
      73                 :             : static DistinctColInfo *distinct_col_search(int colno, List *distinct_cols);
      74                 :             : static bool is_innerrel_unique_for(PlannerInfo *root,
      75                 :             :                                    Relids joinrelids,
      76                 :             :                                    Relids outerrelids,
      77                 :             :                                    RelOptInfo *innerrel,
      78                 :             :                                    JoinType jointype,
      79                 :             :                                    List *restrictlist,
      80                 :             :                                    List **extra_clauses);
      81                 :             : static int  self_join_candidates_cmp(const void *a, const void *b);
      82                 :             : static bool replace_relid_callback(Node *node,
      83                 :             :                                    ChangeVarNodes_context *context);
      84                 :             : 
      85                 :             : 
      86                 :             : /*
      87                 :             :  * remove_useless_joins
      88                 :             :  *      Check for relations that don't actually need to be joined at all,
      89                 :             :  *      and remove them from the query.
      90                 :             :  *
      91                 :             :  * We are passed the current joinlist and return the updated list.  Other
      92                 :             :  * data structures that have to be updated are accessible via "root".
      93                 :             :  */
      94                 :             : List *
      95                 :      248597 : remove_useless_joins(PlannerInfo *root, List *joinlist)
      96                 :             : {
      97                 :             :     ListCell   *lc;
      98                 :             : 
      99                 :             :     /*
     100                 :             :      * We are only interested in relations that are left-joined to, so we can
     101                 :             :      * scan the join_info_list to find them easily.
     102                 :             :      */
     103                 :      257031 : restart:
     104   [ +  +  +  +  :      291486 :     foreach(lc, root->join_info_list)
                   +  + ]
     105                 :             :     {
     106                 :       42889 :         SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
     107                 :             :         int         innerrelid;
     108                 :             :         int         nremoved;
     109                 :             : 
     110                 :             :         /* Skip if not removable */
     111         [ +  + ]:       42889 :         if (!join_is_removable(root, sjinfo))
     112                 :       34455 :             continue;
     113                 :             : 
     114                 :             :         /*
     115                 :             :          * Currently, join_is_removable can only succeed when the sjinfo's
     116                 :             :          * righthand is a single baserel.  Remove that rel from the query and
     117                 :             :          * joinlist.
     118                 :             :          */
     119                 :        8434 :         innerrelid = bms_singleton_member(sjinfo->min_righthand);
     120                 :             : 
     121                 :        8434 :         remove_leftjoinrel_from_query(root, innerrelid, sjinfo);
     122                 :             : 
     123                 :             :         /* We verify that exactly one reference gets removed from joinlist */
     124                 :        8434 :         nremoved = 0;
     125                 :        8434 :         joinlist = remove_rel_from_joinlist(joinlist, innerrelid, &nremoved);
     126         [ -  + ]:        8434 :         if (nremoved != 1)
     127         [ #  # ]:           0 :             elog(ERROR, "failed to find relation %d in joinlist", innerrelid);
     128                 :             : 
     129                 :             :         /*
     130                 :             :          * We can delete this SpecialJoinInfo from the list too, since it's no
     131                 :             :          * longer of interest.  (Since we'll restart the foreach loop
     132                 :             :          * immediately, we don't bother with foreach_delete_current.)
     133                 :             :          */
     134                 :        8434 :         root->join_info_list = list_delete_cell(root->join_info_list, lc);
     135                 :             : 
     136                 :             :         /*
     137                 :             :          * Restart the scan.  This is necessary to ensure we find all
     138                 :             :          * removable joins independently of ordering of the join_info_list
     139                 :             :          * (note that removal of attr_needed bits may make a join appear
     140                 :             :          * removable that did not before).
     141                 :             :          */
     142                 :        8434 :         goto restart;
     143                 :             :     }
     144                 :             : 
     145                 :      248597 :     return joinlist;
     146                 :             : }
     147                 :             : 
     148                 :             : /*
     149                 :             :  * join_is_removable
     150                 :             :  *    Check whether we need not perform this special join at all, because
     151                 :             :  *    it will just duplicate its left input.
     152                 :             :  *
     153                 :             :  * This is true for a left join for which the join condition cannot match
     154                 :             :  * more than one inner-side row.  (There are other possibly interesting
     155                 :             :  * cases, but we don't have the infrastructure to prove them.)  We also
     156                 :             :  * have to check that the inner side doesn't generate any variables needed
     157                 :             :  * above the join.
     158                 :             :  */
     159                 :             : static bool
     160                 :       42889 : join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
     161                 :             : {
     162                 :             :     int         innerrelid;
     163                 :             :     RelOptInfo *innerrel;
     164                 :             :     Relids      inputrelids;
     165                 :             :     Relids      joinrelids;
     166                 :       42889 :     List       *clause_list = NIL;
     167                 :             :     ListCell   *l;
     168                 :             :     int         attroff;
     169                 :             : 
     170                 :             :     /*
     171                 :             :      * Must be a left join to a single baserel, else we aren't going to be
     172                 :             :      * able to do anything with it.
     173                 :             :      */
     174         [ +  + ]:       42889 :     if (sjinfo->jointype != JOIN_LEFT)
     175                 :       10585 :         return false;
     176                 :             : 
     177         [ +  + ]:       32304 :     if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
     178                 :        1058 :         return false;
     179                 :             : 
     180                 :             :     /*
     181                 :             :      * Never try to eliminate a left join to the query result rel.  Although
     182                 :             :      * the case is syntactically impossible in standard SQL, MERGE will build
     183                 :             :      * a join tree that looks exactly like that.
     184                 :             :      */
     185         [ +  + ]:       31246 :     if (innerrelid == root->parse->resultRelation)
     186                 :         636 :         return false;
     187                 :             : 
     188                 :       30610 :     innerrel = find_base_rel(root, innerrelid);
     189                 :             : 
     190                 :             :     /*
     191                 :             :      * Before we go to the effort of checking whether any innerrel variables
     192                 :             :      * are needed above the join, make a quick check to eliminate cases in
     193                 :             :      * which we will surely be unable to prove uniqueness of the innerrel.
     194                 :             :      */
     195         [ +  + ]:       30610 :     if (!rel_supports_distinctness(root, innerrel))
     196                 :        2442 :         return false;
     197                 :             : 
     198                 :             :     /* Compute the relid set for the join we are considering */
     199                 :       28168 :     inputrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
     200                 :             :     Assert(sjinfo->ojrelid != 0);
     201                 :       28168 :     joinrelids = bms_copy(inputrelids);
     202                 :       28168 :     joinrelids = bms_add_member(joinrelids, sjinfo->ojrelid);
     203                 :             : 
     204                 :             :     /*
     205                 :             :      * We can't remove the join if any inner-rel attributes are used above the
     206                 :             :      * join.  Here, "above" the join includes pushed-down conditions, so we
     207                 :             :      * should reject if attr_needed includes the OJ's own relid; therefore,
     208                 :             :      * compare to inputrelids not joinrelids.
     209                 :             :      *
     210                 :             :      * As a micro-optimization, it seems better to start with max_attr and
     211                 :             :      * count down rather than starting with min_attr and counting up, on the
     212                 :             :      * theory that the system attributes are somewhat less likely to be wanted
     213                 :             :      * and should be tested last.
     214                 :             :      */
     215                 :       28168 :     for (attroff = innerrel->max_attr - innerrel->min_attr;
     216         [ +  + ]:      268817 :          attroff >= 0;
     217                 :      240649 :          attroff--)
     218                 :             :     {
     219         [ +  + ]:      260116 :         if (!bms_is_subset(innerrel->attr_needed[attroff], inputrelids))
     220                 :       19467 :             return false;
     221                 :             :     }
     222                 :             : 
     223                 :             :     /*
     224                 :             :      * Similarly check that the inner rel isn't needed by any PlaceHolderVars
     225                 :             :      * that will be used above the join.  The PHV case is a little bit more
     226                 :             :      * complicated, because PHVs may have been assigned a ph_eval_at location
     227                 :             :      * that includes the innerrel, yet their contained expression might not
     228                 :             :      * actually reference the innerrel (it could be just a constant, for
     229                 :             :      * instance).  If such a PHV is due to be evaluated above the join then it
     230                 :             :      * needn't prevent join removal.
     231                 :             :      */
     232   [ +  +  +  +  :        8865 :     foreach(l, root->placeholder_list)
                   +  + ]
     233                 :             :     {
     234                 :         194 :         PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
     235                 :             : 
     236         [ -  + ]:         194 :         if (bms_overlap(phinfo->ph_lateral, innerrel->relids))
     237                 :          30 :             return false;       /* it references innerrel laterally */
     238         [ +  + ]:         194 :         if (!bms_overlap(phinfo->ph_eval_at, innerrel->relids))
     239                 :          61 :             continue;           /* it definitely doesn't reference innerrel */
     240         [ +  + ]:         133 :         if (bms_is_subset(phinfo->ph_needed, inputrelids))
     241                 :           5 :             continue;           /* PHV is not used above the join */
     242         [ +  + ]:         128 :         if (!bms_is_member(sjinfo->ojrelid, phinfo->ph_eval_at))
     243                 :          25 :             return false;       /* it has to be evaluated below the join */
     244                 :             : 
     245                 :             :         /*
     246                 :             :          * We need to be sure there will still be a place to evaluate the PHV
     247                 :             :          * if we remove the join, ie that ph_eval_at wouldn't become empty.
     248                 :             :          */
     249         [ +  + ]:         103 :         if (!bms_overlap(sjinfo->min_lefthand, phinfo->ph_eval_at))
     250                 :           5 :             return false;       /* there isn't any other place to eval PHV */
     251                 :             :         /* Check contained expression last, since this is a bit expensive */
     252         [ -  + ]:          98 :         if (bms_overlap(pull_varnos(root, (Node *) phinfo->ph_var->phexpr),
     253                 :          98 :                         innerrel->relids))
     254                 :           0 :             return false;       /* contained expression references innerrel */
     255                 :             :     }
     256                 :             : 
     257                 :             :     /*
     258                 :             :      * Search for mergejoinable clauses that constrain the inner rel against
     259                 :             :      * either the outer rel or a pseudoconstant.  If an operator is
     260                 :             :      * mergejoinable then it behaves like equality for some btree opclass, so
     261                 :             :      * it's what we want.  The mergejoinability test also eliminates clauses
     262                 :             :      * containing volatile functions, which we couldn't depend on.
     263                 :             :      */
     264   [ +  +  +  +  :       17505 :     foreach(l, innerrel->joininfo)
                   +  + ]
     265                 :             :     {
     266                 :        8834 :         RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l);
     267                 :             : 
     268                 :             :         /*
     269                 :             :          * If the current join commutes with some other outer join(s) via
     270                 :             :          * outer join identity 3, there will be multiple clones of its join
     271                 :             :          * clauses in the joininfo list.  We want to consider only the
     272                 :             :          * has_clone form of such clauses.  Processing more than one form
     273                 :             :          * would be wasteful, and also some of the others would confuse the
     274                 :             :          * RINFO_IS_PUSHED_DOWN test below.
     275                 :             :          */
     276         [ +  + ]:        8834 :         if (restrictinfo->is_clone)
     277                 :          82 :             continue;           /* ignore it */
     278                 :             : 
     279                 :             :         /*
     280                 :             :          * If it's not a join clause for this outer join, we can't use it.
     281                 :             :          * Note that if the clause is pushed-down, then it is logically from
     282                 :             :          * above the outer join, even if it references no other rels (it might
     283                 :             :          * be from WHERE, for example).
     284                 :             :          */
     285   [ +  +  +  + ]:        8752 :         if (RINFO_IS_PUSHED_DOWN(restrictinfo, joinrelids))
     286                 :          99 :             continue;           /* ignore; not useful here */
     287                 :             : 
     288                 :             :         /* Ignore if it's not a mergejoinable clause */
     289         [ +  + ]:        8653 :         if (!restrictinfo->can_join ||
     290         [ -  + ]:        8507 :             restrictinfo->mergeopfamilies == NIL)
     291                 :         146 :             continue;           /* not mergejoinable */
     292                 :             : 
     293                 :             :         /*
     294                 :             :          * Check if the clause has the form "outer op inner" or "inner op
     295                 :             :          * outer", and if so mark which side is inner.
     296                 :             :          */
     297         [ +  + ]:        8507 :         if (!clause_sides_match_join(restrictinfo, sjinfo->min_lefthand,
     298                 :             :                                      innerrel->relids))
     299                 :           5 :             continue;           /* no good for these input relations */
     300                 :             : 
     301                 :             :         /* OK, add to list */
     302                 :        8502 :         clause_list = lappend(clause_list, restrictinfo);
     303                 :             :     }
     304                 :             : 
     305                 :             :     /*
     306                 :             :      * Now that we have the relevant equality join clauses, try to prove the
     307                 :             :      * innerrel distinct.
     308                 :             :      */
     309         [ +  + ]:        8671 :     if (rel_is_distinct_for(root, innerrel, clause_list, NULL))
     310                 :        8434 :         return true;
     311                 :             : 
     312                 :             :     /*
     313                 :             :      * Some day it would be nice to check for other methods of establishing
     314                 :             :      * distinctness.
     315                 :             :      */
     316                 :         237 :     return false;
     317                 :             : }
     318                 :             : 
     319                 :             : /*
     320                 :             :  * Remove the target relid and references to the target join from the
     321                 :             :  * planner's data structures, having determined that there is no need
     322                 :             :  * to include them in the query.
     323                 :             :  *
     324                 :             :  * We are not terribly thorough here.  We only bother to update parts of
     325                 :             :  * the planner's data structures that will actually be consulted later.
     326                 :             :  */
     327                 :             : static void
     328                 :        8434 : remove_leftjoinrel_from_query(PlannerInfo *root, int relid,
     329                 :             :                               SpecialJoinInfo *sjinfo)
     330                 :             : {
     331                 :        8434 :     RelOptInfo *rel = find_base_rel(root, relid);
     332                 :        8434 :     int         ojrelid = sjinfo->ojrelid;
     333                 :             :     Relids      joinrelids;
     334                 :             :     Relids      join_plus_commute;
     335                 :             :     List       *joininfos;
     336                 :             :     ListCell   *l;
     337                 :             : 
     338                 :             :     /* Compute the relid set for the join we are considering */
     339                 :        8434 :     joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
     340                 :             :     Assert(ojrelid != 0);
     341                 :        8434 :     joinrelids = bms_add_member(joinrelids, ojrelid);
     342                 :             : 
     343                 :        8434 :     remove_rel_from_query(root, relid, -1, sjinfo, joinrelids);
     344                 :             : 
     345                 :             :     /*
     346                 :             :      * Remove any joinquals referencing the rel from the joininfo lists.
     347                 :             :      *
     348                 :             :      * In some cases, a joinqual has to be put back after deleting its
     349                 :             :      * reference to the target rel.  This can occur for pseudoconstant and
     350                 :             :      * outerjoin-delayed quals, which can get marked as requiring the rel in
     351                 :             :      * order to force them to be evaluated at or above the join.  We can't
     352                 :             :      * just discard them, though.  Only quals that logically belonged to the
     353                 :             :      * outer join being discarded should be removed from the query.
     354                 :             :      *
     355                 :             :      * We might encounter a qual that is a clone of a deletable qual with some
     356                 :             :      * outer-join relids added (see deconstruct_distribute_oj_quals).  To
     357                 :             :      * ensure we get rid of such clones as well, add the relids of all OJs
     358                 :             :      * commutable with this one to the set we test against for
     359                 :             :      * pushed-down-ness.
     360                 :             :      */
     361                 :        8434 :     join_plus_commute = bms_union(joinrelids,
     362                 :        8434 :                                   sjinfo->commute_above_r);
     363                 :        8434 :     join_plus_commute = bms_add_members(join_plus_commute,
     364                 :        8434 :                                         sjinfo->commute_below_l);
     365                 :             : 
     366                 :             :     /*
     367                 :             :      * We must make a copy of the rel's old joininfo list before starting the
     368                 :             :      * loop, because otherwise remove_join_clause_from_rels would destroy the
     369                 :             :      * list while we're scanning it.
     370                 :             :      */
     371                 :        8434 :     joininfos = list_copy(rel->joininfo);
     372   [ +  +  +  +  :       17047 :     foreach(l, joininfos)
                   +  + ]
     373                 :             :     {
     374                 :        8613 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
     375                 :             : 
     376                 :        8613 :         remove_join_clause_from_rels(root, rinfo, rinfo->required_relids);
     377                 :             : 
     378   [ +  +  +  + ]:        8613 :         if (RINFO_IS_PUSHED_DOWN(rinfo, join_plus_commute))
     379                 :             :         {
     380                 :             :             /*
     381                 :             :              * There might be references to relid or ojrelid in the
     382                 :             :              * RestrictInfo's relid sets, as a consequence of PHVs having had
     383                 :             :              * ph_eval_at sets that include those.  We already checked above
     384                 :             :              * that any such PHV is safe (and updated its ph_eval_at), so we
     385                 :             :              * can just drop those references.
     386                 :             :              */
     387                 :          99 :             remove_rel_from_restrictinfo(rinfo, relid, ojrelid);
     388                 :             : 
     389                 :             :             /*
     390                 :             :              * Cross-check that the clause itself does not reference the
     391                 :             :              * target rel or join.
     392                 :             :              */
     393                 :             : #ifdef USE_ASSERT_CHECKING
     394                 :             :             {
     395                 :             :                 Relids      clause_varnos = pull_varnos(root,
     396                 :             :                                                         (Node *) rinfo->clause);
     397                 :             : 
     398                 :             :                 Assert(!bms_is_member(relid, clause_varnos));
     399                 :             :                 Assert(!bms_is_member(ojrelid, clause_varnos));
     400                 :             :             }
     401                 :             : #endif
     402                 :             :             /* Now throw it back into the joininfo lists */
     403                 :          99 :             distribute_restrictinfo_to_rels(root, rinfo);
     404                 :             :         }
     405                 :             :     }
     406                 :             : 
     407                 :             :     /*
     408                 :             :      * There may be references to the rel in root->fkey_list, but if so,
     409                 :             :      * match_foreign_keys_to_quals() will get rid of them.
     410                 :             :      */
     411                 :             : 
     412                 :             :     /*
     413                 :             :      * Now remove the rel from the baserel array to prevent it from being
     414                 :             :      * referenced again.  (We can't do this earlier because
     415                 :             :      * remove_join_clause_from_rels will touch it.)
     416                 :             :      */
     417                 :        8434 :     root->simple_rel_array[relid] = NULL;
     418                 :        8434 :     root->simple_rte_array[relid] = NULL;
     419                 :             : 
     420                 :             :     /* And nuke the RelOptInfo, just in case there's another access path */
     421                 :        8434 :     pfree(rel);
     422                 :             : 
     423                 :             :     /*
     424                 :             :      * Now repeat construction of attr_needed bits coming from all other
     425                 :             :      * sources.
     426                 :             :      */
     427                 :        8434 :     rebuild_placeholder_attr_needed(root);
     428                 :        8434 :     rebuild_joinclause_attr_needed(root);
     429                 :        8434 :     rebuild_eclass_attr_needed(root);
     430                 :        8434 :     rebuild_lateral_attr_needed(root);
     431                 :        8434 : }
     432                 :             : 
     433                 :             : /*
     434                 :             :  * Remove the target relid and references to the target join from the
     435                 :             :  * planner's data structures, having determined that there is no need
     436                 :             :  * to include them in the query.  Optionally replace references to the
     437                 :             :  * removed relid with subst if this is a self-join removal.
     438                 :             :  *
     439                 :             :  * This function serves as the common infrastructure for left-join removal
     440                 :             :  * and self-join elimination.  It is intentionally scoped to update only the
     441                 :             :  * shared planner data structures that are universally affected by relation
     442                 :             :  * removal.  Each specific caller remains responsible for updating any
     443                 :             :  * remaining data structures required by its unique removal logic.
     444                 :             :  *
     445                 :             :  * The specific type of removal being performed is dictated by the combination
     446                 :             :  * of the sjinfo and subst parameters.  A non-NULL sjinfo indicates left-join
     447                 :             :  * removal.  When sjinfo is NULL, a positive subst value indicates self-join
     448                 :             :  * elimination (where references are replaced with subst).
     449                 :             :  */
     450                 :             : static void
     451                 :        8902 : remove_rel_from_query(PlannerInfo *root, int relid,
     452                 :             :                       int subst, SpecialJoinInfo *sjinfo,
     453                 :             :                       Relids joinrelids)
     454                 :             : {
     455         [ +  + ]:        8902 :     int         ojrelid = sjinfo ? sjinfo->ojrelid : 0;
     456                 :             :     Index       rti;
     457                 :             :     ListCell   *l;
     458                 :        8902 :     bool        is_outer_join = (sjinfo != NULL);
     459   [ +  +  +  - ]:        8902 :     bool        is_self_join = (!is_outer_join && subst > 0);
     460                 :             : 
     461                 :             :     Assert(is_outer_join || is_self_join);
     462                 :             :     Assert(!is_outer_join || ojrelid > 0);
     463                 :             :     Assert(!is_outer_join || joinrelids != NULL);
     464                 :             : 
     465                 :             :     /*
     466                 :             :      * Update all_baserels and related relid sets.
     467                 :             :      */
     468                 :        8902 :     root->all_baserels = adjust_relid_set(root->all_baserels, relid, subst);
     469                 :        8902 :     root->all_query_rels = adjust_relid_set(root->all_query_rels, relid, subst);
     470                 :             : 
     471         [ +  + ]:        8902 :     if (is_outer_join)
     472                 :             :     {
     473                 :        8434 :         root->outer_join_rels = bms_del_member(root->outer_join_rels, ojrelid);
     474                 :        8434 :         root->all_query_rels = bms_del_member(root->all_query_rels, ojrelid);
     475                 :             :     }
     476                 :             : 
     477                 :             :     /*
     478                 :             :      * Likewise remove references from SpecialJoinInfo data structures.
     479                 :             :      *
     480                 :             :      * This is relevant in case the relation we're deleting is part of the
     481                 :             :      * relid sets of special joins: those sets have to be adjusted.  If we are
     482                 :             :      * removing an outer join, the RHS of the target outer join will be made
     483                 :             :      * empty here, but that's OK since the caller will delete that
     484                 :             :      * SpecialJoinInfo entirely.
     485                 :             :      */
     486   [ +  +  +  +  :       21109 :     foreach(l, root->join_info_list)
                   +  + ]
     487                 :             :     {
     488                 :       12207 :         SpecialJoinInfo *sjinf = (SpecialJoinInfo *) lfirst(l);
     489                 :             : 
     490                 :             :         /*
     491                 :             :          * initsplan.c is fairly cavalier about allowing SpecialJoinInfos'
     492                 :             :          * lefthand/righthand relid sets to be shared with other data
     493                 :             :          * structures.  Ensure that we don't modify the original relid sets.
     494                 :             :          * (The commute_xxx sets are always per-SpecialJoinInfo though.)
     495                 :             :          */
     496                 :       12207 :         sjinf->min_lefthand = bms_copy(sjinf->min_lefthand);
     497                 :       12207 :         sjinf->min_righthand = bms_copy(sjinf->min_righthand);
     498                 :       12207 :         sjinf->syn_lefthand = bms_copy(sjinf->syn_lefthand);
     499                 :       12207 :         sjinf->syn_righthand = bms_copy(sjinf->syn_righthand);
     500                 :             : 
     501                 :             :         /* Now adjust relid bit in the sets: */
     502                 :       12207 :         sjinf->min_lefthand = adjust_relid_set(sjinf->min_lefthand, relid, subst);
     503                 :       12207 :         sjinf->min_righthand = adjust_relid_set(sjinf->min_righthand, relid, subst);
     504                 :       12207 :         sjinf->syn_lefthand = adjust_relid_set(sjinf->syn_lefthand, relid, subst);
     505                 :       12207 :         sjinf->syn_righthand = adjust_relid_set(sjinf->syn_righthand, relid, subst);
     506                 :             : 
     507         [ +  + ]:       12207 :         if (is_outer_join)
     508                 :             :         {
     509                 :             :             /* Remove ojrelid bit from the sets: */
     510                 :       12114 :             sjinf->min_lefthand = bms_del_member(sjinf->min_lefthand, ojrelid);
     511                 :       12114 :             sjinf->min_righthand = bms_del_member(sjinf->min_righthand, ojrelid);
     512                 :       12114 :             sjinf->syn_lefthand = bms_del_member(sjinf->syn_lefthand, ojrelid);
     513                 :       12114 :             sjinf->syn_righthand = bms_del_member(sjinf->syn_righthand, ojrelid);
     514                 :             :             /* relid cannot appear in these fields, but ojrelid can: */
     515                 :       12114 :             sjinf->commute_above_l = bms_del_member(sjinf->commute_above_l, ojrelid);
     516                 :       12114 :             sjinf->commute_above_r = bms_del_member(sjinf->commute_above_r, ojrelid);
     517                 :       12114 :             sjinf->commute_below_l = bms_del_member(sjinf->commute_below_l, ojrelid);
     518                 :       12114 :             sjinf->commute_below_r = bms_del_member(sjinf->commute_below_r, ojrelid);
     519                 :             :         }
     520                 :             :         else
     521                 :             :         {
     522                 :             :             /*
     523                 :             :              * For self-join removal, replace relid references in
     524                 :             :              * semi_rhs_exprs.
     525                 :             :              */
     526                 :          93 :             ChangeVarNodesExtended((Node *) sjinf->semi_rhs_exprs, relid, subst,
     527                 :             :                                    0, replace_relid_callback);
     528                 :             :         }
     529                 :             :     }
     530                 :             : 
     531                 :             :     /*
     532                 :             :      * Likewise remove references from PlaceHolderVar data structures,
     533                 :             :      * removing any no-longer-needed placeholders entirely.  We only remove
     534                 :             :      * PHVs for left-join removal.  With self-join elimination, PHVs already
     535                 :             :      * get moved to the remaining relation, where they might still be needed.
     536                 :             :      * It might also happen that we skip the removal of some PHVs that could
     537                 :             :      * be removed.  However, the overhead of extra PHVs is small compared to
     538                 :             :      * the complexity of analysis needed to remove them.
     539                 :             :      *
     540                 :             :      * Removal is a bit trickier than it might seem: we can remove PHVs that
     541                 :             :      * are used at the target rel and/or in the join qual, but not those that
     542                 :             :      * are used at join partner rels or above the join.  It's not that easy to
     543                 :             :      * distinguish PHVs used at partner rels from those used in the join qual,
     544                 :             :      * since they will both have ph_needed sets that are subsets of
     545                 :             :      * joinrelids.  However, a PHV used at a partner rel could not have the
     546                 :             :      * target rel in ph_eval_at, so we check that while deciding whether to
     547                 :             :      * remove or just update the PHV.  There is no corresponding test in
     548                 :             :      * join_is_removable because it doesn't need to distinguish those cases.
     549                 :             :      */
     550   [ +  +  +  +  :        9086 :     foreach(l, root->placeholder_list)
                   +  + ]
     551                 :             :     {
     552                 :         184 :         PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
     553                 :             : 
     554                 :             :         Assert(!is_outer_join || !bms_is_member(relid, phinfo->ph_lateral));
     555                 :             : 
     556   [ +  +  +  + ]:         333 :         if (is_outer_join &&
     557         [ +  + ]:         179 :             bms_is_subset(phinfo->ph_needed, joinrelids) &&
     558                 :          30 :             bms_is_member(relid, phinfo->ph_eval_at) &&
     559         [ +  + ]:          10 :             !bms_is_member(ojrelid, phinfo->ph_eval_at))
     560                 :             :         {
     561                 :           5 :             root->placeholder_list = foreach_delete_current(root->placeholder_list,
     562                 :             :                                                             l);
     563                 :           5 :             root->placeholder_array[phinfo->phid] = NULL;
     564                 :             :         }
     565                 :             :         else
     566                 :             :         {
     567                 :         179 :             PlaceHolderVar *phv = phinfo->ph_var;
     568                 :             : 
     569                 :         179 :             phinfo->ph_eval_at = adjust_relid_set(phinfo->ph_eval_at, relid, subst);
     570         [ +  + ]:         179 :             if (is_outer_join)
     571                 :         144 :                 phinfo->ph_eval_at = bms_del_member(phinfo->ph_eval_at, ojrelid);
     572                 :             :             Assert(!bms_is_empty(phinfo->ph_eval_at));   /* checked previously */
     573                 :             : 
     574                 :             :             /* Reduce ph_needed to contain only "relation 0"; see below */
     575         [ +  + ]:         179 :             if (bms_is_member(0, phinfo->ph_needed))
     576                 :          92 :                 phinfo->ph_needed = bms_make_singleton(0);
     577                 :             :             else
     578                 :          87 :                 phinfo->ph_needed = NULL;
     579                 :             : 
     580                 :         179 :             phv->phrels = adjust_relid_set(phv->phrels, relid, subst);
     581         [ +  + ]:         179 :             if (is_outer_join)
     582                 :         144 :                 phv->phrels = bms_del_member(phv->phrels, ojrelid);
     583                 :             :             Assert(!bms_is_empty(phv->phrels));
     584                 :             : 
     585                 :             :             /*
     586                 :             :              * For self-join removal, update Var nodes within the PHV's
     587                 :             :              * expression to reference the replacement relid, and adjust
     588                 :             :              * ph_lateral for the relid substitution.  (For left-join removal,
     589                 :             :              * we're removing rather than replacing, and any surviving PHV
     590                 :             :              * shouldn't reference the removed rel in its expression.  Also,
     591                 :             :              * relid can't appear in ph_lateral for outer joins.)
     592                 :             :              */
     593         [ +  + ]:         179 :             if (is_self_join)
     594                 :             :             {
     595                 :          35 :                 ChangeVarNodesExtended((Node *) phv->phexpr, relid, subst, 0,
     596                 :             :                                        replace_relid_callback);
     597                 :          35 :                 phinfo->ph_lateral = adjust_relid_set(phinfo->ph_lateral, relid, subst);
     598                 :             : 
     599                 :             :                 /*
     600                 :             :                  * ph_lateral might contain rels mentioned in ph_eval_at after
     601                 :             :                  * the replacement, remove them.
     602                 :             :                  */
     603                 :          35 :                 phinfo->ph_lateral = bms_difference(phinfo->ph_lateral, phinfo->ph_eval_at);
     604                 :             :                 /* ph_lateral might or might not be empty */
     605                 :             :             }
     606                 :             : 
     607                 :             :             Assert(phv->phnullingrels == NULL); /* no need to adjust */
     608                 :             :         }
     609                 :             :     }
     610                 :             : 
     611                 :             :     /*
     612                 :             :      * Likewise remove references from EquivalenceClasses.
     613                 :             :      *
     614                 :             :      * For self-join removal, the caller has already updated the
     615                 :             :      * EquivalenceClasses, so we can skip this step.
     616                 :             :      */
     617         [ +  + ]:        8902 :     if (is_outer_join)
     618                 :             :     {
     619   [ +  -  +  +  :       48860 :         foreach(l, root->eq_classes)
                   +  + ]
     620                 :             :         {
     621                 :       40426 :             EquivalenceClass *ec = (EquivalenceClass *) lfirst(l);
     622                 :             : 
     623                 :       40426 :             remove_rel_from_eclass(root, ec, relid, ojrelid);
     624                 :             :         }
     625                 :             :     }
     626                 :             : 
     627                 :             :     /*
     628                 :             :      * Finally, we must prepare for the caller to recompute per-Var
     629                 :             :      * attr_needed and per-PlaceHolderVar ph_needed relid sets.  These have to
     630                 :             :      * be known accurately, else we may fail to remove other now-removable
     631                 :             :      * joins.  Because the caller removes the join clause(s) associated with
     632                 :             :      * the removed join, Vars that were formerly needed may no longer be.
     633                 :             :      *
     634                 :             :      * The actual reconstruction of these relid sets is performed by the
     635                 :             :      * specific caller.  Here, we simply clear out the existing attr_needed
     636                 :             :      * sets (we already did this above for ph_needed) to ensure they are
     637                 :             :      * rebuilt from scratch.  We can cheat to one small extent: we can avoid
     638                 :             :      * re-examining the targetlist and HAVING qual by preserving "relation 0"
     639                 :             :      * bits from the existing relid sets.  This is safe because we'd never
     640                 :             :      * remove such references.
     641                 :             :      *
     642                 :             :      * Additionally, if we are performing self-join elimination, we must
     643                 :             :      * replace references to the removed relid with subst within the
     644                 :             :      * lateral_vars lists.
     645                 :             :      *
     646                 :             :      * Also, for left-join removal, we strip the removed rel and join from any
     647                 :             :      * PlaceHolderVar embedded in the surviving rels' restriction clauses (see
     648                 :             :      * remove_rel_from_phvs); we needn't bother with the rel being removed,
     649                 :             :      * nor when the query has no PlaceHolderVars.
     650                 :             :      */
     651         [ +  + ]:       59100 :     for (rti = 1; rti < root->simple_rel_array_size; rti++)
     652                 :             :     {
     653                 :       50198 :         RelOptInfo *otherrel = root->simple_rel_array[rti];
     654                 :             :         int         attroff;
     655                 :             : 
     656                 :             :         /* there may be empty slots corresponding to non-baserel RTEs */
     657         [ +  + ]:       50198 :         if (otherrel == NULL)
     658                 :       24411 :             continue;
     659                 :             : 
     660                 :             :         Assert(otherrel->relid == rti); /* sanity check on array */
     661                 :             : 
     662                 :       25787 :         for (attroff = otherrel->max_attr - otherrel->min_attr;
     663         [ +  + ]:      564348 :              attroff >= 0;
     664                 :      538561 :              attroff--)
     665                 :             :         {
     666         [ +  + ]:      538561 :             if (bms_is_member(0, otherrel->attr_needed[attroff]))
     667                 :       37725 :                 otherrel->attr_needed[attroff] = bms_make_singleton(0);
     668                 :             :             else
     669                 :      500836 :                 otherrel->attr_needed[attroff] = NULL;
     670                 :             :         }
     671                 :             : 
     672         [ +  + ]:       25787 :         if (is_self_join)
     673                 :        1209 :             ChangeVarNodesExtended((Node *) otherrel->lateral_vars, relid,
     674                 :             :                                    subst, 0, replace_relid_callback);
     675                 :             : 
     676   [ +  +  +  +  :       25787 :         if (is_outer_join && rti != relid && root->glob->lastPHId != 0)
                   +  + ]
     677                 :             :         {
     678   [ +  +  +  +  :         808 :             foreach_node(RestrictInfo, rinfo, otherrel->baserestrictinfo)
                   +  + ]
     679                 :             :             {
     680                 :         124 :                 rinfo->clause = (Expr *)
     681                 :         124 :                     remove_rel_from_phvs((Node *) rinfo->clause, relid, ojrelid);
     682                 :             :             }
     683                 :             :         }
     684                 :             :     }
     685                 :        8902 : }
     686                 :             : 
     687                 :             : /*
     688                 :             :  * Remove any references to relid or ojrelid from the RestrictInfo.
     689                 :             :  *
     690                 :             :  * We only bother to clean out bits in the RestrictInfo's various relid sets,
     691                 :             :  * not nullingrel bits in contained Vars and PHVs.  (This might have to be
     692                 :             :  * improved sometime.)  However, if the RestrictInfo contains an OR clause
     693                 :             :  * we have to also clean up the sub-clauses.
     694                 :             :  */
     695                 :             : static void
     696                 :        3529 : remove_rel_from_restrictinfo(RestrictInfo *rinfo, int relid, int ojrelid)
     697                 :             : {
     698                 :             :     /*
     699                 :             :      * initsplan.c is fairly cavalier about allowing RestrictInfos to share
     700                 :             :      * relid sets with other RestrictInfos, and SpecialJoinInfos too.  Make
     701                 :             :      * sure this RestrictInfo has its own relid sets before we modify them.
     702                 :             :      * (In present usage, clause_relids is probably not shared, but
     703                 :             :      * required_relids could be; let's not assume anything.)
     704                 :             :      */
     705                 :        3529 :     rinfo->clause_relids = bms_copy(rinfo->clause_relids);
     706                 :        3529 :     rinfo->clause_relids = bms_del_member(rinfo->clause_relids, relid);
     707                 :        3529 :     rinfo->clause_relids = bms_del_member(rinfo->clause_relids, ojrelid);
     708                 :             :     /* Likewise for required_relids */
     709                 :        3529 :     rinfo->required_relids = bms_copy(rinfo->required_relids);
     710                 :        3529 :     rinfo->required_relids = bms_del_member(rinfo->required_relids, relid);
     711                 :        3529 :     rinfo->required_relids = bms_del_member(rinfo->required_relids, ojrelid);
     712                 :             :     /* Likewise for incompatible_relids */
     713                 :        3529 :     rinfo->incompatible_relids = bms_copy(rinfo->incompatible_relids);
     714                 :        3529 :     rinfo->incompatible_relids = bms_del_member(rinfo->incompatible_relids, relid);
     715                 :        3529 :     rinfo->incompatible_relids = bms_del_member(rinfo->incompatible_relids, ojrelid);
     716                 :             :     /* Likewise for outer_relids */
     717                 :        3529 :     rinfo->outer_relids = bms_copy(rinfo->outer_relids);
     718                 :        3529 :     rinfo->outer_relids = bms_del_member(rinfo->outer_relids, relid);
     719                 :        3529 :     rinfo->outer_relids = bms_del_member(rinfo->outer_relids, ojrelid);
     720                 :             :     /* Likewise for left_relids */
     721                 :        3529 :     rinfo->left_relids = bms_copy(rinfo->left_relids);
     722                 :        3529 :     rinfo->left_relids = bms_del_member(rinfo->left_relids, relid);
     723                 :        3529 :     rinfo->left_relids = bms_del_member(rinfo->left_relids, ojrelid);
     724                 :             :     /* Likewise for right_relids */
     725                 :        3529 :     rinfo->right_relids = bms_copy(rinfo->right_relids);
     726                 :        3529 :     rinfo->right_relids = bms_del_member(rinfo->right_relids, relid);
     727                 :        3529 :     rinfo->right_relids = bms_del_member(rinfo->right_relids, ojrelid);
     728                 :             : 
     729                 :             :     /* If it's an OR, recurse to clean up sub-clauses */
     730         [ +  + ]:        3529 :     if (restriction_is_or_clause(rinfo))
     731                 :             :     {
     732                 :             :         ListCell   *lc;
     733                 :             : 
     734                 :             :         Assert(is_orclause(rinfo->orclause));
     735   [ +  -  +  +  :          15 :         foreach(lc, ((BoolExpr *) rinfo->orclause)->args)
                   +  + ]
     736                 :             :         {
     737                 :          10 :             Node       *orarg = (Node *) lfirst(lc);
     738                 :             : 
     739                 :             :             /* OR arguments should be ANDs or sub-RestrictInfos */
     740         [ -  + ]:          10 :             if (is_andclause(orarg))
     741                 :             :             {
     742                 :           0 :                 List       *andargs = ((BoolExpr *) orarg)->args;
     743                 :             :                 ListCell   *lc2;
     744                 :             : 
     745   [ #  #  #  #  :           0 :                 foreach(lc2, andargs)
                   #  # ]
     746                 :             :                 {
     747                 :           0 :                     RestrictInfo *rinfo2 = lfirst_node(RestrictInfo, lc2);
     748                 :             : 
     749                 :           0 :                     remove_rel_from_restrictinfo(rinfo2, relid, ojrelid);
     750                 :             :                 }
     751                 :             :             }
     752                 :             :             else
     753                 :             :             {
     754                 :          10 :                 RestrictInfo *rinfo2 = castNode(RestrictInfo, orarg);
     755                 :             : 
     756                 :          10 :                 remove_rel_from_restrictinfo(rinfo2, relid, ojrelid);
     757                 :             :             }
     758                 :             :         }
     759                 :             :     }
     760                 :        3529 : }
     761                 :             : 
     762                 :             : /*
     763                 :             :  * Remove any references to relid or ojrelid from the EquivalenceClass.
     764                 :             :  *
     765                 :             :  * We fix the EC and EM relid sets to ensure that implied join equalities will
     766                 :             :  * be generated at the appropriate join level(s).  We also strip the removed
     767                 :             :  * rel from PlaceHolderVars embedded in member expressions; a member's
     768                 :             :  * em_relids reflects ph_eval_at rather than the PHV's phrels, so the latter
     769                 :             :  * can still mention the removed rel even when em_relids does not.  Like
     770                 :             :  * remove_rel_from_restrictinfo, we don't bother with nullingrel bits in
     771                 :             :  * contained plain Vars.
     772                 :             :  */
     773                 :             : static void
     774                 :       40426 : remove_rel_from_eclass(PlannerInfo *root, EquivalenceClass *ec,
     775                 :             :                        int relid, int ojrelid)
     776                 :             : {
     777                 :             :     ListCell   *lc;
     778                 :             : 
     779                 :             :     /*
     780                 :             :      * Strip the removed rel/join from PlaceHolderVars in member expressions.
     781                 :             :      * This is needed even when the EC's relids don't mention the removed rel.
     782                 :             :      * Plain Vars and Consts can't contain a PlaceHolderVar, so skip them.
     783                 :             :      */
     784         [ +  + ]:       40426 :     if (root->glob->lastPHId != 0)
     785                 :             :     {
     786   [ +  +  +  +  :        2160 :         foreach_node(EquivalenceMember, em, ec->ec_members)
                   +  + ]
     787                 :             :         {
     788   [ +  +  +  + ]:         814 :             if (!IsA(em->em_expr, Var) && !IsA(em->em_expr, Const))
     789                 :          83 :                 em->em_expr = (Expr *)
     790                 :          83 :                     remove_rel_from_phvs((Node *) em->em_expr, relid, ojrelid);
     791                 :             :         }
     792                 :             :     }
     793                 :             : 
     794         [ +  + ]:       40426 :     if (!bms_is_member(relid, ec->ec_relids) &&
     795         [ +  - ]:       28650 :         !bms_is_member(ojrelid, ec->ec_relids))
     796                 :       28650 :         return;
     797                 :             : 
     798                 :             :     /* Fix up the EC's overall relids */
     799                 :       11776 :     ec->ec_relids = bms_del_member(ec->ec_relids, relid);
     800                 :       11776 :     ec->ec_relids = bms_del_member(ec->ec_relids, ojrelid);
     801                 :             : 
     802                 :             :     /*
     803                 :             :      * We don't expect any EC child members to exist at this point.  Ensure
     804                 :             :      * that's the case, otherwise, we might be getting asked to do something
     805                 :             :      * this function hasn't been coded for.
     806                 :             :      */
     807                 :             :     Assert(ec->ec_childmembers == NULL);
     808                 :             : 
     809                 :             :     /*
     810                 :             :      * Fix up the member expressions.  Any non-const member that ends with
     811                 :             :      * empty em_relids must be a Var or PHV of the removed relation.  We don't
     812                 :             :      * need it anymore, so we can drop it.
     813                 :             :      */
     814   [ +  +  +  +  :       26972 :     foreach(lc, ec->ec_members)
                   +  + ]
     815                 :             :     {
     816                 :       15196 :         EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc);
     817                 :             : 
     818   [ +  +  -  + ]:       18616 :         if (bms_is_member(relid, cur_em->em_relids) ||
     819                 :        3420 :             bms_is_member(ojrelid, cur_em->em_relids))
     820                 :             :         {
     821                 :             :             Assert(!cur_em->em_is_const);
     822                 :             :             /* em_relids is likely to be shared with some RestrictInfo */
     823                 :       11776 :             cur_em->em_relids = bms_copy(cur_em->em_relids);
     824                 :       11776 :             cur_em->em_relids = bms_del_member(cur_em->em_relids, relid);
     825                 :       11776 :             cur_em->em_relids = bms_del_member(cur_em->em_relids, ojrelid);
     826         [ +  + ]:       11776 :             if (bms_is_empty(cur_em->em_relids))
     827                 :       11756 :                 ec->ec_members = foreach_delete_current(ec->ec_members, lc);
     828                 :             :         }
     829                 :             :     }
     830                 :             : 
     831                 :             :     /* Fix up the source clauses, in case we can re-use them later */
     832   [ +  +  +  +  :       15196 :     foreach(lc, ec->ec_sources)
                   +  + ]
     833                 :             :     {
     834                 :        3420 :         RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
     835                 :             : 
     836                 :        3420 :         remove_rel_from_restrictinfo(rinfo, relid, ojrelid);
     837                 :             :     }
     838                 :             : 
     839                 :             :     /*
     840                 :             :      * Rather than expend code on fixing up any already-derived clauses, just
     841                 :             :      * drop them.  (At this point, any such clauses would be base restriction
     842                 :             :      * clauses, which we'd not need anymore anyway.)
     843                 :             :      */
     844                 :       11776 :     ec_clear_derived_clauses(ec);
     845                 :             : }
     846                 :             : 
     847                 :             : /*
     848                 :             :  * Remove any references to the specified RT index(es) from the phrels (and
     849                 :             :  * phnullingrels) of every PlaceHolderVar in the given expression.
     850                 :             :  *
     851                 :             :  * remove_rel_from_query() fixes up the relid sets of RestrictInfos and
     852                 :             :  * EquivalenceMembers, but not the PlaceHolderVars embedded in their
     853                 :             :  * expressions.  That's normally fine, but such an expression may later be
     854                 :             :  * translated for an appendrel child and have its relids recomputed by
     855                 :             :  * pull_varnos().  A leftover removed relid in phrels would then make
     856                 :             :  * pull_varnos() reference a nonexistent rel, so we strip it here to match the
     857                 :             :  * canonical PlaceHolderVar.
     858                 :             :  */
     859                 :             : static Node *
     860                 :         207 : remove_rel_from_phvs(Node *node, int relid, int ojrelid)
     861                 :             : {
     862                 :         207 :     Relids      removable = bms_add_member(bms_make_singleton(relid), ojrelid);
     863                 :             : 
     864                 :         207 :     return remove_rel_from_phvs_mutator(node, removable);
     865                 :             : }
     866                 :             : 
     867                 :             : static Node *
     868                 :        1142 : remove_rel_from_phvs_mutator(Node *node, Relids removable)
     869                 :             : {
     870         [ +  + ]:        1142 :     if (node == NULL)
     871                 :          55 :         return NULL;
     872         [ +  + ]:        1087 :     if (IsA(node, PlaceHolderVar))
     873                 :             :     {
     874                 :          75 :         PlaceHolderVar *phv = (PlaceHolderVar *) node;
     875                 :             :         Relids      newphrels;
     876                 :             : 
     877                 :             :         /* Upper-level PlaceHolderVars should be long gone at this point */
     878                 :             :         Assert(phv->phlevelsup == 0);
     879                 :             : 
     880                 :             :         /* Copy the PlaceHolderVar and mutate what's below ... */
     881                 :             :         phv = (PlaceHolderVar *)
     882                 :          75 :             expression_tree_mutator(node,
     883                 :             :                                     remove_rel_from_phvs_mutator,
     884                 :             :                                     removable);
     885                 :             : 
     886                 :             :         /*
     887                 :             :          * ... then strip the removed rels from its relid sets.
     888                 :             :          *
     889                 :             :          * If stripping would empty phrels, the PHV is evaluated only at the
     890                 :             :          * removed relation(s); it then belongs to an EquivalenceMember that
     891                 :             :          * the caller drops immediately afterwards.  Leave such a PHV
     892                 :             :          * untouched rather than build one with empty phrels, which the rest
     893                 :             :          * of the planner assumes never occurs.
     894                 :             :          */
     895                 :          75 :         newphrels = bms_difference(phv->phrels, removable);
     896         [ +  + ]:          75 :         if (!bms_is_empty(newphrels))
     897                 :             :         {
     898                 :          65 :             phv->phrels = newphrels;
     899                 :          65 :             phv->phnullingrels = bms_difference(phv->phnullingrels,
     900                 :             :                                                 removable);
     901                 :             :         }
     902                 :             : 
     903                 :          75 :         return (Node *) phv;
     904                 :             :     }
     905                 :        1012 :     return expression_tree_mutator(node,
     906                 :             :                                    remove_rel_from_phvs_mutator,
     907                 :             :                                    removable);
     908                 :             : }
     909                 :             : 
     910                 :             : /*
     911                 :             :  * Remove any occurrences of the target relid from a joinlist structure.
     912                 :             :  *
     913                 :             :  * It's easiest to build a whole new list structure, so we handle it that
     914                 :             :  * way.  Efficiency is not a big deal here.
     915                 :             :  *
     916                 :             :  * *nremoved is incremented by the number of occurrences removed (there
     917                 :             :  * should be exactly one, but the caller checks that).
     918                 :             :  */
     919                 :             : static List *
     920                 :        9152 : remove_rel_from_joinlist(List *joinlist, int relid, int *nremoved)
     921                 :             : {
     922                 :        9152 :     List       *result = NIL;
     923                 :             :     ListCell   *jl;
     924                 :             : 
     925   [ +  -  +  +  :       35189 :     foreach(jl, joinlist)
                   +  + ]
     926                 :             :     {
     927                 :       26037 :         Node       *jlnode = (Node *) lfirst(jl);
     928                 :             : 
     929         [ +  + ]:       26037 :         if (IsA(jlnode, RangeTblRef))
     930                 :             :         {
     931                 :       25787 :             int         varno = ((RangeTblRef *) jlnode)->rtindex;
     932                 :             : 
     933         [ +  + ]:       25787 :             if (varno == relid)
     934                 :        8902 :                 (*nremoved)++;
     935                 :             :             else
     936                 :       16885 :                 result = lappend(result, jlnode);
     937                 :             :         }
     938         [ +  - ]:         250 :         else if (IsA(jlnode, List))
     939                 :             :         {
     940                 :             :             /* Recurse to handle subproblem */
     941                 :             :             List       *sublist;
     942                 :             : 
     943                 :         250 :             sublist = remove_rel_from_joinlist((List *) jlnode,
     944                 :             :                                                relid, nremoved);
     945                 :             :             /* Avoid including empty sub-lists in the result */
     946         [ +  - ]:         250 :             if (sublist)
     947                 :         250 :                 result = lappend(result, sublist);
     948                 :             :         }
     949                 :             :         else
     950                 :             :         {
     951         [ #  # ]:           0 :             elog(ERROR, "unrecognized joinlist node type: %d",
     952                 :             :                  (int) nodeTag(jlnode));
     953                 :             :         }
     954                 :             :     }
     955                 :             : 
     956                 :        9152 :     return result;
     957                 :             : }
     958                 :             : 
     959                 :             : 
     960                 :             : /*
     961                 :             :  * reduce_unique_semijoins
     962                 :             :  *      Check for semijoins that can be simplified to plain inner joins
     963                 :             :  *      because the inner relation is provably unique for the join clauses.
     964                 :             :  *
     965                 :             :  * Ideally this would happen during reduce_outer_joins, but we don't have
     966                 :             :  * enough information at that point.
     967                 :             :  *
     968                 :             :  * To perform the strength reduction when applicable, we need only delete
     969                 :             :  * the semijoin's SpecialJoinInfo from root->join_info_list.  (We don't
     970                 :             :  * bother fixing the join type attributed to it in the query jointree,
     971                 :             :  * since that won't be consulted again.)
     972                 :             :  */
     973                 :             : void
     974                 :      248597 : reduce_unique_semijoins(PlannerInfo *root)
     975                 :             : {
     976                 :             :     ListCell   *lc;
     977                 :             : 
     978                 :             :     /*
     979                 :             :      * Scan the join_info_list to find semijoins.
     980                 :             :      */
     981   [ +  +  +  +  :      282679 :     foreach(lc, root->join_info_list)
                   +  + ]
     982                 :             :     {
     983                 :       34082 :         SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc);
     984                 :             :         int         innerrelid;
     985                 :             :         RelOptInfo *innerrel;
     986                 :             :         Relids      joinrelids;
     987                 :             :         List       *restrictlist;
     988                 :             : 
     989                 :             :         /*
     990                 :             :          * Must be a semijoin to a single baserel, else we aren't going to be
     991                 :             :          * able to do anything with it.
     992                 :             :          */
     993         [ +  + ]:       34082 :         if (sjinfo->jointype != JOIN_SEMI)
     994                 :       33845 :             continue;
     995                 :             : 
     996         [ +  + ]:        4030 :         if (!bms_get_singleton_member(sjinfo->min_righthand, &innerrelid))
     997                 :         140 :             continue;
     998                 :             : 
     999                 :        3890 :         innerrel = find_base_rel(root, innerrelid);
    1000                 :             : 
    1001                 :             :         /*
    1002                 :             :          * Before we trouble to run generate_join_implied_equalities, make a
    1003                 :             :          * quick check to eliminate cases in which we will surely be unable to
    1004                 :             :          * prove uniqueness of the innerrel.
    1005                 :             :          */
    1006         [ +  + ]:        3890 :         if (!rel_supports_distinctness(root, innerrel))
    1007                 :         811 :             continue;
    1008                 :             : 
    1009                 :             :         /* Compute the relid set for the join we are considering */
    1010                 :        3079 :         joinrelids = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
    1011                 :             :         Assert(sjinfo->ojrelid == 0);    /* SEMI joins don't have RT indexes */
    1012                 :             : 
    1013                 :             :         /*
    1014                 :             :          * Since we're only considering a single-rel RHS, any join clauses it
    1015                 :             :          * has must be clauses linking it to the semijoin's min_lefthand.  We
    1016                 :             :          * can also consider EC-derived join clauses.
    1017                 :             :          */
    1018                 :             :         restrictlist =
    1019                 :        3079 :             list_concat(generate_join_implied_equalities(root,
    1020                 :             :                                                          joinrelids,
    1021                 :             :                                                          sjinfo->min_lefthand,
    1022                 :             :                                                          innerrel,
    1023                 :             :                                                          NULL),
    1024                 :        3079 :                         innerrel->joininfo);
    1025                 :             : 
    1026                 :             :         /* Test whether the innerrel is unique for those clauses. */
    1027         [ +  + ]:        3079 :         if (!innerrel_is_unique(root,
    1028                 :             :                                 joinrelids, sjinfo->min_lefthand, innerrel,
    1029                 :             :                                 JOIN_SEMI, restrictlist, true))
    1030                 :        2842 :             continue;
    1031                 :             : 
    1032                 :             :         /* OK, remove the SpecialJoinInfo from the list. */
    1033                 :         237 :         root->join_info_list = foreach_delete_current(root->join_info_list, lc);
    1034                 :             :     }
    1035                 :      248597 : }
    1036                 :             : 
    1037                 :             : 
    1038                 :             : /*
    1039                 :             :  * rel_supports_distinctness
    1040                 :             :  *      Could the relation possibly be proven distinct on some set of columns?
    1041                 :             :  *
    1042                 :             :  * This is effectively a pre-checking function for rel_is_distinct_for().
    1043                 :             :  * It must return true if rel_is_distinct_for() could possibly return true
    1044                 :             :  * with this rel, but it should not expend a lot of cycles.  The idea is
    1045                 :             :  * that callers can avoid doing possibly-expensive processing to compute
    1046                 :             :  * rel_is_distinct_for()'s argument lists if the call could not possibly
    1047                 :             :  * succeed.
    1048                 :             :  */
    1049                 :             : static bool
    1050                 :      544547 : rel_supports_distinctness(PlannerInfo *root, RelOptInfo *rel)
    1051                 :             : {
    1052                 :             :     /* We only know about baserels ... */
    1053         [ +  + ]:      544547 :     if (rel->reloptkind != RELOPT_BASEREL)
    1054                 :      200427 :         return false;
    1055         [ +  + ]:      344120 :     if (rel->rtekind == RTE_RELATION)
    1056                 :             :     {
    1057                 :             :         /*
    1058                 :             :          * For a plain relation, we only know how to prove uniqueness by
    1059                 :             :          * reference to unique indexes.  Make sure there's at least one
    1060                 :             :          * suitable unique index.  It must be immediately enforced, and not a
    1061                 :             :          * partial index. (Keep these conditions in sync with
    1062                 :             :          * relation_has_unique_index_for!)
    1063                 :             :          */
    1064                 :             :         ListCell   *lc;
    1065                 :             : 
    1066   [ +  +  +  +  :      423983 :         foreach(lc, rel->indexlist)
                   +  + ]
    1067                 :             :         {
    1068                 :      365715 :             IndexOptInfo *ind = (IndexOptInfo *) lfirst(lc);
    1069                 :             : 
    1070   [ +  +  +  -  :      365715 :             if (ind->unique && ind->immediate && ind->indpred == NIL)
                   +  + ]
    1071                 :      260375 :                 return true;
    1072                 :             :         }
    1073                 :             :     }
    1074         [ +  + ]:       25477 :     else if (rel->rtekind == RTE_SUBQUERY)
    1075                 :             :     {
    1076                 :        9807 :         Query      *subquery = root->simple_rte_array[rel->relid]->subquery;
    1077                 :             : 
    1078                 :             :         /* Check if the subquery has any qualities that support distinctness */
    1079         [ +  + ]:        9807 :         if (query_supports_distinctness(subquery))
    1080                 :        8439 :             return true;
    1081                 :             :     }
    1082                 :             :     /* We have no proof rules for any other rtekinds. */
    1083                 :       75306 :     return false;
    1084                 :             : }
    1085                 :             : 
    1086                 :             : /*
    1087                 :             :  * rel_is_distinct_for
    1088                 :             :  *      Does the relation return only distinct rows according to clause_list?
    1089                 :             :  *
    1090                 :             :  * clause_list is a list of join restriction clauses involving this rel and
    1091                 :             :  * some other one.  Return true if no two rows emitted by this rel could
    1092                 :             :  * possibly join to the same row of the other rel.
    1093                 :             :  *
    1094                 :             :  * The caller must have already determined that each condition is a
    1095                 :             :  * mergejoinable equality with an expression in this relation on one side, and
    1096                 :             :  * an expression not involving this relation on the other.  The transient
    1097                 :             :  * outer_is_left flag is used to identify which side references this relation:
    1098                 :             :  * left side if outer_is_left is false, right side if it is true.
    1099                 :             :  *
    1100                 :             :  * Note that the passed-in clause_list may be destructively modified!  This
    1101                 :             :  * is OK for current uses, because the clause_list is built by the caller for
    1102                 :             :  * the sole purpose of passing to this function.
    1103                 :             :  *
    1104                 :             :  * (*extra_clauses) to be set to the right sides of baserestrictinfo clauses,
    1105                 :             :  * looking like "x = const" if distinctness is derived from such clauses, not
    1106                 :             :  * joininfo clauses.  Pass NULL to the extra_clauses if this value is not
    1107                 :             :  * needed.
    1108                 :             :  */
    1109                 :             : static bool
    1110                 :      177661 : rel_is_distinct_for(PlannerInfo *root, RelOptInfo *rel, List *clause_list,
    1111                 :             :                     List **extra_clauses)
    1112                 :             : {
    1113                 :             :     /*
    1114                 :             :      * We could skip a couple of tests here if we assume all callers checked
    1115                 :             :      * rel_supports_distinctness first, but it doesn't seem worth taking any
    1116                 :             :      * risk for.
    1117                 :             :      */
    1118         [ -  + ]:      177661 :     if (rel->reloptkind != RELOPT_BASEREL)
    1119                 :           0 :         return false;
    1120         [ +  + ]:      177661 :     if (rel->rtekind == RTE_RELATION)
    1121                 :             :     {
    1122                 :             :         /*
    1123                 :             :          * Examine the indexes to see if we have a matching unique index.
    1124                 :             :          * relation_has_unique_index_for automatically adds any usable
    1125                 :             :          * restriction clauses for the rel, so we needn't do that here.
    1126                 :             :          */
    1127         [ +  + ]:      173242 :         if (relation_has_unique_index_for(root, rel, clause_list, extra_clauses))
    1128                 :      103560 :             return true;
    1129                 :             :     }
    1130         [ +  - ]:        4419 :     else if (rel->rtekind == RTE_SUBQUERY)
    1131                 :             :     {
    1132                 :        4419 :         Index       relid = rel->relid;
    1133                 :        4419 :         Query      *subquery = root->simple_rte_array[relid]->subquery;
    1134                 :        4419 :         List       *distinct_cols = NIL;
    1135                 :             :         ListCell   *l;
    1136                 :             : 
    1137                 :             :         /*
    1138                 :             :          * Build the argument list for query_is_distinct_for: a list of
    1139                 :             :          * DistinctColInfo entries, each holding an output column number that
    1140                 :             :          * the query needs to be distinct over, the equality operator that the
    1141                 :             :          * column needs to be distinct according to, and that operator's input
    1142                 :             :          * collation.  The collation matters because the subquery's own
    1143                 :             :          * DISTINCT / GROUP BY / set-op proves uniqueness under its own
    1144                 :             :          * collation, which need not agree with the operator's.
    1145                 :             :          *
    1146                 :             :          * (XXX we are not considering restriction clauses attached to the
    1147                 :             :          * subquery; is that worth doing?)
    1148                 :             :          */
    1149   [ +  +  +  +  :        8468 :         foreach(l, clause_list)
                   +  + ]
    1150                 :             :         {
    1151                 :        4049 :             RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
    1152                 :             :             OpExpr     *opexpr;
    1153                 :             :             Var        *var;
    1154                 :             :             DistinctColInfo *dcinfo;
    1155                 :             : 
    1156                 :             :             /*
    1157                 :             :              * The caller's mergejoinability test should have selected only
    1158                 :             :              * OpExprs.  The operator might be a cross-type operator and thus
    1159                 :             :              * not exactly the same operator the subquery would consider;
    1160                 :             :              * that's all right since query_is_distinct_for can resolve such
    1161                 :             :              * cases.
    1162                 :             :              */
    1163                 :        4049 :             opexpr = castNode(OpExpr, rinfo->clause);
    1164                 :             : 
    1165                 :             :             /* caller identified the inner side for us */
    1166         [ +  + ]:        4049 :             if (rinfo->outer_is_left)
    1167                 :        3678 :                 var = (Var *) get_rightop(rinfo->clause);
    1168                 :             :             else
    1169                 :         371 :                 var = (Var *) get_leftop(rinfo->clause);
    1170                 :             : 
    1171                 :             :             /*
    1172                 :             :              * We may ignore any RelabelType node above the operand.  (There
    1173                 :             :              * won't be more than one, since eval_const_expressions() has been
    1174                 :             :              * applied already.)
    1175                 :             :              */
    1176   [ +  -  +  + ]:        4049 :             if (var && IsA(var, RelabelType))
    1177                 :        2748 :                 var = (Var *) ((RelabelType *) var)->arg;
    1178                 :             : 
    1179                 :             :             /*
    1180                 :             :              * If inner side isn't a Var referencing a subquery output column,
    1181                 :             :              * this clause doesn't help us.
    1182                 :             :              */
    1183   [ +  -  +  + ]:        4049 :             if (!var || !IsA(var, Var) ||
    1184   [ +  -  -  + ]:        4024 :                 var->varno != relid || var->varlevelsup != 0)
    1185                 :          25 :                 continue;
    1186                 :             : 
    1187                 :        4024 :             dcinfo = palloc(sizeof(DistinctColInfo));
    1188                 :        4024 :             dcinfo->colno = var->varattno;
    1189                 :        4024 :             dcinfo->opid = opexpr->opno;
    1190                 :        4024 :             dcinfo->collid = opexpr->inputcollid;
    1191                 :        4024 :             distinct_cols = lappend(distinct_cols, dcinfo);
    1192                 :             :         }
    1193                 :             : 
    1194         [ +  + ]:        4419 :         if (query_is_distinct_for(subquery, distinct_cols))
    1195                 :         580 :             return true;
    1196                 :             :     }
    1197                 :       73521 :     return false;
    1198                 :             : }
    1199                 :             : 
    1200                 :             : 
    1201                 :             : /*
    1202                 :             :  * query_supports_distinctness - could the query possibly be proven distinct
    1203                 :             :  *      on some set of output columns?
    1204                 :             :  *
    1205                 :             :  * This is effectively a pre-checking function for query_is_distinct_for().
    1206                 :             :  * It must return true if query_is_distinct_for() could possibly return true
    1207                 :             :  * with this query, but it should not expend a lot of cycles.  The idea is
    1208                 :             :  * that callers can avoid doing possibly-expensive processing to compute
    1209                 :             :  * query_is_distinct_for()'s argument lists if the call could not possibly
    1210                 :             :  * succeed.
    1211                 :             :  */
    1212                 :             : bool
    1213                 :        9807 : query_supports_distinctness(Query *query)
    1214                 :             : {
    1215                 :             :     /* SRFs break distinctness except with DISTINCT, see below */
    1216   [ +  +  +  - ]:        9807 :     if (query->hasTargetSRFs && query->distinctClause == NIL)
    1217                 :         763 :         return false;
    1218                 :             : 
    1219                 :             :     /* check for features we can prove distinctness with */
    1220         [ +  + ]:        9044 :     if (query->distinctClause != NIL ||
    1221         [ +  + ]:        8859 :         query->groupClause != NIL ||
    1222         [ +  + ]:        8673 :         query->groupingSets != NIL ||
    1223         [ +  + ]:        8633 :         query->hasAggs ||
    1224         [ +  - ]:        7128 :         query->havingQual ||
    1225         [ +  + ]:        7128 :         query->setOperations)
    1226                 :        8439 :         return true;
    1227                 :             : 
    1228                 :         605 :     return false;
    1229                 :             : }
    1230                 :             : 
    1231                 :             : /*
    1232                 :             :  * query_is_distinct_for - does query never return duplicates of the
    1233                 :             :  *      specified columns?
    1234                 :             :  *
    1235                 :             :  * query is a not-yet-planned subquery (in current usage, it's always from
    1236                 :             :  * a subquery RTE, which the planner avoids scribbling on).
    1237                 :             :  *
    1238                 :             :  * distinct_cols is a list of DistinctColInfo, one per requested output column.
    1239                 :             :  * Each entry names the subquery output column number we want distinct, the
    1240                 :             :  * upper-level equality operator we'll compare values with, and that operator's
    1241                 :             :  * input collation.  We are interested in whether rows consisting of just these
    1242                 :             :  * columns are certain to be distinct.
    1243                 :             :  *
    1244                 :             :  * "Distinctness" is defined according to whether the corresponding upper-level
    1245                 :             :  * equality operators would think the values are distinct.  (Note: each opid
    1246                 :             :  * could be a cross-type operator, and thus not exactly the equality operator
    1247                 :             :  * that the subquery would use itself.  We use equality_ops_are_compatible() to
    1248                 :             :  * check compatibility.  That looks at opfamily membership for index AMs that
    1249                 :             :  * have declared that they support consistent equality semantics within an
    1250                 :             :  * opfamily, and so should give trustworthy answers for all operators that we
    1251                 :             :  * might need to deal with here.)
    1252                 :             :  *
    1253                 :             :  * The collid must also agree on equality with the collation the subquery's own
    1254                 :             :  * DISTINCT/GROUP BY/set-op uses to deduplicate the column, else the subquery's
    1255                 :             :  * distinctness does not carry over to the caller's equality semantics.  Two
    1256                 :             :  * collations agree on equality if they match or if both are deterministic (in
    1257                 :             :  * which case both reduce equality to byte-equality; see CREATE COLLATION).
    1258                 :             :  */
    1259                 :             : bool
    1260                 :        4419 : query_is_distinct_for(Query *query, List *distinct_cols)
    1261                 :             : {
    1262                 :             :     ListCell   *l;
    1263                 :             :     DistinctColInfo *dcinfo;
    1264                 :             : 
    1265                 :             :     /*
    1266                 :             :      * DISTINCT (including DISTINCT ON) guarantees uniqueness if all the
    1267                 :             :      * columns in the DISTINCT clause appear in colnos and operator semantics
    1268                 :             :      * match.  This is true even if there are SRFs in the DISTINCT columns or
    1269                 :             :      * elsewhere in the tlist.
    1270                 :             :      */
    1271         [ +  + ]:        4419 :     if (query->distinctClause)
    1272                 :             :     {
    1273   [ +  -  +  +  :         190 :         foreach(l, query->distinctClause)
                   +  + ]
    1274                 :             :         {
    1275                 :         155 :             SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
    1276                 :         155 :             TargetEntry *tle = get_sortgroupclause_tle(sgc,
    1277                 :             :                                                        query->targetList);
    1278                 :             : 
    1279                 :         155 :             dcinfo = distinct_col_search(tle->resno, distinct_cols);
    1280         [ +  + ]:         155 :             if (dcinfo == NULL ||
    1281         [ +  - ]:          90 :                 !equality_ops_are_compatible(dcinfo->opid, sgc->eqop) ||
    1282         [ +  + ]:          90 :                 !collations_agree_on_equality(dcinfo->collid,
    1283                 :          90 :                                               exprCollation((Node *) tle->expr)))
    1284                 :             :                 break;          /* exit early if no match */
    1285                 :             :         }
    1286         [ +  + ]:         140 :         if (l == NULL)          /* had matches for all? */
    1287                 :          35 :             return true;
    1288                 :             :     }
    1289                 :             : 
    1290                 :             :     /*
    1291                 :             :      * Otherwise, a set-returning function in the query's targetlist can
    1292                 :             :      * result in returning duplicate rows, despite any grouping that might
    1293                 :             :      * occur before tlist evaluation.  (If all tlist SRFs are within GROUP BY
    1294                 :             :      * columns, it would be safe because they'd be expanded before grouping.
    1295                 :             :      * But it doesn't currently seem worth the effort to check for that.)
    1296                 :             :      */
    1297         [ -  + ]:        4384 :     if (query->hasTargetSRFs)
    1298                 :           0 :         return false;
    1299                 :             : 
    1300                 :             :     /*
    1301                 :             :      * Similarly, GROUP BY without GROUPING SETS guarantees uniqueness if all
    1302                 :             :      * the grouped columns appear in colnos and operator semantics match.
    1303                 :             :      */
    1304   [ +  +  +  + ]:        4384 :     if (query->groupClause && !query->groupingSets)
    1305                 :             :     {
    1306   [ +  -  +  +  :         216 :         foreach(l, query->groupClause)
                   +  + ]
    1307                 :             :         {
    1308                 :         154 :             SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
    1309                 :         154 :             TargetEntry *tle = get_sortgroupclause_tle(sgc,
    1310                 :             :                                                        query->targetList);
    1311                 :             : 
    1312                 :         154 :             dcinfo = distinct_col_search(tle->resno, distinct_cols);
    1313         [ +  + ]:         154 :             if (dcinfo == NULL ||
    1314         [ +  - ]:         107 :                 !equality_ops_are_compatible(dcinfo->opid, sgc->eqop) ||
    1315         [ +  + ]:         107 :                 !collations_agree_on_equality(dcinfo->collid,
    1316                 :         107 :                                               exprCollation((Node *) tle->expr)))
    1317                 :             :                 break;          /* exit early if no match */
    1318                 :             :         }
    1319         [ +  + ]:         119 :         if (l == NULL)          /* had matches for all? */
    1320                 :          62 :             return true;
    1321                 :             :     }
    1322         [ +  + ]:        4265 :     else if (query->groupingSets)
    1323                 :             :     {
    1324                 :             :         List       *gsets;
    1325                 :             : 
    1326                 :             :         /*
    1327                 :             :          * If we have grouping sets with expressions, we probably don't have
    1328                 :             :          * uniqueness and analysis would be hard. Punt.
    1329                 :             :          */
    1330         [ +  + ]:          50 :         if (query->groupClause)
    1331                 :          10 :             return false;
    1332                 :             : 
    1333                 :             :         /*
    1334                 :             :          * If we have no groupClause (therefore no grouping expressions), we
    1335                 :             :          * might have one or many empty grouping sets.  If there's just one,
    1336                 :             :          * or if the DISTINCT clause is used on the GROUP BY, then we're
    1337                 :             :          * returning only one row and are certainly unique.  But otherwise, we
    1338                 :             :          * know we're certainly not unique.
    1339                 :             :          */
    1340         [ +  + ]:          40 :         if (query->groupDistinct)
    1341                 :           5 :             return true;
    1342                 :             : 
    1343                 :          35 :         gsets = expand_grouping_sets(query->groupingSets, false, -1);
    1344                 :             : 
    1345                 :          35 :         return (list_length(gsets) == 1);
    1346                 :             :     }
    1347                 :             :     else
    1348                 :             :     {
    1349                 :             :         /*
    1350                 :             :          * If we have no GROUP BY, but do have aggregates or HAVING, then the
    1351                 :             :          * result is at most one row so it's surely unique, for any operators.
    1352                 :             :          */
    1353   [ +  +  -  + ]:        4215 :         if (query->hasAggs || query->havingQual)
    1354                 :         408 :             return true;
    1355                 :             :     }
    1356                 :             : 
    1357                 :             :     /*
    1358                 :             :      * UNION, INTERSECT, EXCEPT guarantee uniqueness of the whole output row,
    1359                 :             :      * except with ALL.
    1360                 :             :      */
    1361         [ +  + ]:        3864 :     if (query->setOperations)
    1362                 :             :     {
    1363                 :        3702 :         SetOperationStmt *topop = castNode(SetOperationStmt, query->setOperations);
    1364                 :             : 
    1365                 :             :         Assert(topop->op != SETOP_NONE);
    1366                 :             : 
    1367         [ +  + ]:        3702 :         if (!topop->all)
    1368                 :             :         {
    1369                 :             :             ListCell   *lg;
    1370                 :             : 
    1371                 :             :             /* We're good if all the nonjunk output columns are in colnos */
    1372                 :          98 :             lg = list_head(topop->groupClauses);
    1373   [ +  -  +  +  :         158 :             foreach(l, query->targetList)
                   +  + ]
    1374                 :             :             {
    1375                 :         103 :                 TargetEntry *tle = (TargetEntry *) lfirst(l);
    1376                 :             :                 SortGroupClause *sgc;
    1377                 :             : 
    1378         [ -  + ]:         103 :                 if (tle->resjunk)
    1379                 :           0 :                     continue;   /* ignore resjunk columns */
    1380                 :             : 
    1381                 :             :                 /* non-resjunk columns should have grouping clauses */
    1382                 :             :                 Assert(lg != NULL);
    1383                 :         103 :                 sgc = (SortGroupClause *) lfirst(lg);
    1384                 :         103 :                 lg = lnext(topop->groupClauses, lg);
    1385                 :             : 
    1386                 :         103 :                 dcinfo = distinct_col_search(tle->resno, distinct_cols);
    1387         [ +  + ]:         103 :                 if (dcinfo == NULL ||
    1388         [ +  - ]:          70 :                     !equality_ops_are_compatible(dcinfo->opid, sgc->eqop) ||
    1389         [ +  + ]:          70 :                     !collations_agree_on_equality(dcinfo->collid,
    1390                 :          70 :                                                   exprCollation((Node *) tle->expr)))
    1391                 :             :                     break;      /* exit early if no match */
    1392                 :             :             }
    1393         [ +  + ]:          98 :             if (l == NULL)      /* had matches for all? */
    1394                 :          55 :                 return true;
    1395                 :             :         }
    1396                 :             :     }
    1397                 :             : 
    1398                 :             :     /*
    1399                 :             :      * XXX Are there any other cases in which we can easily see the result
    1400                 :             :      * must be distinct?
    1401                 :             :      *
    1402                 :             :      * If you do add more smarts to this function, be sure to update
    1403                 :             :      * query_supports_distinctness() to match.
    1404                 :             :      */
    1405                 :             : 
    1406                 :        3809 :     return false;
    1407                 :             : }
    1408                 :             : 
    1409                 :             : /*
    1410                 :             :  * distinct_col_search - subroutine for query_is_distinct_for
    1411                 :             :  *
    1412                 :             :  * If colno matches the colno field of an entry in distinct_cols, return a
    1413                 :             :  * pointer to that entry; else return NULL.  (Ordinarily distinct_cols would
    1414                 :             :  * not contain duplicate colnos, but if it does, we arbitrarily select the
    1415                 :             :  * first match.)
    1416                 :             :  */
    1417                 :             : static DistinctColInfo *
    1418                 :         412 : distinct_col_search(int colno, List *distinct_cols)
    1419                 :             : {
    1420   [ +  -  +  +  :         720 :     foreach_ptr(DistinctColInfo, dcinfo, distinct_cols)
                   +  + ]
    1421                 :             :     {
    1422         [ +  + ]:         430 :         if (dcinfo->colno == colno)
    1423                 :         267 :             return dcinfo;
    1424                 :             :     }
    1425                 :             : 
    1426                 :         145 :     return NULL;
    1427                 :             : }
    1428                 :             : 
    1429                 :             : 
    1430                 :             : /*
    1431                 :             :  * innerrel_is_unique
    1432                 :             :  *    Check if the innerrel provably contains at most one tuple matching any
    1433                 :             :  *    tuple from the outerrel, based on join clauses in the 'restrictlist'.
    1434                 :             :  *
    1435                 :             :  * We need an actual RelOptInfo for the innerrel, but it's sufficient to
    1436                 :             :  * identify the outerrel by its Relids.  This asymmetry supports use of this
    1437                 :             :  * function before joinrels have been built.  (The caller is expected to
    1438                 :             :  * also supply the joinrelids, just to save recalculating that.)
    1439                 :             :  *
    1440                 :             :  * The proof must be made based only on clauses that will be "joinquals"
    1441                 :             :  * rather than "otherquals" at execution.  For an inner join there's no
    1442                 :             :  * difference; but if the join is outer, we must ignore pushed-down quals,
    1443                 :             :  * as those will become "otherquals".  Note that this means the answer might
    1444                 :             :  * vary depending on whether IS_OUTER_JOIN(jointype); since we cache the
    1445                 :             :  * answer without regard to that, callers must take care not to call this
    1446                 :             :  * with jointypes that would be classified differently by IS_OUTER_JOIN().
    1447                 :             :  *
    1448                 :             :  * The actual proof is undertaken by is_innerrel_unique_for(); this function
    1449                 :             :  * is a frontend that is mainly concerned with caching the answers.
    1450                 :             :  * In particular, the force_cache argument allows overriding the internal
    1451                 :             :  * heuristic about whether to cache negative answers; it should be "true"
    1452                 :             :  * if making an inquiry that is not part of the normal bottom-up join search
    1453                 :             :  * sequence.
    1454                 :             :  */
    1455                 :             : bool
    1456                 :      587943 : innerrel_is_unique(PlannerInfo *root,
    1457                 :             :                    Relids joinrelids,
    1458                 :             :                    Relids outerrelids,
    1459                 :             :                    RelOptInfo *innerrel,
    1460                 :             :                    JoinType jointype,
    1461                 :             :                    List *restrictlist,
    1462                 :             :                    bool force_cache)
    1463                 :             : {
    1464                 :      587943 :     return innerrel_is_unique_ext(root, joinrelids, outerrelids, innerrel,
    1465                 :             :                                   jointype, restrictlist, force_cache, NULL);
    1466                 :             : }
    1467                 :             : 
    1468                 :             : /*
    1469                 :             :  * innerrel_is_unique_ext
    1470                 :             :  *    Do the same as innerrel_is_unique(), but also set to (*extra_clauses)
    1471                 :             :  *    additional clauses from a baserestrictinfo list used to prove the
    1472                 :             :  *    uniqueness.
    1473                 :             :  *
    1474                 :             :  * A non-NULL extra_clauses indicates that we're checking for self-join and
    1475                 :             :  * correspondingly dealing with filtered clauses.
    1476                 :             :  */
    1477                 :             : bool
    1478                 :      589734 : innerrel_is_unique_ext(PlannerInfo *root,
    1479                 :             :                        Relids joinrelids,
    1480                 :             :                        Relids outerrelids,
    1481                 :             :                        RelOptInfo *innerrel,
    1482                 :             :                        JoinType jointype,
    1483                 :             :                        List *restrictlist,
    1484                 :             :                        bool force_cache,
    1485                 :             :                        List **extra_clauses)
    1486                 :             : {
    1487                 :             :     MemoryContext old_context;
    1488                 :             :     ListCell   *lc;
    1489                 :             :     UniqueRelInfo *uniqueRelInfo;
    1490                 :      589734 :     List       *outer_exprs = NIL;
    1491                 :      589734 :     bool        self_join = (extra_clauses != NULL);
    1492                 :             : 
    1493                 :             :     /* Certainly can't prove uniqueness when there are no joinclauses */
    1494         [ +  + ]:      589734 :     if (restrictlist == NIL)
    1495                 :       79687 :         return false;
    1496                 :             : 
    1497                 :             :     /*
    1498                 :             :      * Make a quick check to eliminate cases in which we will surely be unable
    1499                 :             :      * to prove uniqueness of the innerrel.
    1500                 :             :      */
    1501         [ +  + ]:      510047 :     if (!rel_supports_distinctness(root, innerrel))
    1502                 :      272480 :         return false;
    1503                 :             : 
    1504                 :             :     /*
    1505                 :             :      * Query the cache to see if we've managed to prove that innerrel is
    1506                 :             :      * unique for any subset of this outerrel.  For non-self-join search, we
    1507                 :             :      * don't need an exact match, as extra outerrels can't make the innerrel
    1508                 :             :      * any less unique (or more formally, the restrictlist for a join to a
    1509                 :             :      * superset outerrel must be a superset of the conditions we successfully
    1510                 :             :      * used before). For self-join search, we require an exact match of
    1511                 :             :      * outerrels because we need extra clauses to be valid for our case. Also,
    1512                 :             :      * for self-join checking we've filtered the clauses list.  Thus, we can
    1513                 :             :      * match only the result cached for a self-join search for another
    1514                 :             :      * self-join check.
    1515                 :             :      */
    1516   [ +  +  +  +  :      258452 :     foreach(lc, innerrel->unique_for_rels)
                   +  + ]
    1517                 :             :     {
    1518                 :       89114 :         uniqueRelInfo = (UniqueRelInfo *) lfirst(lc);
    1519                 :             : 
    1520   [ +  +  +  +  :       89114 :         if ((!self_join && bms_is_subset(uniqueRelInfo->outerrelids, outerrelids)) ||
                   +  + ]
    1521         [ +  + ]:          57 :             (self_join && bms_equal(uniqueRelInfo->outerrelids, outerrelids) &&
    1522         [ +  + ]:          42 :              uniqueRelInfo->self_join))
    1523                 :             :         {
    1524         [ +  + ]:       68229 :             if (extra_clauses)
    1525                 :          10 :                 *extra_clauses = uniqueRelInfo->extra_clauses;
    1526                 :       68229 :             return true;        /* Success! */
    1527                 :             :         }
    1528                 :             :     }
    1529                 :             : 
    1530                 :             :     /*
    1531                 :             :      * Conversely, we may have already determined that this outerrel, or some
    1532                 :             :      * superset thereof, cannot prove this innerrel to be unique.
    1533                 :             :      */
    1534   [ +  +  +  +  :      169874 :     foreach(lc, innerrel->non_unique_for_rels)
                   +  + ]
    1535                 :             :     {
    1536                 :         884 :         Relids      unique_for_rels = (Relids) lfirst(lc);
    1537                 :             : 
    1538         [ +  + ]:         884 :         if (bms_is_subset(outerrelids, unique_for_rels))
    1539                 :         348 :             return false;
    1540                 :             :     }
    1541                 :             : 
    1542                 :             :     /* No cached information, so try to make the proof. */
    1543   [ +  +  +  + ]:      168990 :     if (is_innerrel_unique_for(root, joinrelids, outerrelids, innerrel,
    1544                 :             :                                jointype, restrictlist,
    1545                 :             :                                self_join ? &outer_exprs : NULL))
    1546                 :             :     {
    1547                 :             :         /*
    1548                 :             :          * Cache the positive result for future probes, being sure to keep it
    1549                 :             :          * in the planner_cxt even if we are working in GEQO.
    1550                 :             :          *
    1551                 :             :          * Note: one might consider trying to isolate the minimal subset of
    1552                 :             :          * the outerrels that proved the innerrel unique.  But it's not worth
    1553                 :             :          * the trouble, because the planner builds up joinrels incrementally
    1554                 :             :          * and so we'll see the minimally sufficient outerrels before any
    1555                 :             :          * supersets of them anyway.
    1556                 :             :          */
    1557                 :       95706 :         old_context = MemoryContextSwitchTo(root->planner_cxt);
    1558                 :       95706 :         uniqueRelInfo = makeNode(UniqueRelInfo);
    1559                 :       95706 :         uniqueRelInfo->outerrelids = bms_copy(outerrelids);
    1560                 :       95706 :         uniqueRelInfo->self_join = self_join;
    1561                 :       95706 :         uniqueRelInfo->extra_clauses = outer_exprs;
    1562                 :       95706 :         innerrel->unique_for_rels = lappend(innerrel->unique_for_rels,
    1563                 :             :                                             uniqueRelInfo);
    1564                 :       95706 :         MemoryContextSwitchTo(old_context);
    1565                 :             : 
    1566         [ +  + ]:       95706 :         if (extra_clauses)
    1567                 :         513 :             *extra_clauses = outer_exprs;
    1568                 :       95706 :         return true;            /* Success! */
    1569                 :             :     }
    1570                 :             :     else
    1571                 :             :     {
    1572                 :             :         /*
    1573                 :             :          * None of the join conditions for outerrel proved innerrel unique, so
    1574                 :             :          * we can safely reject this outerrel or any subset of it in future
    1575                 :             :          * checks.
    1576                 :             :          *
    1577                 :             :          * However, in normal planning mode, caching this knowledge is totally
    1578                 :             :          * pointless; it won't be queried again, because we build up joinrels
    1579                 :             :          * from smaller to larger.  It's only useful when using GEQO or
    1580                 :             :          * another planner extension that attempts planning multiple times.
    1581                 :             :          *
    1582                 :             :          * Also, allow callers to override that heuristic and force caching;
    1583                 :             :          * that's useful for reduce_unique_semijoins, which calls here before
    1584                 :             :          * the normal join search starts.
    1585                 :             :          */
    1586   [ +  +  -  + ]:       73284 :         if (force_cache || root->assumeReplanning)
    1587                 :             :         {
    1588                 :        3190 :             old_context = MemoryContextSwitchTo(root->planner_cxt);
    1589                 :        3190 :             innerrel->non_unique_for_rels =
    1590                 :        3190 :                 lappend(innerrel->non_unique_for_rels,
    1591                 :        3190 :                         bms_copy(outerrelids));
    1592                 :        3190 :             MemoryContextSwitchTo(old_context);
    1593                 :             :         }
    1594                 :             : 
    1595                 :       73284 :         return false;
    1596                 :             :     }
    1597                 :             : }
    1598                 :             : 
    1599                 :             : /*
    1600                 :             :  * is_innerrel_unique_for
    1601                 :             :  *    Check if the innerrel provably contains at most one tuple matching any
    1602                 :             :  *    tuple from the outerrel, based on join clauses in the 'restrictlist'.
    1603                 :             :  */
    1604                 :             : static bool
    1605                 :      168990 : is_innerrel_unique_for(PlannerInfo *root,
    1606                 :             :                        Relids joinrelids,
    1607                 :             :                        Relids outerrelids,
    1608                 :             :                        RelOptInfo *innerrel,
    1609                 :             :                        JoinType jointype,
    1610                 :             :                        List *restrictlist,
    1611                 :             :                        List **extra_clauses)
    1612                 :             : {
    1613                 :      168990 :     List       *clause_list = NIL;
    1614                 :             :     ListCell   *lc;
    1615                 :             : 
    1616                 :             :     /*
    1617                 :             :      * Search for mergejoinable clauses that constrain the inner rel against
    1618                 :             :      * the outer rel.  If an operator is mergejoinable then it behaves like
    1619                 :             :      * equality for some btree opclass, so it's what we want.  The
    1620                 :             :      * mergejoinability test also eliminates clauses containing volatile
    1621                 :             :      * functions, which we couldn't depend on.
    1622                 :             :      */
    1623   [ +  -  +  +  :      375685 :     foreach(lc, restrictlist)
                   +  + ]
    1624                 :             :     {
    1625                 :      206695 :         RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(lc);
    1626                 :             : 
    1627                 :             :         /*
    1628                 :             :          * As noted above, if it's a pushed-down clause and we're at an outer
    1629                 :             :          * join, we can't use it.
    1630                 :             :          */
    1631         [ +  + ]:      206695 :         if (IS_OUTER_JOIN(jointype) &&
    1632   [ +  +  -  + ]:       81019 :             RINFO_IS_PUSHED_DOWN(restrictinfo, joinrelids))
    1633                 :        7508 :             continue;
    1634                 :             : 
    1635                 :             :         /* Ignore if it's not a mergejoinable clause */
    1636         [ +  + ]:      199187 :         if (!restrictinfo->can_join ||
    1637         [ +  + ]:      186550 :             restrictinfo->mergeopfamilies == NIL)
    1638                 :       13341 :             continue;           /* not mergejoinable */
    1639                 :             : 
    1640                 :             :         /*
    1641                 :             :          * Check if the clause has the form "outer op inner" or "inner op
    1642                 :             :          * outer", and if so mark which side is inner.
    1643                 :             :          */
    1644         [ +  + ]:      185846 :         if (!clause_sides_match_join(restrictinfo, outerrelids,
    1645                 :             :                                      innerrel->relids))
    1646                 :          20 :             continue;           /* no good for these input relations */
    1647                 :             : 
    1648                 :             :         /* OK, add to the list */
    1649                 :      185826 :         clause_list = lappend(clause_list, restrictinfo);
    1650                 :             :     }
    1651                 :             : 
    1652                 :             :     /* Let rel_is_distinct_for() do the hard work */
    1653                 :      168990 :     return rel_is_distinct_for(root, innerrel, clause_list, extra_clauses);
    1654                 :             : }
    1655                 :             : 
    1656                 :             : /*
    1657                 :             :  * Update EC members to point to the remaining relation instead of the removed
    1658                 :             :  * one, removing duplicates.
    1659                 :             :  *
    1660                 :             :  * Restriction clauses for base relations are already distributed to
    1661                 :             :  * the respective baserestrictinfo lists (see
    1662                 :             :  * generate_implied_equalities_for_column). The above code has already processed
    1663                 :             :  * this list and updated these clauses to reference the remaining
    1664                 :             :  * relation, so that we can skip them here based on their relids.
    1665                 :             :  *
    1666                 :             :  * Likewise, we have already processed the join clauses that join the
    1667                 :             :  * removed relation to the remaining one.
    1668                 :             :  *
    1669                 :             :  * Finally, there might be join clauses tying the removed relation to
    1670                 :             :  * some third relation.  We can't just delete the source clauses and
    1671                 :             :  * regenerate them from the EC because the corresponding equality
    1672                 :             :  * operators might be missing (see the handling of ec_broken).
    1673                 :             :  * Therefore, we will update the references in the source clauses.
    1674                 :             :  *
    1675                 :             :  * Derived clauses can be generated again, so it is simpler just to
    1676                 :             :  * delete them.
    1677                 :             :  */
    1678                 :             : static void
    1679                 :         751 : update_eclasses(EquivalenceClass *ec, int from, int to)
    1680                 :             : {
    1681                 :         751 :     List       *new_members = NIL;
    1682                 :         751 :     List       *new_sources = NIL;
    1683                 :             : 
    1684                 :             :     /*
    1685                 :             :      * We don't expect any EC child members to exist at this point.  Ensure
    1686                 :             :      * that's the case, otherwise, we might be getting asked to do something
    1687                 :             :      * this function hasn't been coded for.
    1688                 :             :      */
    1689                 :             :     Assert(ec->ec_childmembers == NULL);
    1690                 :             : 
    1691   [ +  -  +  +  :        3076 :     foreach_node(EquivalenceMember, em, ec->ec_members)
                   +  + ]
    1692                 :             :     {
    1693                 :        1574 :         bool        is_redundant = false;
    1694                 :             : 
    1695         [ +  + ]:        1574 :         if (!bms_is_member(from, em->em_relids))
    1696                 :             :         {
    1697                 :         808 :             new_members = lappend(new_members, em);
    1698                 :         808 :             continue;
    1699                 :             :         }
    1700                 :             : 
    1701                 :         766 :         em->em_relids = adjust_relid_set(em->em_relids, from, to);
    1702                 :         766 :         em->em_jdomain->jd_relids = adjust_relid_set(em->em_jdomain->jd_relids, from, to);
    1703                 :             : 
    1704                 :             :         /* We only process inner joins */
    1705                 :         766 :         ChangeVarNodesExtended((Node *) em->em_expr, from, to, 0,
    1706                 :             :                                replace_relid_callback);
    1707                 :             : 
    1708   [ +  +  +  +  :        1552 :         foreach_node(EquivalenceMember, other, new_members)
                   +  + ]
    1709                 :             :         {
    1710         [ +  + ]:         186 :             if (!equal(em->em_relids, other->em_relids))
    1711                 :          20 :                 continue;
    1712                 :             : 
    1713         [ +  - ]:         166 :             if (equal(em->em_expr, other->em_expr))
    1714                 :             :             {
    1715                 :         166 :                 is_redundant = true;
    1716                 :         166 :                 break;
    1717                 :             :             }
    1718                 :             :         }
    1719                 :             : 
    1720         [ +  + ]:         766 :         if (!is_redundant)
    1721                 :         600 :             new_members = lappend(new_members, em);
    1722                 :             :     }
    1723                 :             : 
    1724                 :         751 :     list_free(ec->ec_members);
    1725                 :         751 :     ec->ec_members = new_members;
    1726                 :             : 
    1727                 :         751 :     ec_clear_derived_clauses(ec);
    1728                 :             : 
    1729                 :             :     /* Update EC source expressions */
    1730   [ +  +  +  +  :        2325 :     foreach_node(RestrictInfo, rinfo, ec->ec_sources)
                   +  + ]
    1731                 :             :     {
    1732                 :         823 :         bool        is_redundant = false;
    1733                 :             : 
    1734         [ +  + ]:         823 :         if (!bms_is_member(from, rinfo->required_relids))
    1735                 :             :         {
    1736                 :         160 :             new_sources = lappend(new_sources, rinfo);
    1737                 :         160 :             continue;
    1738                 :             :         }
    1739                 :             : 
    1740                 :         663 :         ChangeVarNodesExtended((Node *) rinfo, from, to, 0,
    1741                 :             :                                replace_relid_callback);
    1742                 :             : 
    1743                 :             :         /*
    1744                 :             :          * After switching the clause to the remaining relation, check it for
    1745                 :             :          * redundancy with existing ones. We don't have to check for
    1746                 :             :          * redundancy with derived clauses, because we've just deleted them.
    1747                 :             :          */
    1748   [ +  +  +  +  :        1338 :         foreach_node(RestrictInfo, other, new_sources)
                   +  + ]
    1749                 :             :         {
    1750         [ +  + ]:          22 :             if (!equal(rinfo->clause_relids, other->clause_relids))
    1751                 :          12 :                 continue;
    1752                 :             : 
    1753         [ +  - ]:          10 :             if (equal(rinfo->clause, other->clause))
    1754                 :             :             {
    1755                 :          10 :                 is_redundant = true;
    1756                 :          10 :                 break;
    1757                 :             :             }
    1758                 :             :         }
    1759                 :             : 
    1760         [ +  + ]:         663 :         if (!is_redundant)
    1761                 :         653 :             new_sources = lappend(new_sources, rinfo);
    1762                 :             :     }
    1763                 :             : 
    1764                 :         751 :     list_free(ec->ec_sources);
    1765                 :         751 :     ec->ec_sources = new_sources;
    1766                 :         751 :     ec->ec_relids = adjust_relid_set(ec->ec_relids, from, to);
    1767                 :         751 : }
    1768                 :             : 
    1769                 :             : /*
    1770                 :             :  * "Logically" compares two RestrictInfo's ignoring the 'rinfo_serial' field,
    1771                 :             :  * which makes almost every RestrictInfo unique.  This type of comparison is
    1772                 :             :  * useful when removing duplicates while moving RestrictInfo's from removed
    1773                 :             :  * relation to remaining relation during self-join elimination.
    1774                 :             :  *
    1775                 :             :  * XXX: In the future, we might remove the 'rinfo_serial' field completely and
    1776                 :             :  * get rid of this function.
    1777                 :             :  */
    1778                 :             : static bool
    1779                 :         476 : restrict_infos_logically_equal(RestrictInfo *a, RestrictInfo *b)
    1780                 :             : {
    1781                 :         476 :     int         saved_rinfo_serial = a->rinfo_serial;
    1782                 :             :     bool        result;
    1783                 :             : 
    1784                 :         476 :     a->rinfo_serial = b->rinfo_serial;
    1785                 :         476 :     result = equal(a, b);
    1786                 :         476 :     a->rinfo_serial = saved_rinfo_serial;
    1787                 :             : 
    1788                 :         476 :     return result;
    1789                 :             : }
    1790                 :             : 
    1791                 :             : /*
    1792                 :             :  * This function adds all non-redundant clauses to the keeping relation
    1793                 :             :  * during self-join elimination.  That is a contradictory operation. On the
    1794                 :             :  * one hand, we reduce the length of the `restrict` lists, which can
    1795                 :             :  * impact planning or executing time.  Additionally, we improve the
    1796                 :             :  * accuracy of cardinality estimation.  On the other hand, it is one more
    1797                 :             :  * place that can make planning time much longer in specific cases.  It
    1798                 :             :  * would have been better to avoid calling the equal() function here, but
    1799                 :             :  * it's the only way to detect duplicated inequality expressions.
    1800                 :             :  *
    1801                 :             :  * (*keep_rinfo_list) is given by pointer because it might be altered by
    1802                 :             :  * distribute_restrictinfo_to_rels().
    1803                 :             :  */
    1804                 :             : static void
    1805                 :         936 : add_non_redundant_clauses(PlannerInfo *root,
    1806                 :             :                           List *rinfo_candidates,
    1807                 :             :                           List **keep_rinfo_list,
    1808                 :             :                           Index removed_relid)
    1809                 :             : {
    1810   [ +  +  +  +  :        2652 :     foreach_node(RestrictInfo, rinfo, rinfo_candidates)
                   +  + ]
    1811                 :             :     {
    1812                 :         780 :         bool        is_redundant = false;
    1813                 :             : 
    1814                 :             :         Assert(!bms_is_member(removed_relid, rinfo->required_relids));
    1815                 :             : 
    1816   [ +  +  +  +  :        1939 :         foreach_node(RestrictInfo, src, (*keep_rinfo_list))
                   +  + ]
    1817                 :             :         {
    1818         [ +  + ]:         496 :             if (!bms_equal(src->clause_relids, rinfo->clause_relids))
    1819                 :             :                 /* Can't compare trivially different clauses */
    1820                 :          15 :                 continue;
    1821                 :             : 
    1822         [ +  - ]:         481 :             if (src == rinfo ||
    1823         [ +  + ]:         481 :                 (rinfo->parent_ec != NULL &&
    1824   [ +  +  +  + ]:         790 :                  src->parent_ec == rinfo->parent_ec) ||
    1825                 :         476 :                 restrict_infos_logically_equal(rinfo, src))
    1826                 :             :             {
    1827                 :         117 :                 is_redundant = true;
    1828                 :         117 :                 break;
    1829                 :             :             }
    1830                 :             :         }
    1831         [ +  + ]:         780 :         if (!is_redundant)
    1832                 :         663 :             distribute_restrictinfo_to_rels(root, rinfo);
    1833                 :             :     }
    1834                 :         936 : }
    1835                 :             : 
    1836                 :             : /*
    1837                 :             :  * A custom callback for ChangeVarNodesExtended() providing Self-join
    1838                 :             :  * elimination (SJE) related functionality
    1839                 :             :  *
    1840                 :             :  * SJE needs to skip the RangeTblRef node type.  During SJE's last
    1841                 :             :  * step, remove_rel_from_joinlist() removes remaining RangeTblRefs
    1842                 :             :  * with target relid.  If ChangeVarNodes() replaces the target relid
    1843                 :             :  * before, remove_rel_from_joinlist() would fail to identify the nodes
    1844                 :             :  * to delete.
    1845                 :             :  *
    1846                 :             :  * SJE also needs to change the relids within RestrictInfo's.
    1847                 :             :  */
    1848                 :             : static bool
    1849                 :       30676 : replace_relid_callback(Node *node, ChangeVarNodes_context *context)
    1850                 :             : {
    1851         [ +  + ]:       30676 :     if (IsA(node, RangeTblRef))
    1852                 :             :     {
    1853                 :        1249 :         return true;
    1854                 :             :     }
    1855         [ +  + ]:       29427 :     else if (IsA(node, RestrictInfo))
    1856                 :             :     {
    1857                 :        1463 :         RestrictInfo *rinfo = (RestrictInfo *) node;
    1858                 :        1463 :         int         relid = -1;
    1859                 :        1463 :         bool        is_req_equal =
    1860                 :        1463 :             (rinfo->required_relids == rinfo->clause_relids);
    1861                 :        1463 :         bool        clause_relids_is_multiple =
    1862                 :        1463 :             (bms_membership(rinfo->clause_relids) == BMS_MULTIPLE);
    1863                 :             : 
    1864                 :             :         /*
    1865                 :             :          * Recurse down into clauses if the target relation is present in
    1866                 :             :          * clause_relids or required_relids.  We must check required_relids
    1867                 :             :          * because the relation not present in clause_relids might still be
    1868                 :             :          * present somewhere in orclause.
    1869                 :             :          */
    1870   [ +  +  +  + ]:        1511 :         if (bms_is_member(context->rt_index, rinfo->clause_relids) ||
    1871                 :          48 :             bms_is_member(context->rt_index, rinfo->required_relids))
    1872                 :             :         {
    1873                 :             :             Relids      new_clause_relids;
    1874                 :             : 
    1875                 :        1453 :             ChangeVarNodesWalkExpression((Node *) rinfo->clause, context);
    1876                 :        1453 :             ChangeVarNodesWalkExpression((Node *) rinfo->orclause, context);
    1877                 :             : 
    1878                 :        1453 :             new_clause_relids = adjust_relid_set(rinfo->clause_relids,
    1879                 :             :                                                  context->rt_index,
    1880                 :             :                                                  context->new_index);
    1881                 :             : 
    1882                 :             :             /*
    1883                 :             :              * Incrementally adjust num_base_rels based on the change of
    1884                 :             :              * clause_relids, which could contain both base relids and
    1885                 :             :              * outer-join relids.  This operation is legal until we remove
    1886                 :             :              * only baserels.
    1887                 :             :              */
    1888                 :        1453 :             rinfo->num_base_rels -= bms_num_members(rinfo->clause_relids) -
    1889                 :        1453 :                 bms_num_members(new_clause_relids);
    1890                 :             : 
    1891                 :        1453 :             rinfo->clause_relids = new_clause_relids;
    1892                 :        1453 :             rinfo->left_relids =
    1893                 :        1453 :                 adjust_relid_set(rinfo->left_relids, context->rt_index, context->new_index);
    1894                 :        1453 :             rinfo->right_relids =
    1895                 :        1453 :                 adjust_relid_set(rinfo->right_relids, context->rt_index, context->new_index);
    1896                 :             :         }
    1897                 :             : 
    1898         [ +  + ]:        1463 :         if (is_req_equal)
    1899                 :          20 :             rinfo->required_relids = rinfo->clause_relids;
    1900                 :             :         else
    1901                 :        1443 :             rinfo->required_relids =
    1902                 :        1443 :                 adjust_relid_set(rinfo->required_relids, context->rt_index, context->new_index);
    1903                 :             : 
    1904                 :        1463 :         rinfo->outer_relids =
    1905                 :        1463 :             adjust_relid_set(rinfo->outer_relids, context->rt_index, context->new_index);
    1906                 :        1463 :         rinfo->incompatible_relids =
    1907                 :        1463 :             adjust_relid_set(rinfo->incompatible_relids, context->rt_index, context->new_index);
    1908                 :             : 
    1909   [ +  +  +  + ]:        2767 :         if (rinfo->mergeopfamilies &&
    1910         [ +  + ]:        2490 :             bms_get_singleton_member(rinfo->clause_relids, &relid) &&
    1911                 :         991 :             clause_relids_is_multiple &&
    1912   [ +  -  +  - ]:         991 :             relid == context->new_index && IsA(rinfo->clause, OpExpr))
    1913                 :             :         {
    1914                 :             :             Expr       *leftOp;
    1915                 :             :             Expr       *rightOp;
    1916                 :             : 
    1917                 :         991 :             leftOp = (Expr *) get_leftop(rinfo->clause);
    1918                 :         991 :             rightOp = (Expr *) get_rightop(rinfo->clause);
    1919                 :             : 
    1920                 :             :             /*
    1921                 :             :              * For self-join elimination, changing varnos could transform
    1922                 :             :              * "t1.a = t2.a" into "t1.a = t1.a".  That is always true as long
    1923                 :             :              * as "t1.a" is not null.  We use equal() to check for such a
    1924                 :             :              * case, and then we replace the qual with a check for not null
    1925                 :             :              * (NullTest).
    1926                 :             :              */
    1927   [ +  -  +  + ]:         991 :             if (leftOp != NULL && equal(leftOp, rightOp))
    1928                 :             :             {
    1929                 :         981 :                 NullTest   *ntest = makeNode(NullTest);
    1930                 :             : 
    1931                 :         981 :                 ntest->arg = leftOp;
    1932                 :         981 :                 ntest->nulltesttype = IS_NOT_NULL;
    1933                 :         981 :                 ntest->argisrow = false;
    1934                 :         981 :                 ntest->location = -1;
    1935                 :         981 :                 rinfo->clause = (Expr *) ntest;
    1936                 :         981 :                 rinfo->mergeopfamilies = NIL;
    1937                 :         981 :                 rinfo->left_em = NULL;
    1938                 :         981 :                 rinfo->right_em = NULL;
    1939                 :             :             }
    1940                 :             :             Assert(rinfo->orclause == NULL);
    1941                 :             :         }
    1942                 :        1463 :         return true;
    1943                 :             :     }
    1944                 :             : 
    1945                 :       27964 :     return false;
    1946                 :             : }
    1947                 :             : 
    1948                 :             : /*
    1949                 :             :  * Remove a relation after we have proven that it participates only in an
    1950                 :             :  * unneeded unique self-join.
    1951                 :             :  *
    1952                 :             :  * Replace any links in planner info structures.
    1953                 :             :  *
    1954                 :             :  * Transfer join and restriction clauses from the removed relation to the
    1955                 :             :  * remaining one. We change the Vars of the clause to point to the
    1956                 :             :  * remaining relation instead of the removed one. The clauses that require
    1957                 :             :  * a subset of joinrelids become restriction clauses of the remaining
    1958                 :             :  * relation, and others remain join clauses. We append them to
    1959                 :             :  * baserestrictinfo and joininfo, respectively, trying not to introduce
    1960                 :             :  * duplicates.
    1961                 :             :  *
    1962                 :             :  * We also have to process the 'joinclauses' list here, because it
    1963                 :             :  * contains EC-derived join clauses which must become filter clauses. It
    1964                 :             :  * is not enough to just correct the ECs because the EC-derived
    1965                 :             :  * restrictions are generated before join removal (see
    1966                 :             :  * generate_base_implied_equalities).
    1967                 :             :  *
    1968                 :             :  * NOTE: Remember to keep the code in sync with PlannerInfo to be sure all
    1969                 :             :  * cached relids and relid bitmapsets can be correctly cleaned during the
    1970                 :             :  * self-join elimination procedure.
    1971                 :             :  */
    1972                 :             : static void
    1973                 :         468 : remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
    1974                 :             :                      RelOptInfo *toKeep, RelOptInfo *toRemove,
    1975                 :             :                      List *restrictlist)
    1976                 :             : {
    1977                 :             :     List       *joininfos;
    1978                 :             :     ListCell   *lc;
    1979                 :             :     int         i;
    1980                 :         468 :     List       *jinfo_candidates = NIL;
    1981                 :         468 :     List       *binfo_candidates = NIL;
    1982                 :             : 
    1983                 :             :     Assert(toKeep->relid > 0);
    1984                 :             :     Assert(toRemove->relid > 0);
    1985                 :             : 
    1986                 :             :     /*
    1987                 :             :      * Replace the index of the removing table with the keeping one. The
    1988                 :             :      * technique of removing/distributing restrictinfo is used here to attach
    1989                 :             :      * just appeared (for keeping relation) join clauses and avoid adding
    1990                 :             :      * duplicates of those that already exist in the joininfo list.
    1991                 :             :      */
    1992                 :         468 :     joininfos = list_copy(toRemove->joininfo);
    1993   [ +  +  +  +  :        1019 :     foreach_node(RestrictInfo, rinfo, joininfos)
                   +  + ]
    1994                 :             :     {
    1995                 :          83 :         remove_join_clause_from_rels(root, rinfo, rinfo->required_relids);
    1996                 :          83 :         ChangeVarNodesExtended((Node *) rinfo, toRemove->relid, toKeep->relid,
    1997                 :             :                                0, replace_relid_callback);
    1998                 :             : 
    1999         [ +  + ]:          83 :         if (bms_membership(rinfo->required_relids) == BMS_MULTIPLE)
    2000                 :          68 :             jinfo_candidates = lappend(jinfo_candidates, rinfo);
    2001                 :             :         else
    2002                 :          15 :             binfo_candidates = lappend(binfo_candidates, rinfo);
    2003                 :             :     }
    2004                 :             : 
    2005                 :             :     /*
    2006                 :             :      * Concatenate restrictlist to the list of base restrictions of the
    2007                 :             :      * removing table just to simplify the replacement procedure: all of them
    2008                 :             :      * weren't connected to any keeping relations and need to be added to some
    2009                 :             :      * rels.
    2010                 :             :      */
    2011                 :         468 :     toRemove->baserestrictinfo = list_concat(toRemove->baserestrictinfo,
    2012                 :             :                                              restrictlist);
    2013   [ +  -  +  +  :        1633 :     foreach_node(RestrictInfo, rinfo, toRemove->baserestrictinfo)
                   +  + ]
    2014                 :             :     {
    2015                 :         697 :         ChangeVarNodesExtended((Node *) rinfo, toRemove->relid, toKeep->relid,
    2016                 :             :                                0, replace_relid_callback);
    2017                 :             : 
    2018         [ -  + ]:         697 :         if (bms_membership(rinfo->required_relids) == BMS_MULTIPLE)
    2019                 :           0 :             jinfo_candidates = lappend(jinfo_candidates, rinfo);
    2020                 :             :         else
    2021                 :         697 :             binfo_candidates = lappend(binfo_candidates, rinfo);
    2022                 :             :     }
    2023                 :             : 
    2024                 :             :     /*
    2025                 :             :      * Now, add all non-redundant clauses to the keeping relation.
    2026                 :             :      */
    2027                 :         468 :     add_non_redundant_clauses(root, binfo_candidates,
    2028                 :             :                               &toKeep->baserestrictinfo, toRemove->relid);
    2029                 :         468 :     add_non_redundant_clauses(root, jinfo_candidates,
    2030                 :             :                               &toKeep->joininfo, toRemove->relid);
    2031                 :             : 
    2032                 :         468 :     list_free(binfo_candidates);
    2033                 :         468 :     list_free(jinfo_candidates);
    2034                 :             : 
    2035                 :             :     /*
    2036                 :             :      * Arrange equivalence classes, mentioned removing a table, with the
    2037                 :             :      * keeping one: varno of removing table should be replaced in members and
    2038                 :             :      * sources lists. Also, remove duplicated elements if this replacement
    2039                 :             :      * procedure created them.
    2040                 :             :      */
    2041                 :         468 :     i = -1;
    2042         [ +  + ]:        1219 :     while ((i = bms_next_member(toRemove->eclass_indexes, i)) >= 0)
    2043                 :             :     {
    2044                 :         751 :         EquivalenceClass *ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
    2045                 :             : 
    2046                 :         751 :         update_eclasses(ec, toRemove->relid, toKeep->relid);
    2047                 :         751 :         toKeep->eclass_indexes = bms_add_member(toKeep->eclass_indexes, i);
    2048                 :             :     }
    2049                 :             : 
    2050                 :             :     /*
    2051                 :             :      * Transfer the targetlist and attr_needed flags.
    2052                 :             :      */
    2053                 :             : 
    2054   [ +  -  +  +  :        1704 :     foreach(lc, toRemove->reltarget->exprs)
                   +  + ]
    2055                 :             :     {
    2056                 :        1236 :         Node       *node = lfirst(lc);
    2057                 :             : 
    2058                 :        1236 :         ChangeVarNodesExtended(node, toRemove->relid, toKeep->relid, 0,
    2059                 :             :                                replace_relid_callback);
    2060         [ +  + ]:        1236 :         if (!list_member(toKeep->reltarget->exprs, node))
    2061                 :         128 :             toKeep->reltarget->exprs = lappend(toKeep->reltarget->exprs, node);
    2062                 :             :     }
    2063                 :             : 
    2064         [ +  + ]:        5653 :     for (i = toKeep->min_attr; i <= toKeep->max_attr; i++)
    2065                 :             :     {
    2066                 :        5185 :         int         attno = i - toKeep->min_attr;
    2067                 :             : 
    2068                 :       10370 :         toRemove->attr_needed[attno] = adjust_relid_set(toRemove->attr_needed[attno],
    2069                 :        5185 :                                                         toRemove->relid, toKeep->relid);
    2070                 :        5185 :         toKeep->attr_needed[attno] = bms_add_members(toKeep->attr_needed[attno],
    2071                 :        5185 :                                                      toRemove->attr_needed[attno]);
    2072                 :             :     }
    2073                 :             : 
    2074                 :             :     /*
    2075                 :             :      * If the removed relation has a row mark, transfer it to the remaining
    2076                 :             :      * one.
    2077                 :             :      *
    2078                 :             :      * If both rels have row marks, just keep the one corresponding to the
    2079                 :             :      * remaining relation because we verified earlier that they have the same
    2080                 :             :      * strength.
    2081                 :             :      */
    2082         [ +  + ]:         468 :     if (rmark)
    2083                 :             :     {
    2084         [ +  - ]:          41 :         if (kmark)
    2085                 :             :         {
    2086                 :             :             Assert(kmark->markType == rmark->markType);
    2087                 :             : 
    2088                 :          41 :             root->rowMarks = list_delete_ptr(root->rowMarks, rmark);
    2089                 :             :         }
    2090                 :             :         else
    2091                 :             :         {
    2092                 :             :             /* Shouldn't have inheritance children here. */
    2093                 :             :             Assert(rmark->rti == rmark->prti);
    2094                 :             : 
    2095                 :           0 :             rmark->rti = rmark->prti = toKeep->relid;
    2096                 :             :         }
    2097                 :             :     }
    2098                 :             : 
    2099                 :             :     /*
    2100                 :             :      * Replace varno in all the query structures, except nodes RangeTblRef
    2101                 :             :      * otherwise later remove_rel_from_joinlist will yield errors.
    2102                 :             :      */
    2103                 :         468 :     ChangeVarNodesExtended((Node *) root->parse, toRemove->relid, toKeep->relid,
    2104                 :             :                            0, replace_relid_callback);
    2105                 :             : 
    2106                 :             :     /* Replace links in the planner info */
    2107                 :         468 :     remove_rel_from_query(root, toRemove->relid, toKeep->relid, NULL, NULL);
    2108                 :             : 
    2109                 :             :     /* Replace varno in the fully-processed targetlist */
    2110                 :         468 :     ChangeVarNodesExtended((Node *) root->processed_tlist, toRemove->relid,
    2111                 :         468 :                            toKeep->relid, 0, replace_relid_callback);
    2112                 :             : 
    2113                 :             :     /*
    2114                 :             :      * No need to touch all_result_relids or leaf_result_relids: at this point
    2115                 :             :      * those sets contain only parse->resultRelation; inheritance children
    2116                 :             :      * have not been added yet; that happens later in add_other_rels_to_query.
    2117                 :             :      * And remove_self_joins_recurse rejects parse->resultRelation as an SJE
    2118                 :             :      * candidate to preserve the EPQ mechanism.  So toRemove->relid cannot be
    2119                 :             :      * a member.
    2120                 :             :      */
    2121                 :             :     Assert(!bms_is_member(toRemove->relid, root->all_result_relids));
    2122                 :             :     Assert(!bms_is_member(toRemove->relid, root->leaf_result_relids));
    2123                 :             : 
    2124                 :             :     /*
    2125                 :             :      * There may be references to the rel in root->fkey_list, but if so,
    2126                 :             :      * match_foreign_keys_to_quals() will get rid of them.
    2127                 :             :      */
    2128                 :             : 
    2129                 :             :     /*
    2130                 :             :      * Finally, remove the rel from the baserel array to prevent it from being
    2131                 :             :      * referenced again.  (We can't do this earlier because
    2132                 :             :      * remove_join_clause_from_rels will touch it.)
    2133                 :             :      */
    2134                 :         468 :     root->simple_rel_array[toRemove->relid] = NULL;
    2135                 :         468 :     root->simple_rte_array[toRemove->relid] = NULL;
    2136                 :             : 
    2137                 :             :     /* And nuke the RelOptInfo, just in case there's another access path. */
    2138                 :         468 :     pfree(toRemove);
    2139                 :             : 
    2140                 :             : 
    2141                 :             :     /*
    2142                 :             :      * Now repeat construction of attr_needed bits coming from all other
    2143                 :             :      * sources.
    2144                 :             :      */
    2145                 :         468 :     rebuild_placeholder_attr_needed(root);
    2146                 :         468 :     rebuild_joinclause_attr_needed(root);
    2147                 :         468 :     rebuild_eclass_attr_needed(root);
    2148                 :         468 :     rebuild_lateral_attr_needed(root);
    2149                 :         468 : }
    2150                 :             : 
    2151                 :             : /*
    2152                 :             :  * split_selfjoin_quals
    2153                 :             :  *      Processes 'joinquals' by building two lists: one containing the quals
    2154                 :             :  *      where the columns/exprs are on either side of the join match and
    2155                 :             :  *      another one containing the remaining quals.
    2156                 :             :  *
    2157                 :             :  * 'joinquals' must only contain quals for a RTE_RELATION being joined to
    2158                 :             :  * itself.
    2159                 :             :  */
    2160                 :             : static void
    2161                 :        1791 : split_selfjoin_quals(PlannerInfo *root, List *joinquals, List **selfjoinquals,
    2162                 :             :                      List **otherjoinquals, int from, int to)
    2163                 :             : {
    2164                 :        1791 :     List       *sjoinquals = NIL;
    2165                 :        1791 :     List       *ojoinquals = NIL;
    2166                 :             : 
    2167   [ +  -  +  +  :        5497 :     foreach_node(RestrictInfo, rinfo, joinquals)
                   +  + ]
    2168                 :             :     {
    2169                 :             :         OpExpr     *expr;
    2170                 :             :         Node       *leftexpr;
    2171                 :             :         Node       *rightexpr;
    2172                 :             : 
    2173                 :             :         /* In general, clause looks like F(arg1) = G(arg2) */
    2174   [ +  -  +  - ]:        3830 :         if (!rinfo->mergeopfamilies ||
    2175         [ +  - ]:        3830 :             bms_num_members(rinfo->clause_relids) != 2 ||
    2176         [ -  + ]:        3830 :             bms_membership(rinfo->left_relids) != BMS_SINGLETON ||
    2177                 :        1915 :             bms_membership(rinfo->right_relids) != BMS_SINGLETON)
    2178                 :             :         {
    2179                 :           0 :             ojoinquals = lappend(ojoinquals, rinfo);
    2180                 :           0 :             continue;
    2181                 :             :         }
    2182                 :             : 
    2183                 :        1915 :         expr = (OpExpr *) rinfo->clause;
    2184                 :             : 
    2185   [ +  -  -  + ]:        1915 :         if (!IsA(expr, OpExpr) || list_length(expr->args) != 2)
    2186                 :             :         {
    2187                 :           0 :             ojoinquals = lappend(ojoinquals, rinfo);
    2188                 :           0 :             continue;
    2189                 :             :         }
    2190                 :             : 
    2191                 :        1915 :         leftexpr = get_leftop(rinfo->clause);
    2192                 :        1915 :         rightexpr = copyObject(get_rightop(rinfo->clause));
    2193                 :             : 
    2194   [ +  -  +  + ]:        1915 :         if (leftexpr && IsA(leftexpr, RelabelType))
    2195                 :         130 :             leftexpr = (Node *) ((RelabelType *) leftexpr)->arg;
    2196   [ +  -  +  + ]:        1915 :         if (rightexpr && IsA(rightexpr, RelabelType))
    2197                 :         125 :             rightexpr = (Node *) ((RelabelType *) rightexpr)->arg;
    2198                 :             : 
    2199                 :             :         /*
    2200                 :             :          * Quite an expensive operation, narrowing the use case. For example,
    2201                 :             :          * when we have cast of the same var to different (but compatible)
    2202                 :             :          * types.
    2203                 :             :          */
    2204                 :        1915 :         ChangeVarNodesExtended(rightexpr,
    2205                 :        1915 :                                bms_singleton_member(rinfo->right_relids),
    2206                 :        1915 :                                bms_singleton_member(rinfo->left_relids), 0,
    2207                 :             :                                replace_relid_callback);
    2208                 :             : 
    2209         [ +  + ]:        1915 :         if (equal(leftexpr, rightexpr))
    2210                 :        1492 :             sjoinquals = lappend(sjoinquals, rinfo);
    2211                 :             :         else
    2212                 :         423 :             ojoinquals = lappend(ojoinquals, rinfo);
    2213                 :             :     }
    2214                 :             : 
    2215                 :        1791 :     *selfjoinquals = sjoinquals;
    2216                 :        1791 :     *otherjoinquals = ojoinquals;
    2217                 :        1791 : }
    2218                 :             : 
    2219                 :             : /*
    2220                 :             :  * Check for a case when uniqueness is at least partly derived from a
    2221                 :             :  * baserestrictinfo clause. In this case, we have a chance to return only
    2222                 :             :  * one row (if such clauses on both sides of SJ are equal) or nothing (if they
    2223                 :             :  * are different).
    2224                 :             :  */
    2225                 :             : static bool
    2226                 :         523 : match_unique_clauses(PlannerInfo *root, RelOptInfo *outer, List *uclauses,
    2227                 :             :                      Index relid)
    2228                 :             : {
    2229   [ +  +  +  +  :        1061 :     foreach_node(RestrictInfo, rinfo, uclauses)
                   +  + ]
    2230                 :             :     {
    2231                 :             :         Expr       *clause;
    2232                 :             :         Node       *iclause;
    2233                 :             :         Node       *c1;
    2234                 :         125 :         bool        matched = false;
    2235                 :             : 
    2236                 :             :         Assert(outer->relid > 0 && relid > 0);
    2237                 :             : 
    2238                 :             :         /* Only filters like f(R.x1,...,R.xN) == expr we should consider. */
    2239                 :             :         Assert(bms_is_empty(rinfo->left_relids) ^
    2240                 :             :                bms_is_empty(rinfo->right_relids));
    2241                 :             : 
    2242                 :         125 :         clause = (Expr *) copyObject(rinfo->clause);
    2243                 :         125 :         ChangeVarNodesExtended((Node *) clause, relid, outer->relid, 0,
    2244                 :             :                                replace_relid_callback);
    2245                 :             : 
    2246         [ +  + ]:         125 :         iclause = bms_is_empty(rinfo->left_relids) ? get_rightop(clause) :
    2247                 :         120 :             get_leftop(clause);
    2248         [ +  + ]:         125 :         c1 = bms_is_empty(rinfo->left_relids) ? get_leftop(clause) :
    2249                 :         120 :             get_rightop(clause);
    2250                 :             : 
    2251                 :             :         /*
    2252                 :             :          * Compare these left and right sides with the corresponding sides of
    2253                 :             :          * the outer's filters. If no one is detected - return immediately.
    2254                 :             :          */
    2255   [ +  +  +  +  :         340 :         foreach_node(RestrictInfo, orinfo, outer->baserestrictinfo)
                   +  + ]
    2256                 :             :         {
    2257                 :             :             Node       *oclause;
    2258                 :             :             Node       *c2;
    2259                 :             : 
    2260         [ +  + ]:         160 :             if (orinfo->mergeopfamilies == NIL)
    2261                 :             :                 /* Don't consider clauses that aren't similar to 'F(X)=G(Y)' */
    2262                 :          50 :                 continue;
    2263                 :             : 
    2264                 :             :             Assert(is_opclause(orinfo->clause));
    2265                 :             : 
    2266                 :         220 :             oclause = bms_is_empty(orinfo->left_relids) ?
    2267         [ +  + ]:         110 :                 get_rightop(orinfo->clause) : get_leftop(orinfo->clause);
    2268                 :         220 :             c2 = (bms_is_empty(orinfo->left_relids) ?
    2269         [ +  + ]:         110 :                   get_leftop(orinfo->clause) : get_rightop(orinfo->clause));
    2270                 :             : 
    2271   [ +  +  +  + ]:         110 :             if (equal(iclause, oclause) && equal(c1, c2))
    2272                 :             :             {
    2273                 :          70 :                 matched = true;
    2274                 :          70 :                 break;
    2275                 :             :             }
    2276                 :             :         }
    2277                 :             : 
    2278         [ +  + ]:         125 :         if (!matched)
    2279                 :          55 :             return false;
    2280                 :             :     }
    2281                 :             : 
    2282                 :         468 :     return true;
    2283                 :             : }
    2284                 :             : 
    2285                 :             : /*
    2286                 :             :  * Find and remove unique self-joins in a group of base relations that have
    2287                 :             :  * the same Oid.
    2288                 :             :  *
    2289                 :             :  * Returns a set of relids that were removed.
    2290                 :             :  */
    2291                 :             : static Relids
    2292                 :        8721 : remove_self_joins_one_group(PlannerInfo *root, Relids relids)
    2293                 :             : {
    2294                 :        8721 :     Relids      result = NULL;
    2295                 :             :     int         k;              /* Index of kept relation */
    2296                 :        8721 :     int         r = -1;         /* Index of removed relation */
    2297                 :             : 
    2298         [ +  + ]:       27267 :     while ((r = bms_next_member(relids, r)) > 0)
    2299                 :             :     {
    2300                 :       18546 :         RelOptInfo *rrel = root->simple_rel_array[r];
    2301                 :             : 
    2302                 :       18546 :         k = r;
    2303                 :             : 
    2304         [ +  + ]:       29228 :         while ((k = bms_next_member(relids, k)) > 0)
    2305                 :             :         {
    2306                 :       11150 :             Relids      joinrelids = NULL;
    2307                 :       11150 :             RelOptInfo *krel = root->simple_rel_array[k];
    2308                 :             :             List       *restrictlist;
    2309                 :             :             List       *selfjoinquals;
    2310                 :             :             List       *otherjoinquals;
    2311                 :             :             ListCell   *lc;
    2312                 :       11150 :             bool        jinfo_check = true;
    2313                 :       11150 :             PlanRowMark *kmark = NULL;
    2314                 :       11150 :             PlanRowMark *rmark = NULL;
    2315                 :       11150 :             List       *uclauses = NIL;
    2316                 :             : 
    2317                 :             :             /* A sanity check: the relations have the same Oid. */
    2318                 :             :             Assert(root->simple_rte_array[k]->relid ==
    2319                 :             :                    root->simple_rte_array[r]->relid);
    2320                 :             : 
    2321                 :             :             /*
    2322                 :             :              * It is impossible to eliminate the join of two relations if they
    2323                 :             :              * belong to different rules of order. Otherwise, the planner
    2324                 :             :              * can't find any variants of the correct query plan.
    2325                 :             :              */
    2326   [ +  +  +  +  :       13670 :             foreach(lc, root->join_info_list)
                   +  + ]
    2327                 :             :             {
    2328                 :        8640 :                 SpecialJoinInfo *info = (SpecialJoinInfo *) lfirst(lc);
    2329                 :             : 
    2330         [ +  + ]:       17280 :                 if ((bms_is_member(k, info->syn_lefthand) ^
    2331         [ +  + ]:       12181 :                      bms_is_member(r, info->syn_lefthand)) ||
    2332                 :        3541 :                     (bms_is_member(k, info->syn_righthand) ^
    2333                 :        3541 :                      bms_is_member(r, info->syn_righthand)))
    2334                 :             :                 {
    2335                 :        6120 :                     jinfo_check = false;
    2336                 :        6120 :                     break;
    2337                 :             :                 }
    2338                 :             :             }
    2339         [ +  + ]:       11150 :             if (!jinfo_check)
    2340                 :       10682 :                 continue;
    2341                 :             : 
    2342                 :             :             /*
    2343                 :             :              * Check Row Marks equivalence. We can't remove the join if the
    2344                 :             :              * relations have row marks of different strength (e.g., one is
    2345                 :             :              * locked FOR UPDATE, and another just has ROW_MARK_REFERENCE for
    2346                 :             :              * EvalPlanQual rechecking).
    2347                 :             :              */
    2348   [ +  +  +  -  :        5166 :             foreach(lc, root->rowMarks)
                   +  + ]
    2349                 :             :             {
    2350                 :         242 :                 PlanRowMark *rowMark = (PlanRowMark *) lfirst(lc);
    2351                 :             : 
    2352         [ +  + ]:         242 :                 if (rowMark->rti == r)
    2353                 :             :                 {
    2354                 :             :                     Assert(rmark == NULL);
    2355                 :         106 :                     rmark = rowMark;
    2356                 :             :                 }
    2357         [ +  + ]:         136 :                 else if (rowMark->rti == k)
    2358                 :             :                 {
    2359                 :             :                     Assert(kmark == NULL);
    2360                 :         106 :                     kmark = rowMark;
    2361                 :             :                 }
    2362                 :             : 
    2363   [ +  +  +  - ]:         242 :                 if (kmark && rmark)
    2364                 :         106 :                     break;
    2365                 :             :             }
    2366   [ +  +  +  -  :        5030 :             if (kmark && rmark && kmark->markType != rmark->markType)
                   +  + ]
    2367                 :          28 :                 continue;
    2368                 :             : 
    2369                 :             :             /*
    2370                 :             :              * We only deal with base rels here, so their relids bitset
    2371                 :             :              * contains only one member -- their relid.
    2372                 :             :              */
    2373                 :        5002 :             joinrelids = bms_add_member(joinrelids, r);
    2374                 :        5002 :             joinrelids = bms_add_member(joinrelids, k);
    2375                 :             : 
    2376                 :             :             /*
    2377                 :             :              * PHVs should not impose any constraints on removing self-joins.
    2378                 :             :              */
    2379                 :             : 
    2380                 :             :             /*
    2381                 :             :              * At this stage, joininfo lists of inner and outer can contain
    2382                 :             :              * only clauses required for a superior outer join that can't
    2383                 :             :              * influence this optimization. So, we can avoid to call the
    2384                 :             :              * build_joinrel_restrictlist() routine.
    2385                 :             :              */
    2386                 :        5002 :             restrictlist = generate_join_implied_equalities(root, joinrelids,
    2387                 :             :                                                             rrel->relids,
    2388                 :             :                                                             krel, NULL);
    2389         [ +  + ]:        5002 :             if (restrictlist == NIL)
    2390                 :        3211 :                 continue;
    2391                 :             : 
    2392                 :             :             /*
    2393                 :             :              * Process restrictlist to separate the self-join quals from the
    2394                 :             :              * other quals. e.g., "x = x" goes to selfjoinquals and "a = b" to
    2395                 :             :              * otherjoinquals.
    2396                 :             :              */
    2397                 :        1791 :             split_selfjoin_quals(root, restrictlist, &selfjoinquals,
    2398                 :        1791 :                                  &otherjoinquals, rrel->relid, krel->relid);
    2399                 :             : 
    2400                 :             :             Assert(list_length(restrictlist) ==
    2401                 :             :                    (list_length(selfjoinquals) + list_length(otherjoinquals)));
    2402                 :             : 
    2403                 :             :             /*
    2404                 :             :              * To enable SJE for the only degenerate case without any self
    2405                 :             :              * join clauses at all, add baserestrictinfo to this list. The
    2406                 :             :              * degenerate case works only if both sides have the same clause.
    2407                 :             :              * So doesn't matter which side to add.
    2408                 :             :              */
    2409                 :        1791 :             selfjoinquals = list_concat(selfjoinquals, krel->baserestrictinfo);
    2410                 :             : 
    2411                 :             :             /*
    2412                 :             :              * Determine if the rrel can duplicate outer rows. We must bypass
    2413                 :             :              * the unique rel cache here since we're possibly using a subset
    2414                 :             :              * of join quals. We can use 'force_cache' == true when all join
    2415                 :             :              * quals are self-join quals.  Otherwise, we could end up putting
    2416                 :             :              * false negatives in the cache.
    2417                 :             :              */
    2418         [ +  + ]:        1791 :             if (!innerrel_is_unique_ext(root, joinrelids, rrel->relids,
    2419                 :             :                                         krel, JOIN_INNER, selfjoinquals,
    2420                 :        1791 :                                         list_length(otherjoinquals) == 0,
    2421                 :             :                                         &uclauses))
    2422                 :        1268 :                 continue;
    2423                 :             : 
    2424                 :             :             /*
    2425                 :             :              * 'uclauses' is the copy of outer->baserestrictinfo that are
    2426                 :             :              * associated with an index.  We proved by matching selfjoinquals
    2427                 :             :              * to a unique index that the outer relation has at most one
    2428                 :             :              * matching row for each inner row.  Sometimes that is not enough.
    2429                 :             :              * e.g. "WHERE s1.b = s2.b AND s1.a = 1 AND s2.a = 2" when the
    2430                 :             :              * unique index is (a,b).  Having non-empty uclauses, we must
    2431                 :             :              * validate that the inner baserestrictinfo contains the same
    2432                 :             :              * expressions, or we won't match the same row on each side of the
    2433                 :             :              * join.
    2434                 :             :              */
    2435         [ +  + ]:         523 :             if (!match_unique_clauses(root, rrel, uclauses, krel->relid))
    2436                 :          55 :                 continue;
    2437                 :             : 
    2438                 :             :             /*
    2439                 :             :              * Remove rrel RelOptInfo from the planner structures and the
    2440                 :             :              * corresponding row mark.
    2441                 :             :              */
    2442                 :         468 :             remove_self_join_rel(root, kmark, rmark, krel, rrel, restrictlist);
    2443                 :             : 
    2444                 :         468 :             result = bms_add_member(result, r);
    2445                 :             : 
    2446                 :             :             /* We have removed the outer relation, try the next one. */
    2447                 :         468 :             break;
    2448                 :             :         }
    2449                 :             :     }
    2450                 :             : 
    2451                 :        8721 :     return result;
    2452                 :             : }
    2453                 :             : 
    2454                 :             : /*
    2455                 :             :  * Gather indexes of base relations from the joinlist and try to eliminate self
    2456                 :             :  * joins.
    2457                 :             :  */
    2458                 :             : static Relids
    2459                 :       81597 : remove_self_joins_recurse(PlannerInfo *root, List *joinlist, Relids toRemove)
    2460                 :             : {
    2461                 :             :     ListCell   *jl;
    2462                 :       81597 :     Relids      relids = NULL;
    2463                 :       81597 :     SelfJoinCandidate *candidates = NULL;
    2464                 :             :     int         i;
    2465                 :             :     int         j;
    2466                 :             :     int         numRels;
    2467                 :             : 
    2468                 :             :     /* Collect indexes of base relations of the join tree */
    2469   [ +  -  +  +  :      271490 :     foreach(jl, joinlist)
                   +  + ]
    2470                 :             :     {
    2471                 :      189893 :         Node       *jlnode = (Node *) lfirst(jl);
    2472                 :             : 
    2473         [ +  + ]:      189893 :         if (IsA(jlnode, RangeTblRef))
    2474                 :             :         {
    2475                 :      187175 :             int         varno = ((RangeTblRef *) jlnode)->rtindex;
    2476                 :      187175 :             RangeTblEntry *rte = root->simple_rte_array[varno];
    2477                 :             : 
    2478                 :             :             /*
    2479                 :             :              * We only consider ordinary relations as candidates to be
    2480                 :             :              * removed, and these relations should not have TABLESAMPLE
    2481                 :             :              * clauses specified.  Removing a relation with TABLESAMPLE clause
    2482                 :             :              * could potentially change the syntax of the query. Because of
    2483                 :             :              * UPDATE/DELETE EPQ mechanism, currently Query->resultRelation or
    2484                 :             :              * Query->mergeTargetRelation associated rel cannot be eliminated.
    2485                 :             :              */
    2486         [ +  + ]:      187175 :             if (rte->rtekind == RTE_RELATION &&
    2487         [ +  + ]:      166276 :                 rte->relkind == RELKIND_RELATION &&
    2488         [ +  + ]:      161736 :                 rte->tablesample == NULL &&
    2489         [ +  + ]:      161714 :                 varno != root->parse->resultRelation &&
    2490         [ +  - ]:      160190 :                 varno != root->parse->mergeTargetRelation)
    2491                 :             :             {
    2492                 :             :                 Assert(!bms_is_member(varno, relids));
    2493                 :      160190 :                 relids = bms_add_member(relids, varno);
    2494                 :             :             }
    2495                 :             :         }
    2496         [ +  - ]:        2718 :         else if (IsA(jlnode, List))
    2497                 :             :         {
    2498                 :             :             /* Recursively go inside the sub-joinlist */
    2499                 :        2718 :             toRemove = remove_self_joins_recurse(root, (List *) jlnode,
    2500                 :             :                                                  toRemove);
    2501                 :             :         }
    2502                 :             :         else
    2503         [ #  # ]:           0 :             elog(ERROR, "unrecognized joinlist node type: %d",
    2504                 :             :                  (int) nodeTag(jlnode));
    2505                 :             :     }
    2506                 :             : 
    2507                 :       81597 :     numRels = bms_num_members(relids);
    2508                 :             : 
    2509                 :             :     /* Need at least two relations for the join */
    2510         [ +  + ]:       81597 :     if (numRels < 2)
    2511                 :       21991 :         return toRemove;
    2512                 :             : 
    2513                 :             :     /*
    2514                 :             :      * In order to find relations with the same oid we first build an array of
    2515                 :             :      * candidates and then sort it by oid.
    2516                 :             :      */
    2517                 :       59606 :     candidates = palloc_array(SelfJoinCandidate, numRels);
    2518                 :       59606 :     i = -1;
    2519                 :       59606 :     j = 0;
    2520         [ +  + ]:      204054 :     while ((i = bms_next_member(relids, i)) >= 0)
    2521                 :             :     {
    2522                 :      144448 :         candidates[j].relid = i;
    2523                 :      144448 :         candidates[j].reloid = root->simple_rte_array[i]->relid;
    2524                 :      144448 :         j++;
    2525                 :             :     }
    2526                 :             : 
    2527                 :       59606 :     qsort(candidates, numRels, sizeof(SelfJoinCandidate),
    2528                 :             :           self_join_candidates_cmp);
    2529                 :             : 
    2530                 :             :     /*
    2531                 :             :      * Iteratively form a group of relation indexes with the same oid and
    2532                 :             :      * launch the routine that detects self-joins in this group and removes
    2533                 :             :      * excessive range table entries.
    2534                 :             :      *
    2535                 :             :      * At the end of the iteration, exclude the group from the overall relids
    2536                 :             :      * list. So each next iteration of the cycle will involve less and less
    2537                 :             :      * value of relids.
    2538                 :             :      */
    2539                 :       59606 :     i = 0;
    2540         [ +  + ]:      204054 :     for (j = 1; j < numRels + 1; j++)
    2541                 :             :     {
    2542   [ +  +  +  + ]:      144448 :         if (j == numRels || candidates[j].reloid != candidates[i].reloid)
    2543                 :             :         {
    2544         [ +  + ]:      134703 :             if (j - i >= 2)
    2545                 :             :             {
    2546                 :             :                 /* Create a group of relation indexes with the same oid */
    2547                 :        8651 :                 Relids      group = NULL;
    2548                 :             :                 Relids      removed;
    2549                 :             : 
    2550         [ +  + ]:       27047 :                 while (i < j)
    2551                 :             :                 {
    2552                 :       18396 :                     group = bms_add_member(group, candidates[i].relid);
    2553                 :       18396 :                     i++;
    2554                 :             :                 }
    2555                 :        8651 :                 relids = bms_del_members(relids, group);
    2556                 :             : 
    2557                 :             :                 /*
    2558                 :             :                  * Try to remove self-joins from a group of identical entries.
    2559                 :             :                  * Make the next attempt iteratively - if something is deleted
    2560                 :             :                  * from a group, changes in clauses and equivalence classes
    2561                 :             :                  * can give us a chance to find more candidates.
    2562                 :             :                  */
    2563                 :             :                 do
    2564                 :             :                 {
    2565                 :             :                     Assert(!bms_overlap(group, toRemove));
    2566                 :        8721 :                     removed = remove_self_joins_one_group(root, group);
    2567                 :        8721 :                     toRemove = bms_add_members(toRemove, removed);
    2568                 :        8721 :                     group = bms_del_members(group, removed);
    2569   [ +  +  +  + ]:        9169 :                 } while (!bms_is_empty(removed) &&
    2570                 :         448 :                          bms_membership(group) == BMS_MULTIPLE);
    2571                 :        8651 :                 bms_free(removed);
    2572                 :        8651 :                 bms_free(group);
    2573                 :             :             }
    2574                 :             :             else
    2575                 :             :             {
    2576                 :             :                 /* Single relation, just remove it from the set */
    2577                 :      126052 :                 relids = bms_del_member(relids, candidates[i].relid);
    2578                 :      126052 :                 i = j;
    2579                 :             :             }
    2580                 :             :         }
    2581                 :             :     }
    2582                 :             : 
    2583                 :             :     Assert(bms_is_empty(relids));
    2584                 :             : 
    2585                 :       59606 :     return toRemove;
    2586                 :             : }
    2587                 :             : 
    2588                 :             : /*
    2589                 :             :  * Compare self-join candidates by their oids.
    2590                 :             :  */
    2591                 :             : static int
    2592                 :      105620 : self_join_candidates_cmp(const void *a, const void *b)
    2593                 :             : {
    2594                 :      105620 :     const SelfJoinCandidate *ca = (const SelfJoinCandidate *) a;
    2595                 :      105620 :     const SelfJoinCandidate *cb = (const SelfJoinCandidate *) b;
    2596                 :             : 
    2597         [ +  + ]:      105620 :     if (ca->reloid != cb->reloid)
    2598         [ +  + ]:       95830 :         return (ca->reloid < cb->reloid ? -1 : 1);
    2599                 :             :     else
    2600                 :        9790 :         return 0;
    2601                 :             : }
    2602                 :             : 
    2603                 :             : /*
    2604                 :             :  * Find and remove useless self joins.
    2605                 :             :  *
    2606                 :             :  * Search for joins where a relation is joined to itself. If the join clause
    2607                 :             :  * for each tuple from one side of the join is proven to match the same
    2608                 :             :  * physical row (or nothing) on the other side, that self-join can be
    2609                 :             :  * eliminated from the query.  Suitable join clauses are assumed to be in the
    2610                 :             :  * form of X = X, and can be replaced with NOT NULL clauses.
    2611                 :             :  *
    2612                 :             :  * For the sake of simplicity, we don't apply this optimization to special
    2613                 :             :  * joins. Here is a list of what we could do in some particular cases:
    2614                 :             :  * 'a a1 semi join a a2': is reduced to inner by reduce_unique_semijoins,
    2615                 :             :  * and then removed normally.
    2616                 :             :  * 'a a1 anti join a a2': could simplify to a scan with 'outer quals AND
    2617                 :             :  * (IS NULL on join columns OR NOT inner quals)'.
    2618                 :             :  * 'a a1 left join a a2': could simplify to a scan like inner but without
    2619                 :             :  * NOT NULL conditions on join columns.
    2620                 :             :  * 'a a1 left join (a a2 join b)': can't simplify this, because join to b
    2621                 :             :  * can both remove rows and introduce duplicates.
    2622                 :             :  *
    2623                 :             :  * To search for removable joins, we order all the relations on their Oid,
    2624                 :             :  * go over each set with the same Oid, and consider each pair of relations
    2625                 :             :  * in this set.
    2626                 :             :  *
    2627                 :             :  * To remove the join, we mark one of the participating relations as dead
    2628                 :             :  * and rewrite all references to it to point to the remaining relation.
    2629                 :             :  * This includes modifying RestrictInfos, EquivalenceClasses, and
    2630                 :             :  * EquivalenceMembers. We also have to modify the row marks. The join clauses
    2631                 :             :  * of the removed relation become either restriction or join clauses, based on
    2632                 :             :  * whether they reference any relations not participating in the removed join.
    2633                 :             :  *
    2634                 :             :  * 'joinlist' is the top-level joinlist of the query. If it has any
    2635                 :             :  * references to the removed relations, we update them to point to the
    2636                 :             :  * remaining ones.
    2637                 :             :  */
    2638                 :             : List *
    2639                 :      248597 : remove_useless_self_joins(PlannerInfo *root, List *joinlist)
    2640                 :             : {
    2641                 :      248597 :     Relids      toRemove = NULL;
    2642                 :      248597 :     int         relid = -1;
    2643                 :             : 
    2644   [ +  -  +  -  :      497194 :     if (!enable_self_join_elimination || joinlist == NIL ||
                   +  + ]
    2645         [ +  + ]:      419013 :         (list_length(joinlist) == 1 && !IsA(linitial(joinlist), List)))
    2646                 :      169718 :         return joinlist;
    2647                 :             : 
    2648                 :             :     /*
    2649                 :             :      * Merge pairs of relations participated in self-join. Remove unnecessary
    2650                 :             :      * range table entries.
    2651                 :             :      */
    2652                 :       78879 :     toRemove = remove_self_joins_recurse(root, joinlist, toRemove);
    2653                 :             : 
    2654         [ +  + ]:       78879 :     if (unlikely(toRemove != NULL))
    2655                 :             :     {
    2656                 :             :         /* At the end, remove orphaned relation links */
    2657         [ +  + ]:         911 :         while ((relid = bms_next_member(toRemove, relid)) >= 0)
    2658                 :             :         {
    2659                 :         468 :             int         nremoved = 0;
    2660                 :             : 
    2661                 :         468 :             joinlist = remove_rel_from_joinlist(joinlist, relid, &nremoved);
    2662         [ -  + ]:         468 :             if (nremoved != 1)
    2663         [ #  # ]:           0 :                 elog(ERROR, "failed to find relation %d in joinlist", relid);
    2664                 :             :         }
    2665                 :             :     }
    2666                 :             : 
    2667                 :       78879 :     return joinlist;
    2668                 :             : }
        

Generated by: LCOV version 2.0-1