Disallow empty passwords in LDAP authentication, the same way
[PostgreSQL.git] / src / backend / optimizer / util / placeholder.c
blobcf088253f04bbc320771d4e173e7e14fc8168ace
1 /*-------------------------------------------------------------------------
3 * placeholder.c
4 * PlaceHolderVar and PlaceHolderInfo manipulation routines
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * $PostgreSQL$
14 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include "nodes/nodeFuncs.h"
19 #include "optimizer/pathnode.h"
20 #include "optimizer/placeholder.h"
21 #include "optimizer/planmain.h"
22 #include "optimizer/var.h"
23 #include "utils/lsyscache.h"
27 * make_placeholder_expr
28 * Make a PlaceHolderVar for the given expression.
30 * phrels is the syntactic location (as a set of baserels) to attribute
31 * to the expression.
33 PlaceHolderVar *
34 make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
36 PlaceHolderVar *phv = makeNode(PlaceHolderVar);
38 phv->phexpr = expr;
39 phv->phrels = phrels;
40 phv->phid = ++(root->glob->lastPHId);
41 phv->phlevelsup = 0;
43 return phv;
47 * find_placeholder_info
48 * Fetch the PlaceHolderInfo for the given PHV; create it if not found
50 * Note: this should only be called after query_planner() has started.
52 PlaceHolderInfo *
53 find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv)
55 PlaceHolderInfo *phinfo;
56 ListCell *lc;
58 /* if this ever isn't true, we'd need to be able to look in parent lists */
59 Assert(phv->phlevelsup == 0);
61 foreach(lc, root->placeholder_list)
63 phinfo = (PlaceHolderInfo *) lfirst(lc);
64 if (phinfo->phid == phv->phid)
65 return phinfo;
68 /* Not found, so create it */
69 phinfo = makeNode(PlaceHolderInfo);
71 phinfo->phid = phv->phid;
72 phinfo->ph_var = copyObject(phv);
73 phinfo->ph_eval_at = pull_varnos((Node *) phv);
74 /* ph_eval_at may change later, see fix_placeholder_eval_levels */
75 phinfo->ph_needed = NULL; /* initially it's unused */
76 /* for the moment, estimate width using just the datatype info */
77 phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr),
78 exprTypmod((Node *) phv->phexpr));
80 root->placeholder_list = lappend(root->placeholder_list, phinfo);
82 return phinfo;
86 * fix_placeholder_eval_levels
87 * Adjust the target evaluation levels for placeholders
89 * The initial eval_at level set by find_placeholder_info was the set of
90 * rels used in the placeholder's expression (or the whole subselect if
91 * the expr is variable-free). If the subselect contains any outer joins
92 * that can null any of those rels, we must delay evaluation to above those
93 * joins.
95 * In future we might want to put additional policy/heuristics here to
96 * try to determine an optimal evaluation level. The current rules will
97 * result in evaluation at the lowest possible level.
99 void
100 fix_placeholder_eval_levels(PlannerInfo *root)
102 ListCell *lc1;
104 foreach(lc1, root->placeholder_list)
106 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1);
107 Relids syn_level = phinfo->ph_var->phrels;
108 Relids eval_at = phinfo->ph_eval_at;
109 bool found_some;
110 ListCell *lc2;
113 * Check for delays due to lower outer joins. This is the same logic
114 * as in check_outerjoin_delay in initsplan.c, except that we don't
115 * want to modify the delay_upper_joins flags; that was all handled
116 * already during distribute_qual_to_rels.
120 found_some = false;
121 foreach(lc2, root->join_info_list)
123 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc2);
125 /* disregard joins not within the expr's sub-select */
126 if (!bms_is_subset(sjinfo->syn_lefthand, syn_level) ||
127 !bms_is_subset(sjinfo->syn_righthand, syn_level))
128 continue;
130 /* do we reference any nullable rels of this OJ? */
131 if (bms_overlap(eval_at, sjinfo->min_righthand) ||
132 (sjinfo->jointype == JOIN_FULL &&
133 bms_overlap(eval_at, sjinfo->min_lefthand)))
135 /* yes; have we included all its rels in eval_at? */
136 if (!bms_is_subset(sjinfo->min_lefthand, eval_at) ||
137 !bms_is_subset(sjinfo->min_righthand, eval_at))
139 /* no, so add them in */
140 eval_at = bms_add_members(eval_at,
141 sjinfo->min_lefthand);
142 eval_at = bms_add_members(eval_at,
143 sjinfo->min_righthand);
144 /* we'll need another iteration */
145 found_some = true;
149 } while (found_some);
151 phinfo->ph_eval_at = eval_at;
154 * Now that we know where to evaluate the placeholder, make sure that
155 * any vars or placeholders it uses will be available at that join
156 * level. NOTE: this could cause more PlaceHolderInfos to be added to
157 * placeholder_list. That is okay because we'll process them before
158 * falling out of the foreach loop. Also, it could cause the
159 * ph_needed sets of existing list entries to expand, which is also
160 * okay because this loop doesn't examine those.
162 if (bms_membership(eval_at) == BMS_MULTIPLE)
164 List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
165 PVC_INCLUDE_PLACEHOLDERS);
167 add_vars_to_targetlist(root, vars, eval_at);
168 list_free(vars);
173 * Now, if any placeholder can be computed at a base rel and is needed
174 * above it, add it to that rel's targetlist. (This is essentially the
175 * same logic as in add_placeholders_to_joinrel, but we can't do that part
176 * until joinrels are formed.) We have to do this as a separate step
177 * because the ph_needed values aren't stable until the previous loop
178 * finishes.
180 foreach(lc1, root->placeholder_list)
182 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1);
183 Relids eval_at = phinfo->ph_eval_at;
185 if (bms_membership(eval_at) == BMS_SINGLETON)
187 int varno = bms_singleton_member(eval_at);
188 RelOptInfo *rel = find_base_rel(root, varno);
190 if (bms_nonempty_difference(phinfo->ph_needed, rel->relids))
191 rel->reltargetlist = lappend(rel->reltargetlist,
192 copyObject(phinfo->ph_var));
198 * add_placeholders_to_joinrel
199 * Add any required PlaceHolderVars to a join rel's targetlist.
201 * A join rel should emit a PlaceHolderVar if (a) the PHV is needed above
202 * this join level and (b) the PHV can be computed at or below this level.
203 * At this time we do not need to distinguish whether the PHV will be
204 * computed here or copied up from below.
206 void
207 add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel)
209 Relids relids = joinrel->relids;
210 ListCell *lc;
212 foreach(lc, root->placeholder_list)
214 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
216 /* Is it still needed above this joinrel? */
217 if (bms_nonempty_difference(phinfo->ph_needed, relids))
219 /* Is it computable here? */
220 if (bms_is_subset(phinfo->ph_eval_at, relids))
222 /* Yup, add it to the output */
223 joinrel->reltargetlist = lappend(joinrel->reltargetlist,
224 phinfo->ph_var);
225 joinrel->width += phinfo->ph_width;