~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/optimizer/plan/setrefs.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * setrefs.c
 
4
 *        Post-processing of a completed plan tree: fix references to subplan
 
5
 *        vars, and compute regproc values for operators
 
6
 *
 
7
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 *
 
11
 * IDENTIFICATION
 
12
 *        $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.105 2004-12-31 22:00:09 pgsql Exp $
 
13
 *
 
14
 *-------------------------------------------------------------------------
 
15
 */
 
16
#include "postgres.h"
 
17
 
 
18
#include "nodes/makefuncs.h"
 
19
#include "optimizer/clauses.h"
 
20
#include "optimizer/planmain.h"
 
21
#include "optimizer/tlist.h"
 
22
#include "optimizer/var.h"
 
23
#include "parser/parsetree.h"
 
24
#include "utils/lsyscache.h"
 
25
 
 
26
 
 
27
typedef struct
 
28
{
 
29
        List       *rtable;
 
30
        List       *outer_tlist;
 
31
        List       *inner_tlist;
 
32
        Index           acceptable_rel;
 
33
        bool            tlists_have_non_vars;
 
34
} join_references_context;
 
35
 
 
36
typedef struct
 
37
{
 
38
        Index           subvarno;
 
39
        List       *subplan_targetlist;
 
40
        bool            tlist_has_non_vars;
 
41
} replace_vars_with_subplan_refs_context;
 
42
 
 
43
static void fix_expr_references(Plan *plan, Node *node);
 
44
static bool fix_expr_references_walker(Node *node, void *context);
 
45
static void set_join_references(Join *join, List *rtable);
 
46
static void set_uppernode_references(Plan *plan, Index subvarno);
 
47
static bool targetlist_has_non_vars(List *tlist);
 
48
static List *join_references(List *clauses,
 
49
                                List *rtable,
 
50
                                List *outer_tlist,
 
51
                                List *inner_tlist,
 
52
                                Index acceptable_rel,
 
53
                                bool tlists_have_non_vars);
 
54
static Node *join_references_mutator(Node *node,
 
55
                                                join_references_context *context);
 
56
static Node *replace_vars_with_subplan_refs(Node *node,
 
57
                                                           Index subvarno,
 
58
                                                           List *subplan_targetlist,
 
59
                                                           bool tlist_has_non_vars);
 
60
static Node *replace_vars_with_subplan_refs_mutator(Node *node,
 
61
                                                replace_vars_with_subplan_refs_context *context);
 
62
static bool fix_opfuncids_walker(Node *node, void *context);
 
63
static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
 
64
 
 
65
 
 
66
/*****************************************************************************
 
67
 *
 
68
 *              SUBPLAN REFERENCES
 
69
 *
 
70
 *****************************************************************************/
 
71
 
 
72
/*
 
73
 * set_plan_references
 
74
 *        This is the final processing pass of the planner/optimizer.  The plan
 
75
 *        tree is complete; we just have to adjust some representational details
 
76
 *        for the convenience of the executor.  We update Vars in upper plan nodes
 
77
 *        to refer to the outputs of their subplans, and we compute regproc OIDs
 
78
 *        for operators (ie, we look up the function that implements each op).
 
79
 *
 
80
 *        set_plan_references recursively traverses the whole plan tree.
 
81
 *
 
82
 * Returns nothing of interest, but modifies internal fields of nodes.
 
83
 */
 
84
void
 
85
set_plan_references(Plan *plan, List *rtable)
 
86
{
 
87
        ListCell   *l;
 
88
 
 
89
        if (plan == NULL)
 
90
                return;
 
91
 
 
92
        /*
 
93
         * Plan-type-specific fixes
 
94
         */
 
95
        switch (nodeTag(plan))
 
96
        {
 
97
                case T_SeqScan:
 
98
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
99
                        fix_expr_references(plan, (Node *) plan->qual);
 
100
                        break;
 
101
                case T_IndexScan:
 
102
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
103
                        fix_expr_references(plan, (Node *) plan->qual);
 
104
                        fix_expr_references(plan,
 
105
                                                                (Node *) ((IndexScan *) plan)->indxqual);
 
106
                        fix_expr_references(plan,
 
107
                                                        (Node *) ((IndexScan *) plan)->indxqualorig);
 
108
                        break;
 
109
                case T_TidScan:
 
110
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
111
                        fix_expr_references(plan, (Node *) plan->qual);
 
112
                        fix_expr_references(plan,
 
113
                                                                (Node *) ((TidScan *) plan)->tideval);
 
114
                        break;
 
115
                case T_SubqueryScan:
 
116
                        {
 
117
                                RangeTblEntry *rte;
 
118
 
 
119
                                /*
 
120
                                 * We do not do set_uppernode_references() here, because a
 
121
                                 * SubqueryScan will always have been created with correct
 
122
                                 * references to its subplan's outputs to begin with.
 
123
                                 */
 
124
                                fix_expr_references(plan, (Node *) plan->targetlist);
 
125
                                fix_expr_references(plan, (Node *) plan->qual);
 
126
 
 
127
                                /* Recurse into subplan too */
 
128
                                rte = rt_fetch(((SubqueryScan *) plan)->scan.scanrelid,
 
129
                                                           rtable);
 
130
                                Assert(rte->rtekind == RTE_SUBQUERY);
 
131
                                set_plan_references(((SubqueryScan *) plan)->subplan,
 
132
                                                                        rte->subquery->rtable);
 
133
                        }
 
134
                        break;
 
135
                case T_FunctionScan:
 
136
                        {
 
137
                                RangeTblEntry *rte;
 
138
 
 
139
                                fix_expr_references(plan, (Node *) plan->targetlist);
 
140
                                fix_expr_references(plan, (Node *) plan->qual);
 
141
                                rte = rt_fetch(((FunctionScan *) plan)->scan.scanrelid,
 
142
                                                           rtable);
 
143
                                Assert(rte->rtekind == RTE_FUNCTION);
 
144
                                fix_expr_references(plan, rte->funcexpr);
 
145
                        }
 
146
                        break;
 
147
                case T_NestLoop:
 
148
                        set_join_references((Join *) plan, rtable);
 
149
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
150
                        fix_expr_references(plan, (Node *) plan->qual);
 
151
                        fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
 
152
                        break;
 
153
                case T_MergeJoin:
 
154
                        set_join_references((Join *) plan, rtable);
 
155
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
156
                        fix_expr_references(plan, (Node *) plan->qual);
 
157
                        fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
 
158
                        fix_expr_references(plan,
 
159
                                                        (Node *) ((MergeJoin *) plan)->mergeclauses);
 
160
                        break;
 
161
                case T_HashJoin:
 
162
                        set_join_references((Join *) plan, rtable);
 
163
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
164
                        fix_expr_references(plan, (Node *) plan->qual);
 
165
                        fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual);
 
166
                        fix_expr_references(plan,
 
167
                                                          (Node *) ((HashJoin *) plan)->hashclauses);
 
168
                        break;
 
169
                case T_Hash:
 
170
                case T_Material:
 
171
                case T_Sort:
 
172
                case T_Unique:
 
173
                case T_SetOp:
 
174
 
 
175
                        /*
 
176
                         * These plan types don't actually bother to evaluate their
 
177
                         * targetlists or quals (because they just return their
 
178
                         * unmodified input tuples).  The optimizer is lazy about
 
179
                         * creating really valid targetlists for them.  Best to just
 
180
                         * leave the targetlist alone.  In particular, we do not want
 
181
                         * to process subplans for them, since we will likely end up
 
182
                         * reprocessing subplans that also appear in lower levels of
 
183
                         * the plan tree!
 
184
                         */
 
185
                        break;
 
186
                case T_Limit:
 
187
 
 
188
                        /*
 
189
                         * Like the plan types above, Limit doesn't evaluate its tlist
 
190
                         * or quals.  It does have live expressions for limit/offset,
 
191
                         * however.
 
192
                         */
 
193
                        fix_expr_references(plan, ((Limit *) plan)->limitOffset);
 
194
                        fix_expr_references(plan, ((Limit *) plan)->limitCount);
 
195
                        break;
 
196
                case T_Agg:
 
197
                case T_Group:
 
198
                        set_uppernode_references(plan, (Index) 0);
 
199
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
200
                        fix_expr_references(plan, (Node *) plan->qual);
 
201
                        break;
 
202
                case T_Result:
 
203
 
 
204
                        /*
 
205
                         * Result may or may not have a subplan; no need to fix up
 
206
                         * subplan references if it hasn't got one...
 
207
                         *
 
208
                         * XXX why does Result use a different subvarno from Agg/Group?
 
209
                         */
 
210
                        if (plan->lefttree != NULL)
 
211
                                set_uppernode_references(plan, (Index) OUTER);
 
212
                        fix_expr_references(plan, (Node *) plan->targetlist);
 
213
                        fix_expr_references(plan, (Node *) plan->qual);
 
214
                        fix_expr_references(plan, ((Result *) plan)->resconstantqual);
 
215
                        break;
 
216
                case T_Append:
 
217
 
 
218
                        /*
 
219
                         * Append, like Sort et al, doesn't actually evaluate its
 
220
                         * targetlist or quals, and we haven't bothered to give it its
 
221
                         * own tlist copy. So, don't fix targetlist/qual. But do
 
222
                         * recurse into child plans.
 
223
                         */
 
224
                        foreach(l, ((Append *) plan)->appendplans)
 
225
                                set_plan_references((Plan *) lfirst(l), rtable);
 
226
                        break;
 
227
                default:
 
228
                        elog(ERROR, "unrecognized node type: %d",
 
229
                                 (int) nodeTag(plan));
 
230
                        break;
 
231
        }
 
232
 
 
233
        /*
 
234
         * Now recurse into child plans and initplans, if any
 
235
         *
 
236
         * NOTE: it is essential that we recurse into child plans AFTER we set
 
237
         * subplan references in this plan's tlist and quals.  If we did the
 
238
         * reference-adjustments bottom-up, then we would fail to match this
 
239
         * plan's var nodes against the already-modified nodes of the
 
240
         * children.  Fortunately, that consideration doesn't apply to SubPlan
 
241
         * nodes; else we'd need two passes over the expression trees.
 
242
         */
 
243
        set_plan_references(plan->lefttree, rtable);
 
244
        set_plan_references(plan->righttree, rtable);
 
245
 
 
246
        foreach(l, plan->initPlan)
 
247
        {
 
248
                SubPlan    *sp = (SubPlan *) lfirst(l);
 
249
 
 
250
                Assert(IsA(sp, SubPlan));
 
251
                set_plan_references(sp->plan, sp->rtable);
 
252
        }
 
253
}
 
254
 
 
255
/*
 
256
 * fix_expr_references
 
257
 *        Do final cleanup on expressions (targetlists or quals).
 
258
 *
 
259
 * This consists of looking up operator opcode info for OpExpr nodes
 
260
 * and recursively performing set_plan_references on subplans.
 
261
 *
 
262
 * The Plan argument is currently unused, but might be needed again someday.
 
263
 */
 
264
static void
 
265
fix_expr_references(Plan *plan, Node *node)
 
266
{
 
267
        /* This tree walk requires no special setup, so away we go... */
 
268
        fix_expr_references_walker(node, NULL);
 
269
}
 
270
 
 
271
static bool
 
272
fix_expr_references_walker(Node *node, void *context)
 
273
{
 
274
        if (node == NULL)
 
275
                return false;
 
276
        if (IsA(node, OpExpr))
 
277
                set_opfuncid((OpExpr *) node);
 
278
        else if (IsA(node, DistinctExpr))
 
279
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
 
280
        else if (IsA(node, ScalarArrayOpExpr))
 
281
                set_sa_opfuncid((ScalarArrayOpExpr *) node);
 
282
        else if (IsA(node, NullIfExpr))
 
283
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
 
284
        else if (IsA(node, SubPlan))
 
285
        {
 
286
                SubPlan    *sp = (SubPlan *) node;
 
287
 
 
288
                set_plan_references(sp->plan, sp->rtable);
 
289
        }
 
290
        return expression_tree_walker(node, fix_expr_references_walker, context);
 
291
}
 
292
 
 
293
/*
 
294
 * set_join_references
 
295
 *        Modifies the target list and quals of a join node to reference its
 
296
 *        subplans, by setting the varnos to OUTER or INNER and setting attno
 
297
 *        values to the result domain number of either the corresponding outer
 
298
 *        or inner join tuple item.
 
299
 *
 
300
 * In the case of a nestloop with inner indexscan, we will also need to
 
301
 * apply the same transformation to any outer vars appearing in the
 
302
 * quals of the child indexscan.
 
303
 *
 
304
 *      'join' is a join plan node
 
305
 *      'rtable' is the associated range table
 
306
 */
 
307
static void
 
308
set_join_references(Join *join, List *rtable)
 
309
{
 
310
        Plan       *outer_plan = join->plan.lefttree;
 
311
        Plan       *inner_plan = join->plan.righttree;
 
312
        List       *outer_tlist = outer_plan->targetlist;
 
313
        List       *inner_tlist = inner_plan->targetlist;
 
314
        bool            tlists_have_non_vars;
 
315
 
 
316
        tlists_have_non_vars = targetlist_has_non_vars(outer_tlist) ||
 
317
                targetlist_has_non_vars(inner_tlist);
 
318
 
 
319
        /* All join plans have tlist, qual, and joinqual */
 
320
        join->plan.targetlist = join_references(join->plan.targetlist,
 
321
                                                                                        rtable,
 
322
                                                                                        outer_tlist,
 
323
                                                                                        inner_tlist,
 
324
                                                                                        (Index) 0,
 
325
                                                                                        tlists_have_non_vars);
 
326
        join->plan.qual = join_references(join->plan.qual,
 
327
                                                                          rtable,
 
328
                                                                          outer_tlist,
 
329
                                                                          inner_tlist,
 
330
                                                                          (Index) 0,
 
331
                                                                          tlists_have_non_vars);
 
332
        join->joinqual = join_references(join->joinqual,
 
333
                                                                         rtable,
 
334
                                                                         outer_tlist,
 
335
                                                                         inner_tlist,
 
336
                                                                         (Index) 0,
 
337
                                                                         tlists_have_non_vars);
 
338
 
 
339
        /* Now do join-type-specific stuff */
 
340
        if (IsA(join, NestLoop))
 
341
        {
 
342
                if (IsA(inner_plan, IndexScan))
 
343
                {
 
344
                        /*
 
345
                         * An index is being used to reduce the number of tuples
 
346
                         * scanned in the inner relation.  If there are join clauses
 
347
                         * being used with the index, we must update their outer-rel
 
348
                         * var nodes to refer to the outer side of the join.
 
349
                         */
 
350
                        IndexScan  *innerscan = (IndexScan *) inner_plan;
 
351
                        List       *indxqualorig = innerscan->indxqualorig;
 
352
 
 
353
                        /* No work needed if indxqual refers only to its own rel... */
 
354
                        if (NumRelids((Node *) indxqualorig) > 1)
 
355
                        {
 
356
                                Index           innerrel = innerscan->scan.scanrelid;
 
357
 
 
358
                                /* only refs to outer vars get changed in the inner qual */
 
359
                                innerscan->indxqualorig = join_references(indxqualorig,
 
360
                                                                                                                  rtable,
 
361
                                                                                                                  outer_tlist,
 
362
                                                                                                                  NIL,
 
363
                                                                                                                  innerrel,
 
364
                                                                                                   tlists_have_non_vars);
 
365
                                innerscan->indxqual = join_references(innerscan->indxqual,
 
366
                                                                                                          rtable,
 
367
                                                                                                          outer_tlist,
 
368
                                                                                                          NIL,
 
369
                                                                                                          innerrel,
 
370
                                                                                                   tlists_have_non_vars);
 
371
 
 
372
                                /*
 
373
                                 * We must fix the inner qpqual too, if it has join
 
374
                                 * clauses (this could happen if special operators are
 
375
                                 * involved: some indxquals may get rechecked as qpquals).
 
376
                                 */
 
377
                                if (NumRelids((Node *) inner_plan->qual) > 1)
 
378
                                        inner_plan->qual = join_references(inner_plan->qual,
 
379
                                                                                                           rtable,
 
380
                                                                                                           outer_tlist,
 
381
                                                                                                           NIL,
 
382
                                                                                                           innerrel,
 
383
                                                                                                   tlists_have_non_vars);
 
384
                        }
 
385
                }
 
386
                else if (IsA(inner_plan, TidScan))
 
387
                {
 
388
                        TidScan    *innerscan = (TidScan *) inner_plan;
 
389
                        Index           innerrel = innerscan->scan.scanrelid;
 
390
 
 
391
                        innerscan->tideval = join_references(innerscan->tideval,
 
392
                                                                                                 rtable,
 
393
                                                                                                 outer_tlist,
 
394
                                                                                                 NIL,
 
395
                                                                                                 innerrel,
 
396
                                                                                                 tlists_have_non_vars);
 
397
                }
 
398
        }
 
399
        else if (IsA(join, MergeJoin))
 
400
        {
 
401
                MergeJoin  *mj = (MergeJoin *) join;
 
402
 
 
403
                mj->mergeclauses = join_references(mj->mergeclauses,
 
404
                                                                                   rtable,
 
405
                                                                                   outer_tlist,
 
406
                                                                                   inner_tlist,
 
407
                                                                                   (Index) 0,
 
408
                                                                                   tlists_have_non_vars);
 
409
        }
 
410
        else if (IsA(join, HashJoin))
 
411
        {
 
412
                HashJoin   *hj = (HashJoin *) join;
 
413
 
 
414
                hj->hashclauses = join_references(hj->hashclauses,
 
415
                                                                                  rtable,
 
416
                                                                                  outer_tlist,
 
417
                                                                                  inner_tlist,
 
418
                                                                                  (Index) 0,
 
419
                                                                                  tlists_have_non_vars);
 
420
        }
 
421
}
 
422
 
 
423
/*
 
424
 * set_uppernode_references
 
425
 *        Update the targetlist and quals of an upper-level plan node
 
426
 *        to refer to the tuples returned by its lefttree subplan.
 
427
 *
 
428
 * This is used for single-input plan types like Agg, Group, Result.
 
429
 *
 
430
 * In most cases, we have to match up individual Vars in the tlist and
 
431
 * qual expressions with elements of the subplan's tlist (which was
 
432
 * generated by flatten_tlist() from these selfsame expressions, so it
 
433
 * should have all the required variables).  There is an important exception,
 
434
 * however: GROUP BY and ORDER BY expressions will have been pushed into the
 
435
 * subplan tlist unflattened.  If these values are also needed in the output
 
436
 * then we want to reference the subplan tlist element rather than recomputing
 
437
 * the expression.
 
438
 */
 
439
static void
 
440
set_uppernode_references(Plan *plan, Index subvarno)
 
441
{
 
442
        Plan       *subplan = plan->lefttree;
 
443
        List       *subplan_targetlist,
 
444
                           *output_targetlist;
 
445
        ListCell   *l;
 
446
        bool            tlist_has_non_vars;
 
447
 
 
448
        if (subplan != NULL)
 
449
                subplan_targetlist = subplan->targetlist;
 
450
        else
 
451
                subplan_targetlist = NIL;
 
452
 
 
453
        tlist_has_non_vars = targetlist_has_non_vars(subplan_targetlist);
 
454
 
 
455
        output_targetlist = NIL;
 
456
        foreach(l, plan->targetlist)
 
457
        {
 
458
                TargetEntry *tle = (TargetEntry *) lfirst(l);
 
459
                Node       *newexpr;
 
460
 
 
461
                newexpr = replace_vars_with_subplan_refs((Node *) tle->expr,
 
462
                                                                                                 subvarno,
 
463
                                                                                                 subplan_targetlist,
 
464
                                                                                                 tlist_has_non_vars);
 
465
                output_targetlist = lappend(output_targetlist,
 
466
                                                                        makeTargetEntry(tle->resdom,
 
467
                                                                                                        (Expr *) newexpr));
 
468
        }
 
469
        plan->targetlist = output_targetlist;
 
470
 
 
471
        plan->qual = (List *)
 
472
                replace_vars_with_subplan_refs((Node *) plan->qual,
 
473
                                                                           subvarno,
 
474
                                                                           subplan_targetlist,
 
475
                                                                           tlist_has_non_vars);
 
476
}
 
477
 
 
478
/*
 
479
 * targetlist_has_non_vars --- are there any non-Var entries in tlist?
 
480
 *
 
481
 * In most cases, subplan tlists will be "flat" tlists with only Vars.
 
482
 * Checking for this allows us to save comparisons in common cases.
 
483
 */
 
484
static bool
 
485
targetlist_has_non_vars(List *tlist)
 
486
{
 
487
        ListCell   *l;
 
488
 
 
489
        foreach(l, tlist)
 
490
        {
 
491
                TargetEntry *tle = (TargetEntry *) lfirst(l);
 
492
 
 
493
                if (tle->expr && !IsA(tle->expr, Var))
 
494
                        return true;
 
495
        }
 
496
        return false;
 
497
}
 
498
 
 
499
/*
 
500
 * join_references
 
501
 *         Creates a new set of targetlist entries or join qual clauses by
 
502
 *         changing the varno/varattno values of variables in the clauses
 
503
 *         to reference target list values from the outer and inner join
 
504
 *         relation target lists.
 
505
 *
 
506
 * This is used in two different scenarios: a normal join clause, where
 
507
 * all the Vars in the clause *must* be replaced by OUTER or INNER references;
 
508
 * and an indexscan being used on the inner side of a nestloop join.
 
509
 * In the latter case we want to replace the outer-relation Vars by OUTER
 
510
 * references, but not touch the Vars of the inner relation.
 
511
 *
 
512
 * For a normal join, acceptable_rel should be zero so that any failure to
 
513
 * match a Var will be reported as an error.  For the indexscan case,
 
514
 * pass inner_tlist = NIL and acceptable_rel = the ID of the inner relation.
 
515
 *
 
516
 * 'clauses' is the targetlist or list of join clauses
 
517
 * 'rtable' is the current range table
 
518
 * 'outer_tlist' is the target list of the outer join relation
 
519
 * 'inner_tlist' is the target list of the inner join relation, or NIL
 
520
 * 'acceptable_rel' is either zero or the rangetable index of a relation
 
521
 *              whose Vars may appear in the clause without provoking an error.
 
522
 *
 
523
 * Returns the new expression tree.  The original clause structure is
 
524
 * not modified.
 
525
 */
 
526
static List *
 
527
join_references(List *clauses,
 
528
                                List *rtable,
 
529
                                List *outer_tlist,
 
530
                                List *inner_tlist,
 
531
                                Index acceptable_rel,
 
532
                                bool tlists_have_non_vars)
 
533
{
 
534
        join_references_context context;
 
535
 
 
536
        context.rtable = rtable;
 
537
        context.outer_tlist = outer_tlist;
 
538
        context.inner_tlist = inner_tlist;
 
539
        context.acceptable_rel = acceptable_rel;
 
540
        context.tlists_have_non_vars = tlists_have_non_vars;
 
541
        return (List *) join_references_mutator((Node *) clauses, &context);
 
542
}
 
543
 
 
544
static Node *
 
545
join_references_mutator(Node *node,
 
546
                                                join_references_context *context)
 
547
{
 
548
        if (node == NULL)
 
549
                return NULL;
 
550
        if (IsA(node, Var))
 
551
        {
 
552
                Var                *var = (Var *) node;
 
553
                Resdom     *resdom;
 
554
 
 
555
                /* First look for the var in the input tlists */
 
556
                resdom = tlist_member((Node *) var, context->outer_tlist);
 
557
                if (resdom)
 
558
                {
 
559
                        Var                *newvar = (Var *) copyObject(var);
 
560
 
 
561
                        newvar->varno = OUTER;
 
562
                        newvar->varattno = resdom->resno;
 
563
                        return (Node *) newvar;
 
564
                }
 
565
                resdom = tlist_member((Node *) var, context->inner_tlist);
 
566
                if (resdom)
 
567
                {
 
568
                        Var                *newvar = (Var *) copyObject(var);
 
569
 
 
570
                        newvar->varno = INNER;
 
571
                        newvar->varattno = resdom->resno;
 
572
                        return (Node *) newvar;
 
573
                }
 
574
 
 
575
                /* Return the Var unmodified, if it's for acceptable_rel */
 
576
                if (var->varno == context->acceptable_rel)
 
577
                        return (Node *) copyObject(var);
 
578
 
 
579
                /* No referent found for Var */
 
580
                elog(ERROR, "variable not found in subplan target lists");
 
581
        }
 
582
        /* Try matching more complex expressions too, if tlists have any */
 
583
        if (context->tlists_have_non_vars)
 
584
        {
 
585
                Resdom     *resdom;
 
586
 
 
587
                resdom = tlist_member(node, context->outer_tlist);
 
588
                if (resdom)
 
589
                {
 
590
                        /* Found a matching subplan output expression */
 
591
                        Var                *newvar;
 
592
 
 
593
                        newvar = makeVar(OUTER,
 
594
                                                         resdom->resno,
 
595
                                                         resdom->restype,
 
596
                                                         resdom->restypmod,
 
597
                                                         0);
 
598
                        newvar->varnoold = 0;           /* wasn't ever a plain Var */
 
599
                        newvar->varoattno = 0;
 
600
                        return (Node *) newvar;
 
601
                }
 
602
                resdom = tlist_member(node, context->inner_tlist);
 
603
                if (resdom)
 
604
                {
 
605
                        /* Found a matching subplan output expression */
 
606
                        Var                *newvar;
 
607
 
 
608
                        newvar = makeVar(INNER,
 
609
                                                         resdom->resno,
 
610
                                                         resdom->restype,
 
611
                                                         resdom->restypmod,
 
612
                                                         0);
 
613
                        newvar->varnoold = 0;           /* wasn't ever a plain Var */
 
614
                        newvar->varoattno = 0;
 
615
                        return (Node *) newvar;
 
616
                }
 
617
        }
 
618
        return expression_tree_mutator(node,
 
619
                                                                   join_references_mutator,
 
620
                                                                   (void *) context);
 
621
}
 
622
 
 
623
/*
 
624
 * replace_vars_with_subplan_refs
 
625
 *              This routine modifies an expression tree so that all Var nodes
 
626
 *              reference target nodes of a subplan.  It is used to fix up
 
627
 *              target and qual expressions of non-join upper-level plan nodes.
 
628
 *
 
629
 * An error is raised if no matching var can be found in the subplan tlist
 
630
 * --- so this routine should only be applied to nodes whose subplans'
 
631
 * targetlists were generated via flatten_tlist() or some such method.
 
632
 *
 
633
 * If tlist_has_non_vars is true, then we try to match whole subexpressions
 
634
 * against elements of the subplan tlist, so that we can avoid recomputing
 
635
 * expressions that were already computed by the subplan.  (This is relatively
 
636
 * expensive, so we don't want to try it in the common case where the
 
637
 * subplan tlist is just a flattened list of Vars.)
 
638
 *
 
639
 * 'node': the tree to be fixed (a target item or qual)
 
640
 * 'subvarno': varno to be assigned to all Vars
 
641
 * 'subplan_targetlist': target list for subplan
 
642
 * 'tlist_has_non_vars': true if subplan_targetlist contains non-Var exprs
 
643
 *
 
644
 * The resulting tree is a copy of the original in which all Var nodes have
 
645
 * varno = subvarno, varattno = resno of corresponding subplan target.
 
646
 * The original tree is not modified.
 
647
 */
 
648
static Node *
 
649
replace_vars_with_subplan_refs(Node *node,
 
650
                                                           Index subvarno,
 
651
                                                           List *subplan_targetlist,
 
652
                                                           bool tlist_has_non_vars)
 
653
{
 
654
        replace_vars_with_subplan_refs_context context;
 
655
 
 
656
        context.subvarno = subvarno;
 
657
        context.subplan_targetlist = subplan_targetlist;
 
658
        context.tlist_has_non_vars = tlist_has_non_vars;
 
659
        return replace_vars_with_subplan_refs_mutator(node, &context);
 
660
}
 
661
 
 
662
static Node *
 
663
replace_vars_with_subplan_refs_mutator(Node *node,
 
664
                                                 replace_vars_with_subplan_refs_context *context)
 
665
{
 
666
        if (node == NULL)
 
667
                return NULL;
 
668
        if (IsA(node, Var))
 
669
        {
 
670
                Var                *var = (Var *) node;
 
671
                Resdom     *resdom;
 
672
                Var                *newvar;
 
673
 
 
674
                resdom = tlist_member((Node *) var, context->subplan_targetlist);
 
675
                if (!resdom)
 
676
                        elog(ERROR, "variable not found in subplan target list");
 
677
                newvar = (Var *) copyObject(var);
 
678
                newvar->varno = context->subvarno;
 
679
                newvar->varattno = resdom->resno;
 
680
                return (Node *) newvar;
 
681
        }
 
682
        /* Try matching more complex expressions too, if tlist has any */
 
683
        if (context->tlist_has_non_vars)
 
684
        {
 
685
                Resdom     *resdom;
 
686
 
 
687
                resdom = tlist_member(node, context->subplan_targetlist);
 
688
                if (resdom)
 
689
                {
 
690
                        /* Found a matching subplan output expression */
 
691
                        Var                *newvar;
 
692
 
 
693
                        newvar = makeVar(context->subvarno,
 
694
                                                         resdom->resno,
 
695
                                                         resdom->restype,
 
696
                                                         resdom->restypmod,
 
697
                                                         0);
 
698
                        newvar->varnoold = 0;           /* wasn't ever a plain Var */
 
699
                        newvar->varoattno = 0;
 
700
                        return (Node *) newvar;
 
701
                }
 
702
        }
 
703
        return expression_tree_mutator(node,
 
704
                                                                   replace_vars_with_subplan_refs_mutator,
 
705
                                                                   (void *) context);
 
706
}
 
707
 
 
708
/*****************************************************************************
 
709
 *                                      OPERATOR REGPROC LOOKUP
 
710
 *****************************************************************************/
 
711
 
 
712
/*
 
713
 * fix_opfuncids
 
714
 *        Calculate opfuncid field from opno for each OpExpr node in given tree.
 
715
 *        The given tree can be anything expression_tree_walker handles.
 
716
 *
 
717
 * The argument is modified in-place.  (This is OK since we'd want the
 
718
 * same change for any node, even if it gets visited more than once due to
 
719
 * shared structure.)
 
720
 */
 
721
void
 
722
fix_opfuncids(Node *node)
 
723
{
 
724
        /* This tree walk requires no special setup, so away we go... */
 
725
        fix_opfuncids_walker(node, NULL);
 
726
}
 
727
 
 
728
static bool
 
729
fix_opfuncids_walker(Node *node, void *context)
 
730
{
 
731
        if (node == NULL)
 
732
                return false;
 
733
        if (IsA(node, OpExpr))
 
734
                set_opfuncid((OpExpr *) node);
 
735
        else if (IsA(node, DistinctExpr))
 
736
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
 
737
        else if (IsA(node, ScalarArrayOpExpr))
 
738
                set_sa_opfuncid((ScalarArrayOpExpr *) node);
 
739
        else if (IsA(node, NullIfExpr))
 
740
                set_opfuncid((OpExpr *) node);  /* rely on struct equivalence */
 
741
        return expression_tree_walker(node, fix_opfuncids_walker, context);
 
742
}
 
743
 
 
744
/*
 
745
 * set_opfuncid
 
746
 *              Set the opfuncid (procedure OID) in an OpExpr node,
 
747
 *              if it hasn't been set already.
 
748
 *
 
749
 * Because of struct equivalence, this can also be used for
 
750
 * DistinctExpr and NullIfExpr nodes.
 
751
 */
 
752
void
 
753
set_opfuncid(OpExpr *opexpr)
 
754
{
 
755
        if (opexpr->opfuncid == InvalidOid)
 
756
                opexpr->opfuncid = get_opcode(opexpr->opno);
 
757
}
 
758
 
 
759
/*
 
760
 * set_sa_opfuncid
 
761
 *              As above, for ScalarArrayOpExpr nodes.
 
762
 */
 
763
static void
 
764
set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
 
765
{
 
766
        if (opexpr->opfuncid == InvalidOid)
 
767
                opexpr->opfuncid = get_opcode(opexpr->opno);
 
768
}