@@ -20,11 +20,14 @@ package org.apache.spark.sql.catalyst.optimizer
2020import org .apache .spark .sql .catalyst .analysis
2121import org .apache .spark .sql .catalyst .analysis .EliminateAnalysisOperators
2222import org .apache .spark .sql .catalyst .plans .logical ._
23+ import org .apache .spark .sql .catalyst .plans .Inner
24+ import org .apache .spark .sql .catalyst .plans .FullOuter
25+ import org .apache .spark .sql .catalyst .plans .LeftOuter
26+ import org .apache .spark .sql .catalyst .plans .RightOuter
2327import org .apache .spark .sql .catalyst .rules ._
24-
25- /* Implicit conversions */
2628import org .apache .spark .sql .catalyst .dsl .plans ._
2729import org .apache .spark .sql .catalyst .dsl .expressions ._
30+ import org .junit .Test
2831
2932class FilterPushdownSuite extends OptimizerTest {
3033
@@ -35,7 +38,7 @@ class FilterPushdownSuite extends OptimizerTest {
3538 Batch (" Filter Pushdown" , Once ,
3639 CombineFilters ,
3740 PushPredicateThroughProject ,
38- PushPredicateThroughInnerJoin ) :: Nil
41+ PushPredicateThroughJoin ) :: Nil
3942 }
4043
4144 val testRelation = LocalRelation (' a .int, ' b .int, ' c .int)
@@ -161,6 +164,184 @@ class FilterPushdownSuite extends OptimizerTest {
161164
162165 comparePlans(optimized, correctAnswer)
163166 }
167+
168+ test(" joins: push down left outer join #1" ) {
169+ val x = testRelation.subquery(' x )
170+ val y = testRelation.subquery(' y )
171+
172+ val originalQuery = {
173+ x.join(y, LeftOuter )
174+ .where(" x.b" .attr === 1 && " y.b" .attr === 2 )
175+ }
176+
177+ val optimized = Optimize (originalQuery.analyze)
178+ val left = testRelation.where(' b === 1 )
179+ val correctAnswer =
180+ left.join(y, LeftOuter ).where(" y.b" .attr === 2 ).analyze
181+
182+ comparePlans(optimized, correctAnswer)
183+ }
184+
185+ test(" joins: push down right outer join #1" ) {
186+ val x = testRelation.subquery(' x )
187+ val y = testRelation.subquery(' y )
188+
189+ val originalQuery = {
190+ x.join(y, RightOuter )
191+ .where(" x.b" .attr === 1 && " y.b" .attr === 2 )
192+ }
193+
194+ val optimized = Optimize (originalQuery.analyze)
195+ val right = testRelation.where(' b === 2 ).subquery(' d )
196+ val correctAnswer =
197+ x.join(right, RightOuter ).where(" x.b" .attr === 1 ).analyze
198+
199+ comparePlans(optimized, correctAnswer)
200+ }
201+
202+ test(" joins: push down left outer join #2" ) {
203+ val x = testRelation.subquery(' x )
204+ val y = testRelation.subquery(' y )
205+
206+ val originalQuery = {
207+ x.join(y, LeftOuter , Some (" x.b" .attr === 1 ))
208+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 )
209+ }
210+
211+ val optimized = Optimize (originalQuery.analyze)
212+ val left = testRelation.where(' b === 2 ).subquery(' d )
213+ val correctAnswer =
214+ left.join(y, LeftOuter , Some (" d.b" .attr === 1 )).where(" y.b" .attr === 2 ).analyze
215+
216+ comparePlans(optimized, correctAnswer)
217+ }
218+
219+ test(" joins: push down right outer join #2" ) {
220+ val x = testRelation.subquery(' x )
221+ val y = testRelation.subquery(' y )
222+
223+ val originalQuery = {
224+ x.join(y, RightOuter , Some (" y.b" .attr === 1 ))
225+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 )
226+ }
227+
228+ val optimized = Optimize (originalQuery.analyze)
229+ val right = testRelation.where(' b === 2 ).subquery(' d )
230+ val correctAnswer =
231+ x.join(right, RightOuter , Some (" d.b" .attr === 1 )).where(" x.b" .attr === 2 ).analyze
232+
233+ comparePlans(optimized, correctAnswer)
234+ }
235+
236+ test(" joins: push down left outer join #3" ) {
237+ val x = testRelation.subquery(' x )
238+ val y = testRelation.subquery(' y )
239+
240+ val originalQuery = {
241+ x.join(y, LeftOuter , Some (" y.b" .attr === 1 ))
242+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 )
243+ }
244+
245+ val optimized = Optimize (originalQuery.analyze)
246+ val left = testRelation.where(' b === 2 ).subquery(' l )
247+ val right = testRelation.where(' b === 1 ).subquery(' r )
248+ val correctAnswer =
249+ left.join(right, LeftOuter ).where(" r.b" .attr === 2 ).analyze
250+
251+ comparePlans(optimized, correctAnswer)
252+ }
253+
254+ test(" joins: push down right outer join #3" ) {
255+ val x = testRelation.subquery(' x )
256+ val y = testRelation.subquery(' y )
257+
258+ val originalQuery = {
259+ x.join(y, RightOuter , Some (" y.b" .attr === 1 ))
260+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 )
261+ }
262+
263+ val optimized = Optimize (originalQuery.analyze)
264+ val right = testRelation.where(' b === 2 ).subquery(' r )
265+ val correctAnswer =
266+ x.join(right, RightOuter , Some (" r.b" .attr === 1 )).where(" x.b" .attr === 2 ).analyze
267+
268+ comparePlans(optimized, correctAnswer)
269+ }
270+
271+ test(" joins: push down left outer join #4" ) {
272+ val x = testRelation.subquery(' x )
273+ val y = testRelation.subquery(' y )
274+
275+ val originalQuery = {
276+ x.join(y, LeftOuter , Some (" y.b" .attr === 1 ))
277+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 && " x.c" .attr === " y.c" .attr)
278+ }
279+
280+ val optimized = Optimize (originalQuery.analyze)
281+ val left = testRelation.where(' b === 2 ).subquery(' l )
282+ val right = testRelation.where(' b === 1 ).subquery(' r )
283+ val correctAnswer =
284+ left.join(right, LeftOuter ).where(" r.b" .attr === 2 && " l.c" .attr === " r.c" .attr).analyze
285+
286+ comparePlans(optimized, correctAnswer)
287+ }
288+
289+ test(" joins: push down right outer join #4" ) {
290+ val x = testRelation.subquery(' x )
291+ val y = testRelation.subquery(' y )
292+
293+ val originalQuery = {
294+ x.join(y, RightOuter , Some (" y.b" .attr === 1 ))
295+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 && " x.c" .attr === " y.c" .attr)
296+ }
297+
298+ val optimized = Optimize (originalQuery.analyze)
299+ val left = testRelation.subquery(' l )
300+ val right = testRelation.where(' b === 2 ).subquery(' r )
301+ val correctAnswer =
302+ left.join(right, RightOuter , Some (" r.b" .attr === 1 )).
303+ where(" l.b" .attr === 2 && " l.c" .attr === " r.c" .attr).analyze
304+
305+ comparePlans(optimized, correctAnswer)
306+ }
307+
308+ test(" joins: push down left outer join #5" ) {
309+ val x = testRelation.subquery(' x )
310+ val y = testRelation.subquery(' y )
311+
312+ val originalQuery = {
313+ x.join(y, LeftOuter , Some (" y.b" .attr === 1 && " x.a" .attr === 3 ))
314+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 && " x.c" .attr === " y.c" .attr)
315+ }
316+
317+ val optimized = Optimize (originalQuery.analyze)
318+ val left = testRelation.where(' b === 2 ).subquery(' l )
319+ val right = testRelation.where(' b === 1 ).subquery(' r )
320+ val correctAnswer =
321+ left.join(right, LeftOuter , Some (" l.a" .attr=== 3 )).
322+ where(" r.b" .attr === 2 && " l.c" .attr === " r.c" .attr).analyze
323+
324+ comparePlans(optimized, correctAnswer)
325+ }
326+
327+ test(" joins: push down right outer join #5" ) {
328+ val x = testRelation.subquery(' x )
329+ val y = testRelation.subquery(' y )
330+
331+ val originalQuery = {
332+ x.join(y, RightOuter , Some (" y.b" .attr === 1 && " x.a" .attr === 3 ))
333+ .where(" x.b" .attr === 2 && " y.b" .attr === 2 && " x.c" .attr === " y.c" .attr)
334+ }
335+
336+ val optimized = Optimize (originalQuery.analyze)
337+ val left = testRelation.where(' a === 3 ).subquery(' l )
338+ val right = testRelation.where(' b === 2 ).subquery(' r )
339+ val correctAnswer =
340+ left.join(right, RightOuter , Some (" r.b" .attr === 1 )).
341+ where(" l.b" .attr === 2 && " l.c" .attr === " r.c" .attr).analyze
342+
343+ comparePlans(optimized, correctAnswer)
344+ }
164345
165346 test(" joins: can't push down" ) {
166347 val x = testRelation.subquery(' x )
0 commit comments