00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include "nodes/nodeFuncs.h"
00019 #include "optimizer/pathnode.h"
00020 #include "optimizer/placeholder.h"
00021 #include "optimizer/planmain.h"
00022 #include "optimizer/var.h"
00023 #include "utils/lsyscache.h"
00024
00025
00026 static Relids find_placeholders_recurse(PlannerInfo *root, Node *jtnode);
00027 static void mark_placeholders_in_expr(PlannerInfo *root, Node *expr,
00028 Relids relids);
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 PlaceHolderVar *
00039 make_placeholder_expr(PlannerInfo *root, Expr *expr, Relids phrels)
00040 {
00041 PlaceHolderVar *phv = makeNode(PlaceHolderVar);
00042
00043 phv->phexpr = expr;
00044 phv->phrels = phrels;
00045 phv->phid = ++(root->glob->lastPHId);
00046 phv->phlevelsup = 0;
00047
00048 return phv;
00049 }
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 PlaceHolderInfo *
00069 find_placeholder_info(PlannerInfo *root, PlaceHolderVar *phv,
00070 bool create_new_ph)
00071 {
00072 PlaceHolderInfo *phinfo;
00073 ListCell *lc;
00074
00075
00076 Assert(phv->phlevelsup == 0);
00077
00078 foreach(lc, root->placeholder_list)
00079 {
00080 phinfo = (PlaceHolderInfo *) lfirst(lc);
00081 if (phinfo->phid == phv->phid)
00082 return phinfo;
00083 }
00084
00085
00086 if (!create_new_ph)
00087 elog(ERROR, "too late to create a new PlaceHolderInfo");
00088
00089 phinfo = makeNode(PlaceHolderInfo);
00090
00091 phinfo->phid = phv->phid;
00092 phinfo->ph_var = copyObject(phv);
00093 phinfo->ph_eval_at = pull_varnos((Node *) phv);
00094
00095 phinfo->ph_needed = NULL;
00096 phinfo->ph_may_need = NULL;
00097
00098 phinfo->ph_width = get_typavgwidth(exprType((Node *) phv->phexpr),
00099 exprTypmod((Node *) phv->phexpr));
00100
00101 root->placeholder_list = lappend(root->placeholder_list, phinfo);
00102
00103 return phinfo;
00104 }
00105
00106
00107
00108
00109
00110
00111
00112
00113 void
00114 find_placeholders_in_jointree(PlannerInfo *root)
00115 {
00116
00117 if (root->glob->lastPHId != 0)
00118 {
00119
00120 Assert(root->parse->jointree != NULL &&
00121 IsA(root->parse->jointree, FromExpr));
00122 (void) find_placeholders_recurse(root, (Node *) root->parse->jointree);
00123 }
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135 static Relids
00136 find_placeholders_recurse(PlannerInfo *root, Node *jtnode)
00137 {
00138 Relids jtrelids;
00139
00140 if (jtnode == NULL)
00141 return NULL;
00142 if (IsA(jtnode, RangeTblRef))
00143 {
00144 int varno = ((RangeTblRef *) jtnode)->rtindex;
00145
00146
00147 jtrelids = bms_make_singleton(varno);
00148 }
00149 else if (IsA(jtnode, FromExpr))
00150 {
00151 FromExpr *f = (FromExpr *) jtnode;
00152 ListCell *l;
00153
00154
00155
00156
00157 jtrelids = NULL;
00158 foreach(l, f->fromlist)
00159 {
00160 Relids sub_relids;
00161
00162 sub_relids = find_placeholders_recurse(root, lfirst(l));
00163 jtrelids = bms_join(jtrelids, sub_relids);
00164 }
00165
00166
00167
00168
00169 mark_placeholders_in_expr(root, f->quals, jtrelids);
00170 }
00171 else if (IsA(jtnode, JoinExpr))
00172 {
00173 JoinExpr *j = (JoinExpr *) jtnode;
00174 Relids leftids,
00175 rightids;
00176
00177
00178
00179
00180 leftids = find_placeholders_recurse(root, j->larg);
00181 rightids = find_placeholders_recurse(root, j->rarg);
00182 jtrelids = bms_join(leftids, rightids);
00183
00184
00185 mark_placeholders_in_expr(root, j->quals, jtrelids);
00186 }
00187 else
00188 {
00189 elog(ERROR, "unrecognized node type: %d",
00190 (int) nodeTag(jtnode));
00191 jtrelids = NULL;
00192 }
00193 return jtrelids;
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 static void
00205 mark_placeholders_in_expr(PlannerInfo *root, Node *expr, Relids relids)
00206 {
00207 List *vars;
00208 ListCell *vl;
00209
00210
00211
00212
00213
00214 vars = pull_var_clause(expr,
00215 PVC_RECURSE_AGGREGATES,
00216 PVC_INCLUDE_PLACEHOLDERS);
00217 foreach(vl, vars)
00218 {
00219 PlaceHolderVar *phv = (PlaceHolderVar *) lfirst(vl);
00220 PlaceHolderInfo *phinfo;
00221
00222
00223 if (!IsA(phv, PlaceHolderVar))
00224 continue;
00225
00226
00227 phinfo = find_placeholder_info(root, phv, true);
00228
00229
00230 mark_placeholder_maybe_needed(root, phinfo, relids);
00231 }
00232 list_free(vars);
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 void
00250 mark_placeholder_maybe_needed(PlannerInfo *root, PlaceHolderInfo *phinfo,
00251 Relids relids)
00252 {
00253 Relids est_eval_level;
00254
00255
00256 phinfo->ph_may_need = bms_add_members(phinfo->ph_may_need, relids);
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 est_eval_level = bms_union(phinfo->ph_var->phrels, phinfo->ph_eval_at);
00269
00270
00271 mark_placeholders_in_expr(root, (Node *) phinfo->ph_var->phexpr,
00272 est_eval_level);
00273
00274 bms_free(est_eval_level);
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 void
00302 update_placeholder_eval_levels(PlannerInfo *root, SpecialJoinInfo *new_sjinfo)
00303 {
00304 ListCell *lc1;
00305
00306 foreach(lc1, root->placeholder_list)
00307 {
00308 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc1);
00309 Relids syn_level = phinfo->ph_var->phrels;
00310 Relids eval_at;
00311 bool found_some;
00312 ListCell *lc2;
00313
00314
00315
00316
00317
00318 if (!bms_is_subset(new_sjinfo->syn_lefthand, syn_level) ||
00319 !bms_is_subset(new_sjinfo->syn_righthand, syn_level))
00320 continue;
00321
00322
00323
00324
00325
00326
00327
00328
00329 eval_at = phinfo->ph_eval_at;
00330
00331 do
00332 {
00333 found_some = false;
00334 foreach(lc2, root->join_info_list)
00335 {
00336 SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc2);
00337
00338
00339 if (!bms_is_subset(sjinfo->syn_lefthand, syn_level) ||
00340 !bms_is_subset(sjinfo->syn_righthand, syn_level))
00341 continue;
00342
00343
00344 if (bms_overlap(eval_at, sjinfo->min_righthand) ||
00345 (sjinfo->jointype == JOIN_FULL &&
00346 bms_overlap(eval_at, sjinfo->min_lefthand)))
00347 {
00348
00349 if (!bms_is_subset(sjinfo->min_lefthand, eval_at) ||
00350 !bms_is_subset(sjinfo->min_righthand, eval_at))
00351 {
00352
00353 eval_at = bms_add_members(eval_at,
00354 sjinfo->min_lefthand);
00355 eval_at = bms_add_members(eval_at,
00356 sjinfo->min_righthand);
00357
00358 found_some = true;
00359 }
00360 }
00361 }
00362 } while (found_some);
00363
00364 phinfo->ph_eval_at = eval_at;
00365 }
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 void
00381 fix_placeholder_input_needed_levels(PlannerInfo *root)
00382 {
00383 ListCell *lc;
00384
00385 foreach(lc, root->placeholder_list)
00386 {
00387 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
00388 Relids eval_at = phinfo->ph_eval_at;
00389
00390
00391 if (bms_membership(eval_at) == BMS_MULTIPLE)
00392 {
00393 List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
00394 PVC_RECURSE_AGGREGATES,
00395 PVC_INCLUDE_PLACEHOLDERS);
00396
00397 add_vars_to_targetlist(root, vars, eval_at, false);
00398 list_free(vars);
00399 }
00400 }
00401 }
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 void
00415 add_placeholders_to_base_rels(PlannerInfo *root)
00416 {
00417 ListCell *lc;
00418
00419 foreach(lc, root->placeholder_list)
00420 {
00421 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
00422 Relids eval_at = phinfo->ph_eval_at;
00423
00424 if (bms_membership(eval_at) == BMS_SINGLETON &&
00425 bms_nonempty_difference(phinfo->ph_needed, eval_at))
00426 {
00427 int varno = bms_singleton_member(eval_at);
00428 RelOptInfo *rel = find_base_rel(root, varno);
00429
00430 rel->reltargetlist = lappend(rel->reltargetlist,
00431 copyObject(phinfo->ph_var));
00432 }
00433 }
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 void
00446 add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel)
00447 {
00448 Relids relids = joinrel->relids;
00449 ListCell *lc;
00450
00451 foreach(lc, root->placeholder_list)
00452 {
00453 PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc);
00454
00455
00456 if (bms_nonempty_difference(phinfo->ph_needed, relids))
00457 {
00458
00459 if (bms_is_subset(phinfo->ph_eval_at, relids))
00460 {
00461
00462 joinrel->reltargetlist = lappend(joinrel->reltargetlist,
00463 phinfo->ph_var);
00464 joinrel->width += phinfo->ph_width;
00465 }
00466 }
00467 }
00468 }