88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.67 2005/06/05 22:32:56 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.68 2005/06/06 04:13:36 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
2525
2626static RelOptInfo * make_reloptinfo (PlannerInfo * root ,int relid ,
2727RelOptKind reloptkind );
28- static void build_joinrel_tlist (PlannerInfo * root ,RelOptInfo * joinrel );
28+ static void build_joinrel_tlist (PlannerInfo * root ,RelOptInfo * joinrel ,
29+ RelOptInfo * input_rel );
2930static List * build_joinrel_restrictlist (PlannerInfo * root ,
3031RelOptInfo * joinrel ,
3132RelOptInfo * outer_rel ,
@@ -43,78 +44,60 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
4344/*
4445 * build_base_rel
4546 * Construct a new base relation RelOptInfo, and put it in the query's
46- *base_rel_list .
47+ *base_rel_array .
4748 */
4849void
4950build_base_rel (PlannerInfo * root ,int relid )
5051{
51- ListCell * l ;
52- RelOptInfo * rel ;
52+ Assert (relid > 0 );
5353
5454/* Rel should not exist already */
55- foreach (l ,root -> base_rel_list )
56- {
57- rel = (RelOptInfo * )lfirst (l );
58- if (relid == rel -> relid )
59- elog (ERROR ,"rel already exists" );
60- }
61-
62- /* It should not exist as an "other" rel, either */
63- foreach (l ,root -> other_rel_list )
64- {
65- rel = (RelOptInfo * )lfirst (l );
66- if (relid == rel -> relid )
67- elog (ERROR ,"rel already exists as \"other\" rel" );
68- }
55+ if (relid < root -> base_rel_array_size &&
56+ root -> base_rel_array [relid ]!= NULL )
57+ elog (ERROR ,"rel already exists" );
6958
7059/* No existing RelOptInfo for this base rel, so make a new one */
71- rel = make_reloptinfo (root ,relid ,RELOPT_BASEREL );
72-
73- /* and add it to the list */
74- root -> base_rel_list = lcons (rel ,root -> base_rel_list );
60+ (void )make_reloptinfo (root ,relid ,RELOPT_BASEREL );
7561}
7662
7763/*
7864 * build_other_rel
7965 * Returns relation entry corresponding to 'relid', creating a new one
8066 * if necessary. This is for 'other' relations, which are much like
81- * base relations except that theylive in a differentlist .
67+ * base relations except that theyhave a differentRelOptKind .
8268 */
8369RelOptInfo *
8470build_other_rel (PlannerInfo * root ,int relid )
8571{
86- ListCell * l ;
8772RelOptInfo * rel ;
8873
74+ Assert (relid > 0 );
75+
8976/* Already made? */
90- foreach ( l , root -> other_rel_list )
77+ if ( relid < root -> base_rel_array_size )
9178{
92- rel = (RelOptInfo * )lfirst (l );
93- if (relid == rel -> relid )
79+ rel = root -> base_rel_array [relid ];
80+ if (rel )
81+ {
82+ /* it should not exist as a base rel */
83+ if (rel -> reloptkind == RELOPT_BASEREL )
84+ elog (ERROR ,"rel already exists as base rel" );
85+ /* otherwise, A-OK */
9486return rel ;
95- }
96-
97- /* It should not exist as a base rel */
98- foreach (l ,root -> base_rel_list )
99- {
100- rel = (RelOptInfo * )lfirst (l );
101- if (relid == rel -> relid )
102- elog (ERROR ,"rel already exists as base rel" );
87+ }
10388}
10489
10590/* No existing RelOptInfo for this other rel, so make a new one */
10691/* presently, must be an inheritance child rel */
10792rel = make_reloptinfo (root ,relid ,RELOPT_OTHER_CHILD_REL );
10893
109- /* and add it to the list */
110- root -> other_rel_list = lcons (rel ,root -> other_rel_list );
111-
11294return rel ;
11395}
11496
11597/*
11698 * make_reloptinfo
117- * Construct a RelOptInfo for the specified rangetable index.
99+ * Construct a RelOptInfo for the specified rangetable index,
100+ * and enter it into base_rel_array.
118101 *
119102 * Common code for build_base_rel and build_other_rel.
120103 */
@@ -172,31 +155,40 @@ make_reloptinfo(PlannerInfo *root, int relid, RelOptKind reloptkind)
172155break ;
173156}
174157
158+ /* Add the finished struct to the base_rel_array */
159+ if (relid >=root -> base_rel_array_size )
160+ {
161+ int oldsize = root -> base_rel_array_size ;
162+ int newsize ;
163+
164+ newsize = Max (oldsize * 2 ,relid + 1 );
165+ root -> base_rel_array = (RelOptInfo * * )
166+ repalloc (root -> base_rel_array ,newsize * sizeof (RelOptInfo * ));
167+ MemSet (root -> base_rel_array + oldsize ,0 ,
168+ (newsize - oldsize )* sizeof (RelOptInfo * ));
169+ root -> base_rel_array_size = newsize ;
170+ }
171+
172+ root -> base_rel_array [relid ]= rel ;
173+
175174return rel ;
176175}
177176
178177/*
179178 * find_base_rel
180- * Find a base or other relation entry, which must already exist
181- * (since we'd have no idea which list to add it to).
179+ * Find a base or other relation entry, which must already exist.
182180 */
183181RelOptInfo *
184182find_base_rel (PlannerInfo * root ,int relid )
185183{
186- ListCell * l ;
187184RelOptInfo * rel ;
188185
189- foreach (l ,root -> base_rel_list )
190- {
191- rel = (RelOptInfo * )lfirst (l );
192- if (relid == rel -> relid )
193- return rel ;
194- }
186+ Assert (relid > 0 );
195187
196- foreach ( l , root -> other_rel_list )
188+ if ( relid < root -> base_rel_array_size )
197189{
198- rel = ( RelOptInfo * ) lfirst ( l ) ;
199- if (relid == rel -> relid )
190+ rel = root -> base_rel_array [ relid ] ;
191+ if (rel )
200192return rel ;
201193}
202194
@@ -308,8 +300,13 @@ build_join_rel(PlannerInfo *root,
308300 * Create a new tlist containing just the vars that need to be output
309301 * from this join (ie, are needed for higher joinclauses or final
310302 * output).
303+ *
304+ * NOTE: the tlist order for a join rel will depend on which pair of
305+ * outer and inner rels we first try to build it from. But the
306+ * contents should be the same regardless.
311307 */
312- build_joinrel_tlist (root ,joinrel );
308+ build_joinrel_tlist (root ,joinrel ,outer_rel );
309+ build_joinrel_tlist (root ,joinrel ,inner_rel );
313310
314311/*
315312 * Construct restrict and join clause lists for the new joinrel. (The
@@ -344,48 +341,39 @@ build_join_rel(PlannerInfo *root,
344341 * Builds a join relation's target list.
345342 *
346343 * The join's targetlist includes all Vars of its member relations that
347- * will still be needed above the join.
348- *
349- * In a former lifetime, this just merged the tlists of the two member
350- * relations first presented. While we could still do that, working from
351- * lists of Vars would mean doing a find_base_rel lookup for each Var.
352- * It seems more efficient to scan the list of base rels and collect the
353- * needed vars directly from there.
344+ * will still be needed above the join. This subroutine adds all such
345+ * Vars from the specified input rel's tlist to the join rel's tlist.
354346 *
355347 * We also compute the expected width of the join's output, making use
356348 * of data that was cached at the baserel level by set_rel_width().
357349 */
358350static void
359- build_joinrel_tlist (PlannerInfo * root ,RelOptInfo * joinrel )
351+ build_joinrel_tlist (PlannerInfo * root ,RelOptInfo * joinrel ,
352+ RelOptInfo * input_rel )
360353{
361354Relids relids = joinrel -> relids ;
362- ListCell * rels ;
355+ ListCell * vars ;
363356
364- joinrel -> reltargetlist = NIL ;
365- joinrel -> width = 0 ;
366-
367- foreach (rels ,root -> base_rel_list )
357+ foreach (vars ,input_rel -> reltargetlist )
368358{
369- RelOptInfo * baserel = (RelOptInfo * )lfirst (rels );
370- ListCell * vars ;
359+ Var * var = (Var * )lfirst (vars );
360+ RelOptInfo * baserel ;
361+ int ndx ;
362+
363+ /* We can't run into any child RowExprs here */
364+ Assert (IsA (var ,Var ));
371365
372- if (! bms_is_member ( baserel -> relid , relids ))
373- continue ;
366+ /* Get the Var's original base rel */
367+ baserel = find_base_rel ( root , var -> varno ) ;
374368
375- foreach (vars ,baserel -> reltargetlist )
369+ /* Is it still needed above this joinrel? */
370+ ndx = var -> varattno - baserel -> min_attr ;
371+ if (bms_nonempty_difference (baserel -> attr_needed [ndx ],relids ))
376372{
377- Var * var = (Var * )lfirst (vars );
378- int ndx = var -> varattno - baserel -> min_attr ;
379-
380- /* We can't run into any child RowExprs here */
381- Assert (IsA (var ,Var ));
382-
383- if (bms_nonempty_difference (baserel -> attr_needed [ndx ],relids ))
384- {
385- joinrel -> reltargetlist = lappend (joinrel -> reltargetlist ,var );
386- Assert (baserel -> attr_widths [ndx ]> 0 );
387- joinrel -> width += baserel -> attr_widths [ndx ];
388- }
373+ /* Yup, add it to the output */
374+ joinrel -> reltargetlist = lappend (joinrel -> reltargetlist ,var );
375+ Assert (baserel -> attr_widths [ndx ]> 0 );
376+ joinrel -> width += baserel -> attr_widths [ndx ];
389377}
390378}
391379}