* push_down_restrict * push down restrictinfo to subquery if any. * * If there are any restriction clauses that have been attached to the * subquery relation, consider pushing them down to become WHERE or HAVING * quals of the subquery itself. This transformation is useful because it * may allow us to generate a better plan for the subquery than evaluating * all the subquery output rows
| 3943 | * push down a pushable qual, because it'd result in a worse plan? |
| 3944 | */ |
| 3945 | static Query * |
| 3946 | push_down_restrict(PlannerInfo *root, RelOptInfo *rel, |
| 3947 | RangeTblEntry *rte, Index rti, Query *subquery) |
| 3948 | { |
| 3949 | pushdown_safety_info safetyInfo; |
| 3950 | |
| 3951 | /* Nothing to do here if it doesn't have qual at all */ |
| 3952 | if (rel->baserestrictinfo == NIL) |
| 3953 | return subquery; |
| 3954 | |
| 3955 | /* |
| 3956 | * Zero out result area for subquery_is_pushdown_safe, so that it can set |
| 3957 | * flags as needed while recursing. In particular, we need a workspace |
| 3958 | * for keeping track of unsafe-to-reference columns. unsafeColumns[i] |
| 3959 | * will be set true if we find that output column i of the subquery is |
| 3960 | * unsafe to use in a pushed-down qual. |
| 3961 | */ |
| 3962 | memset(&safetyInfo, 0, sizeof(safetyInfo)); |
| 3963 | safetyInfo.unsafeColumns = (bool *) |
| 3964 | palloc0((list_length(subquery->targetList) + 1) * sizeof(bool)); |
| 3965 | |
| 3966 | /* |
| 3967 | * If the subquery has the "security_barrier" flag, it means the subquery |
| 3968 | * originated from a view that must enforce row-level security. Then we |
| 3969 | * must not push down quals that contain leaky functions. (Ideally this |
| 3970 | * would be checked inside subquery_is_pushdown_safe, but since we don't |
| 3971 | * currently pass the RTE to that function, we must do it here.) |
| 3972 | */ |
| 3973 | safetyInfo.unsafeLeaky = rte->security_barrier; |
| 3974 | |
| 3975 | if (subquery_is_pushdown_safe(subquery, subquery, &safetyInfo)) |
| 3976 | { |
| 3977 | /* OK to consider pushing down individual quals */ |
| 3978 | List *upperrestrictlist = NIL; |
| 3979 | ListCell *l; |
| 3980 | |
| 3981 | foreach(l, rel->baserestrictinfo) |
| 3982 | { |
| 3983 | RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); |
| 3984 | Node *clause = (Node *) rinfo->clause; |
| 3985 | |
| 3986 | if (!rinfo->pseudoconstant && |
| 3987 | qual_is_pushdown_safe(subquery, rti, rinfo, &safetyInfo)) |
| 3988 | { |
| 3989 | /* Push it down */ |
| 3990 | subquery_push_qual(subquery, rte, rti, clause); |
| 3991 | } |
| 3992 | else |
| 3993 | { |
| 3994 | /* Keep it in the upper query */ |
| 3995 | upperrestrictlist = lappend(upperrestrictlist, rinfo); |
| 3996 | } |
| 3997 | } |
| 3998 | rel->baserestrictinfo = upperrestrictlist; |
| 3999 | /* We don't bother recomputing baserestrict_min_security */ |
| 4000 | } |
| 4001 | |
| 4002 | pfree(safetyInfo.unsafeColumns); |
no test coverage detected