~ubuntu-branches/ubuntu/hardy/postgresql-8.4/hardy-backports

« back to all changes in this revision

Viewing changes to src/backend/optimizer/util/var.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * var.c
 
4
 *        Var node manipulation routines
 
5
 *
 
6
 * Note: for most purposes, PlaceHolderVar is considered a Var too,
 
7
 * even if its contained expression is variable-free.  Also, CurrentOfExpr
 
8
 * is treated as a Var for purposes of determining whether an expression
 
9
 * contains variables.
 
10
 *
 
11
 *
 
12
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
13
 * Portions Copyright (c) 1994, Regents of the University of California
 
14
 *
 
15
 *
 
16
 * IDENTIFICATION
 
17
 *        $PostgreSQL$
 
18
 *
 
19
 *-------------------------------------------------------------------------
 
20
 */
 
21
#include "postgres.h"
 
22
 
 
23
#include "access/sysattr.h"
 
24
#include "nodes/nodeFuncs.h"
 
25
#include "optimizer/prep.h"
 
26
#include "optimizer/var.h"
 
27
#include "parser/parsetree.h"
 
28
#include "rewrite/rewriteManip.h"
 
29
 
 
30
 
 
31
typedef struct
 
32
{
 
33
        Relids          varnos;
 
34
        int                     sublevels_up;
 
35
} pull_varnos_context;
 
36
 
 
37
typedef struct
 
38
{
 
39
        int                     var_location;
 
40
        int                     sublevels_up;
 
41
} locate_var_of_level_context;
 
42
 
 
43
typedef struct
 
44
{
 
45
        int                     var_location;
 
46
        int                     relid;
 
47
        int                     sublevels_up;
 
48
} locate_var_of_relation_context;
 
49
 
 
50
typedef struct
 
51
{
 
52
        int                     min_varlevel;
 
53
        int                     sublevels_up;
 
54
} find_minimum_var_level_context;
 
55
 
 
56
typedef struct
 
57
{
 
58
        List       *varlist;
 
59
        bool            includePlaceHolderVars;
 
60
} pull_var_clause_context;
 
61
 
 
62
typedef struct
 
63
{
 
64
        PlannerInfo *root;
 
65
        int                     sublevels_up;
 
66
} flatten_join_alias_vars_context;
 
67
 
 
68
static bool pull_varnos_walker(Node *node,
 
69
                                   pull_varnos_context *context);
 
70
static bool pull_varattnos_walker(Node *node, Bitmapset **varattnos);
 
71
static bool contain_var_clause_walker(Node *node, void *context);
 
72
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
 
73
static bool locate_var_of_level_walker(Node *node,
 
74
                                                                           locate_var_of_level_context *context);
 
75
static bool locate_var_of_relation_walker(Node *node,
 
76
                                                                        locate_var_of_relation_context *context);
 
77
static bool find_minimum_var_level_walker(Node *node,
 
78
                                                          find_minimum_var_level_context *context);
 
79
static bool pull_var_clause_walker(Node *node,
 
80
                                           pull_var_clause_context *context);
 
81
static Node *flatten_join_alias_vars_mutator(Node *node,
 
82
                                                                flatten_join_alias_vars_context *context);
 
83
static Relids alias_relid_set(PlannerInfo *root, Relids relids);
 
84
 
 
85
 
 
86
/*
 
87
 * pull_varnos
 
88
 *              Create a set of all the distinct varnos present in a parsetree.
 
89
 *              Only varnos that reference level-zero rtable entries are considered.
 
90
 *
 
91
 * NOTE: this is used on not-yet-planned expressions.  It may therefore find
 
92
 * bare SubLinks, and if so it needs to recurse into them to look for uplevel
 
93
 * references to the desired rtable level!      But when we find a completed
 
94
 * SubPlan, we only need to look at the parameters passed to the subplan.
 
95
 */
 
96
Relids
 
97
pull_varnos(Node *node)
 
98
{
 
99
        pull_varnos_context context;
 
100
 
 
101
        context.varnos = NULL;
 
102
        context.sublevels_up = 0;
 
103
 
 
104
        /*
 
105
         * Must be prepared to start with a Query or a bare expression tree; if
 
106
         * it's a Query, we don't want to increment sublevels_up.
 
107
         */
 
108
        query_or_expression_tree_walker(node,
 
109
                                                                        pull_varnos_walker,
 
110
                                                                        (void *) &context,
 
111
                                                                        0);
 
112
 
 
113
        return context.varnos;
 
114
}
 
115
 
 
116
static bool
 
117
pull_varnos_walker(Node *node, pull_varnos_context *context)
 
118
{
 
119
        if (node == NULL)
 
120
                return false;
 
121
        if (IsA(node, Var))
 
122
        {
 
123
                Var                *var = (Var *) node;
 
124
 
 
125
                if (var->varlevelsup == context->sublevels_up)
 
126
                        context->varnos = bms_add_member(context->varnos, var->varno);
 
127
                return false;
 
128
        }
 
129
        if (IsA(node, CurrentOfExpr))
 
130
        {
 
131
                CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
 
132
 
 
133
                if (context->sublevels_up == 0)
 
134
                        context->varnos = bms_add_member(context->varnos, cexpr->cvarno);
 
135
                return false;
 
136
        }
 
137
        if (IsA(node, PlaceHolderVar))
 
138
        {
 
139
                /*
 
140
                 * Normally, we can just take the varnos in the contained expression.
 
141
                 * But if it is variable-free, use the PHV's syntactic relids.
 
142
                 */
 
143
                PlaceHolderVar *phv = (PlaceHolderVar *) node;
 
144
                pull_varnos_context subcontext;
 
145
 
 
146
                subcontext.varnos = NULL;
 
147
                subcontext.sublevels_up = context->sublevels_up;
 
148
                (void) pull_varnos_walker((Node *) phv->phexpr, &subcontext);
 
149
 
 
150
                if (bms_is_empty(subcontext.varnos) &&
 
151
                        phv->phlevelsup == context->sublevels_up)
 
152
                        context->varnos = bms_add_members(context->varnos, phv->phrels);
 
153
                else
 
154
                        context->varnos = bms_join(context->varnos, subcontext.varnos);
 
155
                return false;
 
156
        }
 
157
        if (IsA(node, Query))
 
158
        {
 
159
                /* Recurse into RTE subquery or not-yet-planned sublink subquery */
 
160
                bool            result;
 
161
 
 
162
                context->sublevels_up++;
 
163
                result = query_tree_walker((Query *) node, pull_varnos_walker,
 
164
                                                                   (void *) context, 0);
 
165
                context->sublevels_up--;
 
166
                return result;
 
167
        }
 
168
        return expression_tree_walker(node, pull_varnos_walker,
 
169
                                                                  (void *) context);
 
170
}
 
171
 
 
172
 
 
173
/*
 
174
 * pull_varattnos
 
175
 *              Find all the distinct attribute numbers present in an expression tree,
 
176
 *              and add them to the initial contents of *varattnos.
 
177
 *              Only Vars that reference RTE 1 of rtable level zero are considered.
 
178
 *
 
179
 * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
 
180
 * we can include system attributes (e.g., OID) in the bitmap representation.
 
181
 *
 
182
 * Currently, this does not support subqueries nor expressions containing
 
183
 * references to multiple tables; not needed since it's only applied to
 
184
 * index expressions and predicates.
 
185
 */
 
186
void
 
187
pull_varattnos(Node *node, Bitmapset **varattnos)
 
188
{
 
189
        (void) pull_varattnos_walker(node, varattnos);
 
190
}
 
191
 
 
192
static bool
 
193
pull_varattnos_walker(Node *node, Bitmapset **varattnos)
 
194
{
 
195
        if (node == NULL)
 
196
                return false;
 
197
        if (IsA(node, Var))
 
198
        {
 
199
                Var                *var = (Var *) node;
 
200
 
 
201
                Assert(var->varno == 1);
 
202
                *varattnos = bms_add_member(*varattnos,
 
203
                                                 var->varattno - FirstLowInvalidHeapAttributeNumber);
 
204
                return false;
 
205
        }
 
206
        /* Should not find a subquery or subplan */
 
207
        Assert(!IsA(node, Query));
 
208
        Assert(!IsA(node, SubPlan));
 
209
 
 
210
        return expression_tree_walker(node, pull_varattnos_walker,
 
211
                                                                  (void *) varattnos);
 
212
}
 
213
 
 
214
 
 
215
/*
 
216
 * contain_var_clause
 
217
 *        Recursively scan a clause to discover whether it contains any Var nodes
 
218
 *        (of the current query level).
 
219
 *
 
220
 *        Returns true if any varnode found.
 
221
 *
 
222
 * Does not examine subqueries, therefore must only be used after reduction
 
223
 * of sublinks to subplans!
 
224
 */
 
225
bool
 
226
contain_var_clause(Node *node)
 
227
{
 
228
        return contain_var_clause_walker(node, NULL);
 
229
}
 
230
 
 
231
static bool
 
232
contain_var_clause_walker(Node *node, void *context)
 
233
{
 
234
        if (node == NULL)
 
235
                return false;
 
236
        if (IsA(node, Var))
 
237
        {
 
238
                if (((Var *) node)->varlevelsup == 0)
 
239
                        return true;            /* abort the tree traversal and return true */
 
240
                return false;
 
241
        }
 
242
        if (IsA(node, CurrentOfExpr))
 
243
                return true;
 
244
        if (IsA(node, PlaceHolderVar))
 
245
        {
 
246
                if (((PlaceHolderVar *) node)->phlevelsup == 0)
 
247
                        return true;            /* abort the tree traversal and return true */
 
248
                /* else fall through to check the contained expr */
 
249
        }
 
250
        return expression_tree_walker(node, contain_var_clause_walker, context);
 
251
}
 
252
 
 
253
 
 
254
/*
 
255
 * contain_vars_of_level
 
256
 *        Recursively scan a clause to discover whether it contains any Var nodes
 
257
 *        of the specified query level.
 
258
 *
 
259
 *        Returns true if any such Var found.
 
260
 *
 
261
 * Will recurse into sublinks.  Also, may be invoked directly on a Query.
 
262
 */
 
263
bool
 
264
contain_vars_of_level(Node *node, int levelsup)
 
265
{
 
266
        int                     sublevels_up = levelsup;
 
267
 
 
268
        return query_or_expression_tree_walker(node,
 
269
                                                                                   contain_vars_of_level_walker,
 
270
                                                                                   (void *) &sublevels_up,
 
271
                                                                                   0);
 
272
}
 
273
 
 
274
static bool
 
275
contain_vars_of_level_walker(Node *node, int *sublevels_up)
 
276
{
 
277
        if (node == NULL)
 
278
                return false;
 
279
        if (IsA(node, Var))
 
280
        {
 
281
                if (((Var *) node)->varlevelsup == *sublevels_up)
 
282
                        return true;            /* abort tree traversal and return true */
 
283
                return false;
 
284
        }
 
285
        if (IsA(node, CurrentOfExpr))
 
286
        {
 
287
                if (*sublevels_up == 0)
 
288
                        return true;
 
289
                return false;
 
290
        }
 
291
        if (IsA(node, PlaceHolderVar))
 
292
        {
 
293
                if (((PlaceHolderVar *) node)->phlevelsup == *sublevels_up)
 
294
                        return true;            /* abort the tree traversal and return true */
 
295
                /* else fall through to check the contained expr */
 
296
        }
 
297
        if (IsA(node, Query))
 
298
        {
 
299
                /* Recurse into subselects */
 
300
                bool            result;
 
301
 
 
302
                (*sublevels_up)++;
 
303
                result = query_tree_walker((Query *) node,
 
304
                                                                   contain_vars_of_level_walker,
 
305
                                                                   (void *) sublevels_up,
 
306
                                                                   0);
 
307
                (*sublevels_up)--;
 
308
                return result;
 
309
        }
 
310
        return expression_tree_walker(node,
 
311
                                                                  contain_vars_of_level_walker,
 
312
                                                                  (void *) sublevels_up);
 
313
}
 
314
 
 
315
 
 
316
/*
 
317
 * locate_var_of_level
 
318
 *        Find the parse location of any Var of the specified query level.
 
319
 *
 
320
 * Returns -1 if no such Var is in the querytree, or if they all have
 
321
 * unknown parse location.  (The former case is probably caller error,
 
322
 * but we don't bother to distinguish it from the latter case.)
 
323
 *
 
324
 * Will recurse into sublinks.  Also, may be invoked directly on a Query.
 
325
 *
 
326
 * Note: it might seem appropriate to merge this functionality into
 
327
 * contain_vars_of_level, but that would complicate that function's API.
 
328
 * Currently, the only uses of this function are for error reporting,
 
329
 * and so shaving cycles probably isn't very important.
 
330
 */
 
331
int
 
332
locate_var_of_level(Node *node, int levelsup)
 
333
{
 
334
        locate_var_of_level_context context;
 
335
 
 
336
        context.var_location = -1;              /* in case we find nothing */
 
337
        context.sublevels_up = levelsup;
 
338
 
 
339
        (void) query_or_expression_tree_walker(node,
 
340
                                                                                   locate_var_of_level_walker,
 
341
                                                                                   (void *) &context,
 
342
                                                                                   0);
 
343
 
 
344
        return context.var_location;
 
345
}
 
346
 
 
347
static bool
 
348
locate_var_of_level_walker(Node *node,
 
349
                                                   locate_var_of_level_context *context)
 
350
{
 
351
        if (node == NULL)
 
352
                return false;
 
353
        if (IsA(node, Var))
 
354
        {
 
355
                Var        *var = (Var *) node;
 
356
 
 
357
                if (var->varlevelsup == context->sublevels_up &&
 
358
                        var->location >= 0)
 
359
                {
 
360
                        context->var_location = var->location;
 
361
                        return true;            /* abort tree traversal and return true */
 
362
                }
 
363
                return false;
 
364
        }
 
365
        if (IsA(node, CurrentOfExpr))
 
366
        {
 
367
                /* since CurrentOfExpr doesn't carry location, nothing we can do */
 
368
                return false;
 
369
        }
 
370
        /* No extra code needed for PlaceHolderVar; just look in contained expr */
 
371
        if (IsA(node, Query))
 
372
        {
 
373
                /* Recurse into subselects */
 
374
                bool            result;
 
375
 
 
376
                context->sublevels_up++;
 
377
                result = query_tree_walker((Query *) node,
 
378
                                                                   locate_var_of_level_walker,
 
379
                                                                   (void *) context,
 
380
                                                                   0);
 
381
                context->sublevels_up--;
 
382
                return result;
 
383
        }
 
384
        return expression_tree_walker(node,
 
385
                                                                  locate_var_of_level_walker,
 
386
                                                                  (void *) context);
 
387
}
 
388
 
 
389
 
 
390
/*
 
391
 * locate_var_of_relation
 
392
 *        Find the parse location of any Var of the specified relation.
 
393
 *
 
394
 * Returns -1 if no such Var is in the querytree, or if they all have
 
395
 * unknown parse location.
 
396
 *
 
397
 * Will recurse into sublinks.  Also, may be invoked directly on a Query.
 
398
 */
 
399
int
 
400
locate_var_of_relation(Node *node, int relid, int levelsup)
 
401
{
 
402
        locate_var_of_relation_context context;
 
403
 
 
404
        context.var_location = -1;              /* in case we find nothing */
 
405
        context.relid = relid;
 
406
        context.sublevels_up = levelsup;
 
407
 
 
408
        (void) query_or_expression_tree_walker(node,
 
409
                                                                                   locate_var_of_relation_walker,
 
410
                                                                                   (void *) &context,
 
411
                                                                                   0);
 
412
 
 
413
        return context.var_location;
 
414
}
 
415
 
 
416
static bool
 
417
locate_var_of_relation_walker(Node *node,
 
418
                                                          locate_var_of_relation_context *context)
 
419
{
 
420
        if (node == NULL)
 
421
                return false;
 
422
        if (IsA(node, Var))
 
423
        {
 
424
                Var        *var = (Var *) node;
 
425
 
 
426
                if (var->varno == context->relid &&
 
427
                        var->varlevelsup == context->sublevels_up &&
 
428
                        var->location >= 0)
 
429
                {
 
430
                        context->var_location = var->location;
 
431
                        return true;            /* abort tree traversal and return true */
 
432
                }
 
433
                return false;
 
434
        }
 
435
        if (IsA(node, CurrentOfExpr))
 
436
        {
 
437
                /* since CurrentOfExpr doesn't carry location, nothing we can do */
 
438
                return false;
 
439
        }
 
440
        /* No extra code needed for PlaceHolderVar; just look in contained expr */
 
441
        if (IsA(node, Query))
 
442
        {
 
443
                /* Recurse into subselects */
 
444
                bool            result;
 
445
 
 
446
                context->sublevels_up++;
 
447
                result = query_tree_walker((Query *) node,
 
448
                                                                   locate_var_of_relation_walker,
 
449
                                                                   (void *) context,
 
450
                                                                   0);
 
451
                context->sublevels_up--;
 
452
                return result;
 
453
        }
 
454
        return expression_tree_walker(node,
 
455
                                                                  locate_var_of_relation_walker,
 
456
                                                                  (void *) context);
 
457
}
 
458
 
 
459
 
 
460
/*
 
461
 * find_minimum_var_level
 
462
 *        Recursively scan a clause to find the lowest variable level it
 
463
 *        contains --- for example, zero is returned if there are any local
 
464
 *        variables, one if there are no local variables but there are
 
465
 *        one-level-up outer references, etc.  Subqueries are scanned to see
 
466
 *        if they possess relevant outer references.  (But any local variables
 
467
 *        within subqueries are not relevant.)
 
468
 *
 
469
 *        -1 is returned if the clause has no variables at all.
 
470
 *
 
471
 * Will recurse into sublinks.  Also, may be invoked directly on a Query.
 
472
 */
 
473
int
 
474
find_minimum_var_level(Node *node)
 
475
{
 
476
        find_minimum_var_level_context context;
 
477
 
 
478
        context.min_varlevel = -1;      /* signifies nothing found yet */
 
479
        context.sublevels_up = 0;
 
480
 
 
481
        (void) query_or_expression_tree_walker(node,
 
482
                                                                                   find_minimum_var_level_walker,
 
483
                                                                                   (void *) &context,
 
484
                                                                                   0);
 
485
 
 
486
        return context.min_varlevel;
 
487
}
 
488
 
 
489
static bool
 
490
find_minimum_var_level_walker(Node *node,
 
491
                                                          find_minimum_var_level_context *context)
 
492
{
 
493
        if (node == NULL)
 
494
                return false;
 
495
        if (IsA(node, Var))
 
496
        {
 
497
                int                     varlevelsup = ((Var *) node)->varlevelsup;
 
498
 
 
499
                /* convert levelsup to frame of reference of original query */
 
500
                varlevelsup -= context->sublevels_up;
 
501
                /* ignore local vars of subqueries */
 
502
                if (varlevelsup >= 0)
 
503
                {
 
504
                        if (context->min_varlevel < 0 ||
 
505
                                context->min_varlevel > varlevelsup)
 
506
                        {
 
507
                                context->min_varlevel = varlevelsup;
 
508
 
 
509
                                /*
 
510
                                 * As soon as we find a local variable, we can abort the tree
 
511
                                 * traversal, since min_varlevel is then certainly 0.
 
512
                                 */
 
513
                                if (varlevelsup == 0)
 
514
                                        return true;
 
515
                        }
 
516
                }
 
517
        }
 
518
        if (IsA(node, CurrentOfExpr))
 
519
        {
 
520
                int                     varlevelsup = 0;
 
521
 
 
522
                /* convert levelsup to frame of reference of original query */
 
523
                varlevelsup -= context->sublevels_up;
 
524
                /* ignore local vars of subqueries */
 
525
                if (varlevelsup >= 0)
 
526
                {
 
527
                        if (context->min_varlevel < 0 ||
 
528
                                context->min_varlevel > varlevelsup)
 
529
                        {
 
530
                                context->min_varlevel = varlevelsup;
 
531
 
 
532
                                /*
 
533
                                 * As soon as we find a local variable, we can abort the tree
 
534
                                 * traversal, since min_varlevel is then certainly 0.
 
535
                                 */
 
536
                                if (varlevelsup == 0)
 
537
                                        return true;
 
538
                        }
 
539
                }
 
540
        }
 
541
 
 
542
        /*
 
543
         * An Aggref must be treated like a Var of its level.  Normally we'd get
 
544
         * the same result from looking at the Vars in the aggregate's argument,
 
545
         * but this fails in the case of a Var-less aggregate call (COUNT(*)).
 
546
         */
 
547
        if (IsA(node, Aggref))
 
548
        {
 
549
                int                     agglevelsup = ((Aggref *) node)->agglevelsup;
 
550
 
 
551
                /* convert levelsup to frame of reference of original query */
 
552
                agglevelsup -= context->sublevels_up;
 
553
                /* ignore local aggs of subqueries */
 
554
                if (agglevelsup >= 0)
 
555
                {
 
556
                        if (context->min_varlevel < 0 ||
 
557
                                context->min_varlevel > agglevelsup)
 
558
                        {
 
559
                                context->min_varlevel = agglevelsup;
 
560
 
 
561
                                /*
 
562
                                 * As soon as we find a local aggregate, we can abort the tree
 
563
                                 * traversal, since min_varlevel is then certainly 0.
 
564
                                 */
 
565
                                if (agglevelsup == 0)
 
566
                                        return true;
 
567
                        }
 
568
                }
 
569
        }
 
570
        /* Likewise, make sure PlaceHolderVar is treated correctly */
 
571
        if (IsA(node, PlaceHolderVar))
 
572
        {
 
573
                int                     phlevelsup = ((PlaceHolderVar *) node)->phlevelsup;
 
574
 
 
575
                /* convert levelsup to frame of reference of original query */
 
576
                phlevelsup -= context->sublevels_up;
 
577
                /* ignore local vars of subqueries */
 
578
                if (phlevelsup >= 0)
 
579
                {
 
580
                        if (context->min_varlevel < 0 ||
 
581
                                context->min_varlevel > phlevelsup)
 
582
                        {
 
583
                                context->min_varlevel = phlevelsup;
 
584
 
 
585
                                /*
 
586
                                 * As soon as we find a local variable, we can abort the tree
 
587
                                 * traversal, since min_varlevel is then certainly 0.
 
588
                                 */
 
589
                                if (phlevelsup == 0)
 
590
                                        return true;
 
591
                        }
 
592
                }
 
593
        }
 
594
        if (IsA(node, Query))
 
595
        {
 
596
                /* Recurse into subselects */
 
597
                bool            result;
 
598
 
 
599
                context->sublevels_up++;
 
600
                result = query_tree_walker((Query *) node,
 
601
                                                                   find_minimum_var_level_walker,
 
602
                                                                   (void *) context,
 
603
                                                                   0);
 
604
                context->sublevels_up--;
 
605
                return result;
 
606
        }
 
607
        return expression_tree_walker(node,
 
608
                                                                  find_minimum_var_level_walker,
 
609
                                                                  (void *) context);
 
610
}
 
611
 
 
612
 
 
613
/*
 
614
 * pull_var_clause
 
615
 *        Recursively pulls all Var nodes from an expression clause.
 
616
 *
 
617
 *        PlaceHolderVars are included too, if includePlaceHolderVars is true.
 
618
 *        If it isn't true, an error is thrown if any are found.
 
619
 *        Note that Vars within a PHV's expression are *not* included.
 
620
 *
 
621
 *        CurrentOfExpr nodes are *not* included.
 
622
 *
 
623
 *        Upper-level vars (with varlevelsup > 0) are not included.
 
624
 *        (These probably represent errors too, but we don't complain.)
 
625
 *
 
626
 *        Returns list of nodes found.  Note the nodes themselves are not
 
627
 *        copied, only referenced.
 
628
 *
 
629
 * Does not examine subqueries, therefore must only be used after reduction
 
630
 * of sublinks to subplans!
 
631
 */
 
632
List *
 
633
pull_var_clause(Node *node, bool includePlaceHolderVars)
 
634
{
 
635
        pull_var_clause_context context;
 
636
 
 
637
        context.varlist = NIL;
 
638
        context.includePlaceHolderVars = includePlaceHolderVars;
 
639
 
 
640
        pull_var_clause_walker(node, &context);
 
641
        return context.varlist;
 
642
}
 
643
 
 
644
static bool
 
645
pull_var_clause_walker(Node *node, pull_var_clause_context *context)
 
646
{
 
647
        if (node == NULL)
 
648
                return false;
 
649
        if (IsA(node, Var))
 
650
        {
 
651
                if (((Var *) node)->varlevelsup == 0)
 
652
                        context->varlist = lappend(context->varlist, node);
 
653
                return false;
 
654
        }
 
655
        if (IsA(node, PlaceHolderVar))
 
656
        {
 
657
                if (!context->includePlaceHolderVars)
 
658
                        elog(ERROR, "PlaceHolderVar found where not expected");
 
659
                if (((PlaceHolderVar *) node)->phlevelsup == 0)
 
660
                        context->varlist = lappend(context->varlist, node);
 
661
                /* we do NOT descend into the contained expression */
 
662
                return false;
 
663
        }
 
664
        return expression_tree_walker(node, pull_var_clause_walker,
 
665
                                                                  (void *) context);
 
666
}
 
667
 
 
668
 
 
669
/*
 
670
 * flatten_join_alias_vars
 
671
 *        Replace Vars that reference JOIN outputs with references to the original
 
672
 *        relation variables instead.  This allows quals involving such vars to be
 
673
 *        pushed down.  Whole-row Vars that reference JOIN relations are expanded
 
674
 *        into RowExpr constructs that name the individual output Vars.  This
 
675
 *        is necessary since we will not scan the JOIN as a base relation, which
 
676
 *        is the only way that the executor can directly handle whole-row Vars.
 
677
 *
 
678
 * This also adjusts relid sets found in some expression node types to
 
679
 * substitute the contained base rels for any join relid.
 
680
 *
 
681
 * NOTE: this is used on not-yet-planned expressions.  We do not expect it
 
682
 * to be applied directly to a Query node.
 
683
 */
 
684
Node *
 
685
flatten_join_alias_vars(PlannerInfo *root, Node *node)
 
686
{
 
687
        flatten_join_alias_vars_context context;
 
688
 
 
689
        context.root = root;
 
690
        context.sublevels_up = 0;
 
691
 
 
692
        return flatten_join_alias_vars_mutator(node, &context);
 
693
}
 
694
 
 
695
static Node *
 
696
flatten_join_alias_vars_mutator(Node *node,
 
697
                                                                flatten_join_alias_vars_context *context)
 
698
{
 
699
        if (node == NULL)
 
700
                return NULL;
 
701
        if (IsA(node, Var))
 
702
        {
 
703
                Var                *var = (Var *) node;
 
704
                RangeTblEntry *rte;
 
705
                Node       *newvar;
 
706
 
 
707
                /* No change unless Var belongs to a JOIN of the target level */
 
708
                if (var->varlevelsup != context->sublevels_up)
 
709
                        return node;            /* no need to copy, really */
 
710
                rte = rt_fetch(var->varno, context->root->parse->rtable);
 
711
                if (rte->rtekind != RTE_JOIN)
 
712
                        return node;
 
713
                if (var->varattno == InvalidAttrNumber)
 
714
                {
 
715
                        /* Must expand whole-row reference */
 
716
                        RowExpr    *rowexpr;
 
717
                        List       *fields = NIL;
 
718
                        AttrNumber      attnum;
 
719
                        ListCell   *l;
 
720
 
 
721
                        attnum = 0;
 
722
                        foreach(l, rte->joinaliasvars)
 
723
                        {
 
724
                                newvar = (Node *) lfirst(l);
 
725
                                attnum++;
 
726
                                /* Ignore dropped columns */
 
727
                                if (IsA(newvar, Const))
 
728
                                        continue;
 
729
 
 
730
                                /*
 
731
                                 * If we are expanding an alias carried down from an upper
 
732
                                 * query, must adjust its varlevelsup fields.
 
733
                                 */
 
734
                                if (context->sublevels_up != 0)
 
735
                                {
 
736
                                        newvar = copyObject(newvar);
 
737
                                        IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
 
738
                                }
 
739
                                /* Recurse in case join input is itself a join */
 
740
                                newvar = flatten_join_alias_vars_mutator(newvar, context);
 
741
                                fields = lappend(fields, newvar);
 
742
                        }
 
743
                        rowexpr = makeNode(RowExpr);
 
744
                        rowexpr->args = fields;
 
745
                        rowexpr->row_typeid = var->vartype;
 
746
                        rowexpr->row_format = COERCE_IMPLICIT_CAST;
 
747
                        rowexpr->colnames = NIL;
 
748
                        rowexpr->location = -1;
 
749
 
 
750
                        return (Node *) rowexpr;
 
751
                }
 
752
 
 
753
                /* Expand join alias reference */
 
754
                Assert(var->varattno > 0);
 
755
                newvar = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
 
756
 
 
757
                /*
 
758
                 * If we are expanding an alias carried down from an upper query, must
 
759
                 * adjust its varlevelsup fields.
 
760
                 */
 
761
                if (context->sublevels_up != 0)
 
762
                {
 
763
                        newvar = copyObject(newvar);
 
764
                        IncrementVarSublevelsUp(newvar, context->sublevels_up, 0);
 
765
                }
 
766
                /* Recurse in case join input is itself a join */
 
767
                return flatten_join_alias_vars_mutator(newvar, context);
 
768
        }
 
769
        if (IsA(node, PlaceHolderVar))
 
770
        {
 
771
                /* Copy the PlaceHolderVar node with correct mutation of subnodes */
 
772
                PlaceHolderVar *phv;
 
773
 
 
774
                phv = (PlaceHolderVar *) expression_tree_mutator(node,
 
775
                                                                                         flatten_join_alias_vars_mutator,
 
776
                                                                                                                 (void *) context);
 
777
                /* now fix PlaceHolderVar's relid sets */
 
778
                if (phv->phlevelsup == context->sublevels_up)
 
779
                {
 
780
                        phv->phrels = alias_relid_set(context->root,
 
781
                                                                                  phv->phrels);
 
782
                }
 
783
                return (Node *) phv;
 
784
        }
 
785
 
 
786
        if (IsA(node, Query))
 
787
        {
 
788
                /* Recurse into RTE subquery or not-yet-planned sublink subquery */
 
789
                Query      *newnode;
 
790
 
 
791
                context->sublevels_up++;
 
792
                newnode = query_tree_mutator((Query *) node,
 
793
                                                                         flatten_join_alias_vars_mutator,
 
794
                                                                         (void *) context,
 
795
                                                                         QTW_IGNORE_JOINALIASES);
 
796
                context->sublevels_up--;
 
797
                return (Node *) newnode;
 
798
        }
 
799
        /* Already-planned tree not supported */
 
800
        Assert(!IsA(node, SubPlan));
 
801
        /* Shouldn't need to handle these planner auxiliary nodes here */
 
802
        Assert(!IsA(node, SpecialJoinInfo));
 
803
        Assert(!IsA(node, PlaceHolderInfo));
 
804
 
 
805
        return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
 
806
                                                                   (void *) context);
 
807
}
 
808
 
 
809
/*
 
810
 * alias_relid_set: in a set of RT indexes, replace joins by their
 
811
 * underlying base relids
 
812
 */
 
813
static Relids
 
814
alias_relid_set(PlannerInfo *root, Relids relids)
 
815
{
 
816
        Relids          result = NULL;
 
817
        Relids          tmprelids;
 
818
        int                     rtindex;
 
819
 
 
820
        tmprelids = bms_copy(relids);
 
821
        while ((rtindex = bms_first_member(tmprelids)) >= 0)
 
822
        {
 
823
                RangeTblEntry *rte = rt_fetch(rtindex, root->parse->rtable);
 
824
 
 
825
                if (rte->rtekind == RTE_JOIN)
 
826
                        result = bms_join(result, get_relids_for_join(root, rtindex));
 
827
                else
 
828
                        result = bms_add_member(result, rtindex);
 
829
        }
 
830
        bms_free(tmprelids);
 
831
        return result;
 
832
}