@@ -25,8 +25,8 @@ import scala.collection.JavaConverters._
2525import org .apache .spark .rdd .RDD
2626import org .apache .spark .sql .catalyst .InternalRow
2727import org .apache .spark .sql .catalyst .errors ._
28- import org .apache .spark .sql .catalyst .expressions ._
29- import org .apache .spark .sql .catalyst .expressions .codegen .{ GenerateUnsafeProjection , Predicate }
28+ import org .apache .spark .sql .catalyst .expressions .{ Predicate => _ , _ }
29+ import org .apache .spark .sql .catalyst .expressions .codegen ._
3030import org .apache .spark .sql .catalyst .plans .logical .EventTimeWatermark
3131import org .apache .spark .sql .catalyst .plans .physical .{AllTuples , ClusteredDistribution , Distribution , Partitioning }
3232import org .apache .spark .sql .catalyst .streaming .InternalOutputModes ._
@@ -40,7 +40,7 @@ import org.apache.spark.util.{CompletionIterator, NextIterator, Utils}
4040case class CountLateRowsExec (
4141 eventTimeWatermark : Option [Long ] = None ,
4242 child : SparkPlan )
43- extends UnaryExecNode with WatermarkSupport {
43+ extends UnaryExecNode with WatermarkSupport with CodegenSupport {
4444
4545 // No need to determine key expressions here.
4646 override def keyExpressions : Seq [Attribute ] = Seq .empty
@@ -70,6 +70,50 @@ case class CountLateRowsExec(
7070 }
7171 }
7272 }
73+
74+ override def inputRDDs (): Seq [RDD [InternalRow ]] = {
75+ child.asInstanceOf [CodegenSupport ].inputRDDs()
76+ }
77+
78+ override protected def doProduce (ctx : CodegenContext ): String = {
79+ child.asInstanceOf [CodegenSupport ].produce(ctx, this )
80+ }
81+
82+ override def doConsume (ctx : CodegenContext , input : Seq [ExprCode ], row : ExprCode ): String = {
83+ val numLateRows = metricTerm(ctx, " numLateRows" )
84+
85+ val generated = watermarkExpression match {
86+ case Some (expr) =>
87+ val bound = BindReferences .bindReference(expr, child.output)
88+ val evaluated = evaluateRequiredVariables(child.output, input, expr.references)
89+
90+ // Generate the code for the predicate.
91+ val ev = ExpressionCanonicalizer .execute(bound).genCode(ctx)
92+ val nullCheck = if (bound.nullable) {
93+ s " ${ev.isNull} || "
94+ } else {
95+ s " "
96+ }
97+
98+ s """
99+ | $evaluated
100+ | ${ev.code}
101+ |if ( ${nullCheck}${ev.value}) {
102+ | $numLateRows.add(1);
103+ |}
104+ """ .stripMargin
105+
106+ case None => " "
107+ }
108+
109+ // Note: wrap in "do { } while(false);", so the generated checks can jump out with "continue;"
110+ s """
111+ |do {
112+ | $generated
113+ | ${consume(ctx, input)}
114+ |} while(false);
115+ """ .stripMargin
116+ }
73117}
74118
75119/** Used to identify the state store for a given operator. */
0 commit comments