@@ -40,7 +40,16 @@ import com.nvidia.spark.rapids.delta.shims.DeltaLogShim
4040import com .nvidia .spark .rapids .shims .ShimPredicateHelper
4141
4242import org .apache .spark .sql .{DataFrame , SaveMode , SparkSession }
43- import org .apache .spark .sql .catalyst .expressions .{AttributeReference , EqualTo , Expression , If , IsNotNull , Literal , Not }
43+ import org .apache .spark .sql .catalyst .expressions .{
44+ And ,
45+ AttributeReference ,
46+ EqualTo ,
47+ Expression ,
48+ If ,
49+ IsNotNull ,
50+ Literal ,
51+ Not
52+ }
4453import org .apache .spark .sql .catalyst .plans .logical .TableSpec
4554import org .apache .spark .sql .connector .write .V1Write
4655import org .apache .spark .sql .execution .{FileSourceScanExec , FilterExec , ProjectExec , SparkPlan }
@@ -321,8 +330,20 @@ private object DB173DVPredicatePushdown extends ShimPredicateHelper {
321330
322331 def pruneDeletionVectorSkipRowColumn (plan : SparkPlan ): SparkPlan = {
323332 plan.transformUp {
333+ case project @ ProjectExec (projectList, _) =>
334+ project.copy(projectList = projectList.filterNot(isDeletionVectorSkipRowColumnRef))
324335 case project @ GpuProjectExec (projectList, _, _) =>
325336 project.copy(projectList = projectList.filterNot(isDeletionVectorSkipRowColumnRef))
337+ case fsse : FileSourceScanExec =>
338+ fsse.copy(
339+ output = fsse.output.filterNot(attr => isDeletionVectorSkipRowColumn(attr.name)),
340+ requiredSchema = StructType (fsse.requiredSchema.filterNot(field =>
341+ isDeletionVectorSkipRowColumn(field.name))),
342+ // AQE expects expressions in dataFilters to exist in the output of the scan.
343+ // It will not reuse the stage of the scan otherwise. Since we are removing
344+ // the deletion-vector skip-row column from scan's output, remove the
345+ // corresponding filter from dataFilters as well.
346+ dataFilters = fsse.dataFilters.filterNot(isDVCondition))
326347 case fsse : GpuFileSourceScanExec =>
327348 fsse.copy(
328349 originalOutput = fsse.originalOutput.filterNot(attr =>
@@ -341,37 +362,53 @@ private object DB173DVPredicatePushdown extends ShimPredicateHelper {
341362 // Only native GPU DV scans can replace the skip-row filter. DB DML bitmap-writing
342363 // plans may still need that filter even when the plugin is enabled.
343364 plan.exists {
365+ case fsse : FileSourceScanExec =>
366+ fsse.relation.fileFormat.isInstanceOf [GpuDeltaParquetFileFormatNativeDV ]
344367 case fsse : GpuFileSourceScanExec =>
345368 fsse.relation.fileFormat.isInstanceOf [GpuDeltaParquetFileFormatNativeDV ]
346369 case _ => false
347370 }
348371 }
349372
373+ def rewriteFilter (
374+ condition : Expression ,
375+ child : SparkPlan ,
376+ combinePredicates : (Expression , Expression ) => Expression ,
377+ copyFilter : (Expression , SparkPlan ) => SparkPlan ): Option [SparkPlan ] = {
378+ val conjuncts = splitConjunctivePredicates(condition)
379+ val (dvPredicates, otherPredicates) = conjuncts.partition { predicate =>
380+ predicate.references.size == 1 &&
381+ predicate.references.exists(ref => isDeletionVectorSkipRowColumn(ref.name)) &&
382+ isDVCondition(predicate)
383+ }
384+ val otherPredicatesReadingSkipRow = otherPredicates.exists { predicate =>
385+ predicate.references.exists(ref => isDeletionVectorSkipRowColumn(ref.name))
386+ }
387+ if (dvPredicates.nonEmpty &&
388+ ! otherPredicatesReadingSkipRow &&
389+ hasNativeDeletionVectorGpuScan(child)) {
390+ val newChild = pruneDeletionVectorSkipRowColumn(child)
391+ Some (if (otherPredicates.isEmpty) {
392+ newChild
393+ } else {
394+ copyFilter(otherPredicates.reduce(combinePredicates), newChild)
395+ })
396+ } else {
397+ None
398+ }
399+ }
400+
350401 plan.transformUp {
351402 case filter @ GpuFilterExec (condition, child)
352403 if condition.references.exists(ref => isDeletionVectorSkipRowColumn(ref.name)) =>
353- val conjuncts = splitConjunctivePredicates(condition)
354- val (dvPredicates, otherPredicates) = conjuncts.partition { predicate =>
355- predicate.references.size == 1 &&
356- predicate.references.exists(ref => isDeletionVectorSkipRowColumn(ref.name)) &&
357- isDVCondition(predicate)
358- }
359- val otherPredicatesReadingSkipRow = otherPredicates.exists { predicate =>
360- predicate.references.exists(ref => isDeletionVectorSkipRowColumn(ref.name))
361- }
362- if (dvPredicates.nonEmpty &&
363- ! otherPredicatesReadingSkipRow &&
364- hasNativeDeletionVectorGpuScan(child)) {
365- val newChild = pruneDeletionVectorSkipRowColumn(child)
366- if (otherPredicates.isEmpty) {
367- newChild
368- } else {
369- filter.copy(condition = otherPredicates.reduce(GpuAnd ),
370- child = newChild)(filter.coalesceAfter)
371- }
372- } else {
373- filter
374- }
404+ rewriteFilter(condition, child, GpuAnd (_, _),
405+ (newCondition, newChild) => filter.copy(condition = newCondition,
406+ child = newChild)(filter.coalesceAfter)).getOrElse(filter)
407+ case filter @ FilterExec (condition, child)
408+ if condition.references.exists(ref => isDeletionVectorSkipRowColumn(ref.name)) =>
409+ rewriteFilter(condition, child, And (_, _),
410+ (newCondition, newChild) => filter.copy(condition = newCondition, child = newChild))
411+ .getOrElse(filter)
375412 }
376413 }
377414
0 commit comments