Allow extensions to control join strategy.
authorRobert Haas <rhaas@postgresql.org>
Thu, 29 Aug 2024 19:38:58 +0000 (15:38 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 30 Aug 2024 18:08:23 +0000 (14:08 -0400)
commit58d495a03f78d157f2d13a355d21a8bccf2c9de8
tree21db03ab1597516fd5f499a4d9ebc48ba8a637d4
parent6654bb92047b37cee053cedd6fa1829841b2ad8e
Allow extensions to control join strategy.

At the start of join planning, we build a bitmask called jsa_mask based on
the values of the various enable_* planner GUCs, indicating which join
strategies are allowed. Extensions can override this mask on a plan-wide
basis using join_search_hook, or, generaly more usefully, they can change
the mask for each call to add_paths_to_joinrel using a new hook called
join_path_setup_hook. This is sufficient to allow an extension to force
the use of particular join strategies either in general or for specific
joins, and it is also sufficient to allow an extension to force the join
order.

If you want to control some aspect of planner behavior that is not
join-related, this patch won't help, but the same concepts could be
applied to scans, appendrels, and aggregation.

Notes:
- Materialization and memoization are optional sub-strategies when
  performing a nested loop. You might want to avoid these strategies, allow
  them, or force them.  I don't know how this should be controlled.
- join_path_setup_hook will see JOIN_UNIQUE_INNER or JOIN_UNIQUE_OUTER as the
  jointype and can reject if it wants. Conversely, you could allow that
  case and reject the JOIN_SEMI/JOIN_RIGHT_SEMI case. However, if you wanted
  to force the uniquification to use a sort or a hash rather than the
  other, more would be needed (though it looks like you could kludge things
  by modifying the SpecialJoinInfo).
- To fully control merge joins produced by sort_outer_and_inner(),
  you would need control over which merge clauses are selected.
  In match_unsorted_outer(), it's just a function of the input paths.
- You could potentially want to disallow certain strategies at greater
  granularity than is possible here - e.g. unparameterized paths aren't
  disabled, but making a nested loop out of them is.
- There are going to be residual references to various planner GUCs in
  the code path, such as enable_parallel_hash and enable_sort. That seems
  fine.
13 files changed:
src/backend/optimizer/geqo/geqo_eval.c
src/backend/optimizer/geqo/geqo_main.c
src/backend/optimizer/geqo/geqo_pool.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/joinpath.c
src/backend/optimizer/path/joinrels.c
src/backend/optimizer/util/relnode.c
src/include/nodes/pathnodes.h
src/include/optimizer/geqo.h
src/include/optimizer/geqo_pool.h
src/include/optimizer/pathnode.h
src/include/optimizer/paths.h