• Tom Lane's avatar
    Avoid invalidating all foreign-join cached plans when user mappings change. · 45639a05
    Tom Lane authored
    We must not push down a foreign join when the foreign tables involved
    should be accessed under different user mappings.  Previously we tried
    to enforce that rule literally during planning, but that meant that the
    resulting plans were dependent on the current contents of the
    pg_user_mapping catalog, and we had to blow away all cached plans
    containing any remote join when anything at all changed in pg_user_mapping.
    This could have been improved somewhat, but the fact that a syscache inval
    callback has very limited info about what changed made it hard to do better
    within that design.  Instead, let's change the planner to not consider user
    mappings per se, but to allow a foreign join if both RTEs have the same
    checkAsUser value.  If they do, then they necessarily will use the same
    user mapping at runtime, and we don't need to know specifically which one
    that is.  Post-plan-time changes in pg_user_mapping no longer require any
    plan invalidation.
    
    This rule does give up some optimization ability, to wit where two foreign
    table references come from views with different owners or one's from a view
    and one's directly in the query, but nonetheless the same user mapping
    would have applied.  We'll sacrifice the first case, but to not regress
    more than we have to in the second case, allow a foreign join involving
    both zero and nonzero checkAsUser values if the nonzero one is the same as
    the prevailing effective userID.  In that case, mark the plan as only
    runnable by that userID.
    
    The plancache code already had a notion of plans being userID-specific,
    in order to support RLS.  It was a little confused though, in particular
    lacking clarity of thought as to whether it was the rewritten query or just
    the finished plan that's dependent on the userID.  Rearrange that code so
    that it's clearer what depends on which, and so that the same logic applies
    to both RLS-injected role dependency and foreign-join-injected role
    dependency.
    
    Note that this patch doesn't remove the other issue mentioned in the
    original complaint, which is that while we'll reliably stop using a foreign
    join if it's disallowed in a new context, we might fail to start using a
    foreign join if it's now allowed, but we previously created a generic
    cached plan that didn't use one.  It was agreed that the chance of winning
    that way was not high enough to justify the much larger number of plan
    invalidations that would have to occur if we tried to cause it to happen.
    
    In passing, clean up randomly-varying spelling of EXPLAIN commands in
    postgres_fdw.sql, and fix a COSTS ON example that had been allowed to
    leak into the committed tests.
    
    This reverts most of commits fbe5a3fb and 5d4171d1, which were the
    previous attempt at ensuring we wouldn't push down foreign joins that
    span permissions contexts.
    
    Etsuro Fujita and Tom Lane
    
    Discussion: <d49c1e5b-f059-20f4-c132-e9752ee0113e@lab.ntt.co.jp>
    45639a05
plancache.h 8.36 KB