Skip to content

Commit 84f944c

Browse files
Add unit tests to verify limit 0 optimization
1 parent df05284 commit 84f944c

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/PropagateEmptyRelationSuite.scala

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import org.apache.spark.sql.catalyst.dsl.expressions._
2323
import org.apache.spark.sql.catalyst.dsl.plans._
2424
import org.apache.spark.sql.catalyst.expressions.Literal
2525
import org.apache.spark.sql.catalyst.plans._
26-
import org.apache.spark.sql.catalyst.plans.logical.{LocalRelation, LogicalPlan, Project}
26+
import org.apache.spark.sql.catalyst.plans.logical.{Distinct, GlobalLimit, LocalLimit,
27+
LocalRelation, LogicalPlan, Project}
2728
import org.apache.spark.sql.catalyst.rules.RuleExecutor
2829
import org.apache.spark.sql.types.{IntegerType, StructType}
2930

@@ -221,4 +222,79 @@ class PropagateEmptyRelationSuite extends PlanTest {
221222
val optimized = Optimize.execute(query.analyze)
222223
assert(optimized.resolved)
223224
}
225+
226+
test("Limit 0: return empty local relation") {
227+
val query = testRelation1.limit(0)
228+
229+
val optimized = Optimize.execute(query.analyze)
230+
val correctAnswer = LocalRelation('a.int)
231+
232+
comparePlans(optimized, correctAnswer)
233+
}
234+
235+
test("Limit 0: individual LocalLimit 0 node") {
236+
val query = LocalLimit(0, testRelation1)
237+
238+
val optimized = Optimize.execute(query.analyze)
239+
val correctAnswer = LocalRelation('a.int)
240+
241+
comparePlans(optimized, correctAnswer)
242+
}
243+
244+
test("Limit 0: individual GlobalLimit 0 node") {
245+
val query = GlobalLimit(0, testRelation1)
246+
247+
val optimized = Optimize.execute(query.analyze)
248+
val correctAnswer = LocalRelation('a.int)
249+
250+
comparePlans(optimized, correctAnswer)
251+
}
252+
253+
test("Limit 0: Joins") {
254+
val testcases = Seq(
255+
(Inner, Some(LocalRelation('a.int, 'b.int))),
256+
(LeftOuter,
257+
Some(Project(Seq('a, Literal(null).cast(IntegerType).as('b)), testRelation1).analyze)),
258+
(RightOuter, Some(LocalRelation('a.int, 'b.int))),
259+
(FullOuter,
260+
Some(Project(Seq('a, Literal(null).cast(IntegerType).as('b)), testRelation1).analyze))
261+
)
262+
263+
testcases.foreach { case (jt, answer) =>
264+
val query = testRelation1
265+
.join(testRelation2.limit(0), joinType = jt, condition = Some('a.attr == 'b.attr))
266+
267+
val optimized = Optimize.execute(query.analyze)
268+
val correctAnswer =
269+
answer.getOrElse(OptimizeWithoutPropagateEmptyRelation.execute(query.analyze))
270+
271+
comparePlans(optimized, correctAnswer)
272+
}
273+
}
274+
275+
test("Limit 0: 3-way join") {
276+
val testRelation3 = LocalRelation.fromExternalRows(Seq('c.int), data = Seq(Row(1)))
277+
278+
val subJoinQuery = testRelation1
279+
.join(testRelation2, joinType = Inner, condition = Some('a.attr == 'b.attr))
280+
val query = subJoinQuery
281+
.join(testRelation3.limit(0), joinType = Inner, condition = Some('a.attr == 'c.attr))
282+
283+
val optimized = Optimize.execute(query.analyze)
284+
val correctAnswer = Some(LocalRelation('a.int, 'b.int, 'c.int))
285+
.getOrElse(OptimizeWithoutPropagateEmptyRelation.execute(query.analyze))
286+
287+
comparePlans(optimized, correctAnswer)
288+
}
289+
290+
test("Limit 0: intersect") {
291+
val query = testRelation1
292+
.intersect(testRelation1.limit(0), isAll = false)
293+
294+
val optimized = Optimize.execute(query.analyze)
295+
val correctAnswer = Distinct(Some(LocalRelation('a.int))
296+
.getOrElse(OptimizeWithoutPropagateEmptyRelation.execute(query.analyze)))
297+
298+
comparePlans(optimized, correctAnswer)
299+
}
224300
}

0 commit comments

Comments
 (0)