This is an automated email from the ASF dual-hosted git repository.
taiyangli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-gluten.git
The following commit(s) were added to refs/heads/main by this push:
new 596858adde support nested column pruning (#7268)
596858adde is described below
commit 596858adde56caa4167e73ffdf53dedf8700874d
Author: kevinyhzou <[email protected]>
AuthorDate: Fri Nov 15 14:19:18 2024 +0800
support nested column pruning (#7268)
Co-authored-by: zouyunhe <[email protected]>
---
.../gluten/backendsapi/clickhouse/CHBackend.scala | 4 +
.../hive/GlutenClickHouseHiveTableSuite.scala | 53 +++++
.../gluten/backendsapi/BackendSettingsApi.scala | 2 +
.../columnar/heuristic/OffloadSingleNode.scala | 8 +-
.../sql/hive/HiveTableScanExecTransformer.scala | 11 +-
.../hive/HiveTableScanNestedColumnPruning.scala | 252 +++++++++++++++++++++
.../scala/org/apache/gluten/GlutenConfig.scala | 10 +
.../hive/execution/AbstractHiveTableScanExec.scala | 7 +-
.../hive/execution/AbstractHiveTableScanExec.scala | 7 +-
.../hive/execution/AbstractHiveTableScanExec.scala | 7 +-
.../hive/execution/AbstractHiveTableScanExec.scala | 7 +-
11 files changed, 360 insertions(+), 8 deletions(-)
diff --git
a/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHBackend.scala
b/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHBackend.scala
index 54ab38569b..6e73ff6b29 100644
---
a/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHBackend.scala
+++
b/backends-clickhouse/src/main/scala/org/apache/gluten/backendsapi/clickhouse/CHBackend.scala
@@ -396,4 +396,8 @@ object CHBackendSettings extends BackendSettingsApi with
Logging {
}
override def supportWindowGroupLimitExec(rankLikeFunction: Expression):
Boolean = true
+
+ override def supportHiveTableScanNestedColumnPruning: Boolean =
+ GlutenConfig.getConf.enableColumnarHiveTableScanNestedColumnPruning
+
}
diff --git
a/backends-clickhouse/src/test/scala/org/apache/gluten/execution/hive/GlutenClickHouseHiveTableSuite.scala
b/backends-clickhouse/src/test/scala/org/apache/gluten/execution/hive/GlutenClickHouseHiveTableSuite.scala
index ff2d13996d..7e31e73040 100644
---
a/backends-clickhouse/src/test/scala/org/apache/gluten/execution/hive/GlutenClickHouseHiveTableSuite.scala
+++
b/backends-clickhouse/src/test/scala/org/apache/gluten/execution/hive/GlutenClickHouseHiveTableSuite.scala
@@ -1499,4 +1499,57 @@ class GlutenClickHouseHiveTableSuite
spark.sql("drop table if exists aj")
}
+ test("test hive table scan nested column pruning") {
+ val json_table_name = "test_tbl_7267_json"
+ val pq_table_name = "test_tbl_7267_pq"
+ val create_table_sql =
+ s"""
+ | create table if not exists %s(
+ | id bigint,
+ | d1 STRUCT<c: STRING, d: ARRAY<STRUCT<x: STRING, y: STRING>>>,
+ | d2 STRUCT<c: STRING, d: Map<STRING, STRUCT<x: STRING, y: STRING>>>,
+ | day string,
+ | hour string
+ | ) partitioned by(day, hour)
+ |""".stripMargin
+ val create_table_json = create_table_sql.format(json_table_name) +
+ s"""
+ | ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
+ | STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat'
+ | OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
+ |""".stripMargin
+ val create_table_pq = create_table_sql.format(pq_table_name) + " Stored as
PARQUET"
+ val insert_sql =
+ """
+ | insert into %s values(1,
+ | named_struct('c', 'c123', 'd', array(named_struct('x', 'x123', 'y',
'y123'))),
+ | named_struct('c', 'c124', 'd', map('m124', named_struct('x', 'x124',
'y', 'y124'))),
+ | '2024-09-26', '12'
+ | )
+ |""".stripMargin
+ val select_sql =
+ "select id, d1.c, d1.d[0].x, d2.d['m124'].y from %s where day =
'2024-09-26' and hour = '12'"
+ val table_names = Array.apply(json_table_name, pq_table_name)
+ val create_table_sqls = Array.apply(create_table_json, create_table_pq)
+ for (i <- table_names.indices) {
+ val table_name = table_names(i)
+ val create_table = create_table_sqls(i)
+ spark.sql(create_table)
+ spark.sql(insert_sql.format(table_name))
+ withSQLConf(("spark.sql.hive.convertMetastoreParquet" -> "false")) {
+ compareResultsAgainstVanillaSpark(
+ select_sql.format(table_name),
+ compareResult = true,
+ df => {
+ val scan = collect(df.queryExecution.executedPlan) {
+ case l: HiveTableScanExecTransformer => l
+ }
+ assert(scan.size == 1)
+ }
+ )
+ }
+ spark.sql("drop table if exists %s".format(table_name))
+ }
+ }
+
}
diff --git
a/gluten-substrait/src/main/scala/org/apache/gluten/backendsapi/BackendSettingsApi.scala
b/gluten-substrait/src/main/scala/org/apache/gluten/backendsapi/BackendSettingsApi.scala
index 177d19c0c7..700571fd28 100644
---
a/gluten-substrait/src/main/scala/org/apache/gluten/backendsapi/BackendSettingsApi.scala
+++
b/gluten-substrait/src/main/scala/org/apache/gluten/backendsapi/BackendSettingsApi.scala
@@ -131,4 +131,6 @@ trait BackendSettingsApi {
def supportColumnarArrowUdf(): Boolean = false
def needPreComputeRangeFrameBoundary(): Boolean = false
+
+ def supportHiveTableScanNestedColumnPruning(): Boolean = false
}
diff --git
a/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/heuristic/OffloadSingleNode.scala
b/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/heuristic/OffloadSingleNode.scala
index a8c200e9be..bae98bec2e 100644
---
a/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/heuristic/OffloadSingleNode.scala
+++
b/gluten-substrait/src/main/scala/org/apache/gluten/extension/columnar/heuristic/OffloadSingleNode.scala
@@ -37,7 +37,7 @@ import
org.apache.spark.sql.execution.exchange.{BroadcastExchangeExec, ShuffleEx
import org.apache.spark.sql.execution.joins._
import org.apache.spark.sql.execution.python.{ArrowEvalPythonExec,
BatchEvalPythonExec}
import org.apache.spark.sql.execution.window.{WindowExec,
WindowGroupLimitExecShim}
-import org.apache.spark.sql.hive.HiveTableScanExecTransformer
+import org.apache.spark.sql.hive.{HiveTableScanExecTransformer,
HiveTableScanNestedColumnPruning}
/**
* Converts a vanilla Spark plan node into Gluten plan node. Gluten plan is
supposed to be executed
@@ -226,7 +226,11 @@ object OffloadOthers {
case plan: ProjectExec =>
val columnarChild = plan.child
logDebug(s"Columnar Processing for ${plan.getClass} is currently
supported.")
- ProjectExecTransformer(plan.projectList, columnarChild)
+ if
(HiveTableScanNestedColumnPruning.supportNestedColumnPruning(plan)) {
+ HiveTableScanNestedColumnPruning.apply(plan)
+ } else {
+ ProjectExecTransformer(plan.projectList, columnarChild)
+ }
case plan: HashAggregateExec =>
logDebug(s"Columnar Processing for ${plan.getClass} is currently
supported.")
HashAggregateExecBaseTransformer.from(plan)
diff --git
a/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanExecTransformer.scala
b/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanExecTransformer.scala
index 85432350d4..f701c76b18 100644
---
a/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanExecTransformer.scala
+++
b/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanExecTransformer.scala
@@ -45,7 +45,8 @@ import java.net.URI
case class HiveTableScanExecTransformer(
requestedAttributes: Seq[Attribute],
relation: HiveTableRelation,
- partitionPruningPred: Seq[Expression])(@transient session: SparkSession)
+ partitionPruningPred: Seq[Expression],
+ prunedOutput: Seq[Attribute] = Seq.empty[Attribute])(@transient session:
SparkSession)
extends AbstractHiveTableScanExec(requestedAttributes, relation,
partitionPruningPred)(session)
with BasicScanExecTransformer {
@@ -63,7 +64,13 @@ case class HiveTableScanExecTransformer(
override def getMetadataColumns(): Seq[AttributeReference] = Seq.empty
- override def outputAttributes(): Seq[Attribute] = output
+ override def outputAttributes(): Seq[Attribute] = {
+ if (prunedOutput.nonEmpty) {
+ prunedOutput
+ } else {
+ output
+ }
+ }
override def getPartitions: Seq[InputPartition] = partitions
diff --git
a/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanNestedColumnPruning.scala
b/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanNestedColumnPruning.scala
new file mode 100644
index 0000000000..7a20e5c37d
--- /dev/null
+++
b/gluten-substrait/src/main/scala/org/apache/spark/sql/hive/HiveTableScanNestedColumnPruning.scala
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.spark.sql.hive
+
+import org.apache.gluten.backendsapi.BackendsApiManager
+import org.apache.gluten.execution.ProjectExecTransformer
+
+import org.apache.spark.internal.Logging
+import org.apache.spark.sql.catalyst.catalog.HiveTableRelation
+import org.apache.spark.sql.catalyst.expressions._
+import org.apache.spark.sql.execution.{FilterExec, LeafExecNode, ProjectExec,
SparkPlan}
+import
org.apache.spark.sql.hive.HiveTableScanExecTransformer.{ORC_INPUT_FORMAT_CLASS,
PARQUET_INPUT_FORMAT_CLASS, TEXT_INPUT_FORMAT_CLASS}
+import org.apache.spark.sql.types.{ArrayType, DataType, MapType, StructType}
+import org.apache.spark.sql.util.SchemaUtils._
+import org.apache.spark.util.Utils
+
+object HiveTableScanNestedColumnPruning extends Logging {
+ import org.apache.spark.sql.catalyst.expressions.SchemaPruning._
+
+ def supportNestedColumnPruning(projectExec: ProjectExec): Boolean = {
+ if
(BackendsApiManager.getSettings.supportHiveTableScanNestedColumnPruning()) {
+ projectExec.child match {
+ case HiveTableScanExecTransformer(_, relation, _, _) =>
+ relation.tableMeta.storage.inputFormat match {
+ case Some(inputFormat)
+ if
TEXT_INPUT_FORMAT_CLASS.isAssignableFrom(Utils.classForName(inputFormat)) =>
+ relation.tableMeta.storage.serde match {
+ case Some("org.openx.data.jsonserde.JsonSerDe") | Some(
+ "org.apache.hive.hcatalog.data.JsonSerDe") =>
+ return true
+ case _ =>
+ }
+ case Some(inputFormat)
+ if
ORC_INPUT_FORMAT_CLASS.isAssignableFrom(Utils.classForName(inputFormat)) =>
+ return true
+ case Some(inputFormat)
+ if
PARQUET_INPUT_FORMAT_CLASS.isAssignableFrom(Utils.classForName(inputFormat)) =>
+ return true
+ case _ =>
+ }
+ case _ =>
+ }
+ }
+ false
+ }
+
+ def apply(plan: SparkPlan): SparkPlan = {
+ plan match {
+ case ProjectExec(projectList, child) =>
+ child match {
+ case h: HiveTableScanExecTransformer =>
+ val newPlan = prunePhysicalColumns(
+ h.relation,
+ projectList,
+ Seq.empty[Expression],
+ (prunedDataSchema, prunedMetadataSchema) => {
+ buildNewHiveTableScan(h, prunedDataSchema,
prunedMetadataSchema)
+ },
+ (schema, requestFields) => {
+ h.pruneSchema(schema, requestFields)
+ }
+ )
+ if (newPlan.nonEmpty) {
+ return newPlan.get
+ } else {
+ return ProjectExecTransformer(projectList, child)
+ }
+ case _ =>
+ return ProjectExecTransformer(projectList, child)
+ }
+ case _ =>
+ }
+ plan
+ }
+
+ private def prunePhysicalColumns(
+ relation: HiveTableRelation,
+ projects: Seq[NamedExpression],
+ filters: Seq[Expression],
+ leafNodeBuilder: (StructType, StructType) => LeafExecNode,
+ pruneSchemaFunc: (StructType, Seq[SchemaPruning.RootField]) =>
StructType)
+ : Option[SparkPlan] = {
+ val (normalizedProjects, normalizedFilters) =
+ normalizeAttributeRefNames(relation.output, projects, filters)
+ val requestedRootFields = identifyRootFields(normalizedProjects,
normalizedFilters)
+ // If requestedRootFields includes a nested field, continue. Otherwise,
+ // return op
+ if (requestedRootFields.exists { root: RootField => !root.derivedFromAtt
}) {
+ val prunedDataSchema = pruneSchemaFunc(relation.tableMeta.dataSchema,
requestedRootFields)
+ val metaFieldNames = relation.tableMeta.schema.fieldNames
+ val metadataSchema = relation.output.collect {
+ case attr: AttributeReference if metaFieldNames.contains(attr.name) =>
attr
+ }.toStructType
+ val prunedMetadataSchema = if (metadataSchema.nonEmpty) {
+ pruneSchemaFunc(metadataSchema, requestedRootFields)
+ } else {
+ metadataSchema
+ }
+ // If the data schema is different from the pruned data schema
+ // OR
+ // the metadata schema is different from the pruned metadata schema,
continue.
+ // Otherwise, return None.
+ if (
+ countLeaves(relation.tableMeta.dataSchema) >
countLeaves(prunedDataSchema) ||
+ countLeaves(metadataSchema) > countLeaves(prunedMetadataSchema)
+ ) {
+ val leafNode = leafNodeBuilder(prunedDataSchema, prunedMetadataSchema)
+ val projectionOverSchema = ProjectionOverSchema(
+ prunedDataSchema.merge(prunedMetadataSchema),
+ AttributeSet(relation.output))
+ Some(
+ buildNewProjection(
+ projects,
+ normalizedProjects,
+ normalizedFilters,
+ leafNode,
+ projectionOverSchema))
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ /**
+ * Normalizes the names of the attribute references in the given projects
and filters to reflect
+ * the names in the given logical relation. This makes it possible to
compare attributes and
+ * fields by name. Returns a tuple with the normalized projects and filters,
respectively.
+ */
+ private def normalizeAttributeRefNames(
+ output: Seq[AttributeReference],
+ projects: Seq[NamedExpression],
+ filters: Seq[Expression]): (Seq[NamedExpression], Seq[Expression]) = {
+ val normalizedAttNameMap = output.map(att => (att.exprId, att.name)).toMap
+ val normalizedProjects = projects
+ .map(_.transform {
+ case att: AttributeReference if
normalizedAttNameMap.contains(att.exprId) =>
+ att.withName(normalizedAttNameMap(att.exprId))
+ })
+ .map { case expr: NamedExpression => expr }
+ val normalizedFilters = filters.map(_.transform {
+ case att: AttributeReference if
normalizedAttNameMap.contains(att.exprId) =>
+ att.withName(normalizedAttNameMap(att.exprId))
+ })
+ (normalizedProjects, normalizedFilters)
+ }
+
+ /** Builds the new output [[Project]] Spark SQL operator that has the
`leafNode`. */
+ private def buildNewProjection(
+ projects: Seq[NamedExpression],
+ normalizedProjects: Seq[NamedExpression],
+ filters: Seq[Expression],
+ leafNode: LeafExecNode,
+ projectionOverSchema: ProjectionOverSchema): ProjectExecTransformer = {
+ // Construct a new target for our projection by rewriting and
+ // including the original filters where available
+ val projectionChild =
+ if (filters.nonEmpty) {
+ val projectedFilters = filters.map(_.transformDown {
+ case projectionOverSchema(expr) => expr
+ })
+ val newFilterCondition = projectedFilters.reduce(And)
+ FilterExec(newFilterCondition, leafNode)
+ } else {
+ leafNode
+ }
+
+ // Construct the new projections of our Project by
+ // rewriting the original projections
+ val newProjects =
+ normalizedProjects.map(_.transformDown { case projectionOverSchema(expr)
=> expr }).map {
+ case expr: NamedExpression => expr
+ }
+
+ ProjectExecTransformer(
+ restoreOriginalOutputNames(newProjects, projects.map(_.name)),
+ projectionChild)
+ }
+
+ private def buildNewHiveTableScan(
+ hiveTableScan: HiveTableScanExecTransformer,
+ prunedDataSchema: StructType,
+ prunedMetadataSchema: StructType): HiveTableScanExecTransformer = {
+ val relation = hiveTableScan.relation
+ val partitionSchema = relation.tableMeta.partitionSchema
+ val prunedBaseSchema = StructType(
+ prunedDataSchema.fields.filterNot(
+ f => partitionSchema.fieldNames.contains(f.name)) ++
partitionSchema.fields)
+ val finalSchema = prunedBaseSchema.merge(prunedMetadataSchema)
+ val prunedOutput = getPrunedOutput(relation.output, finalSchema)
+ var finalOutput = Seq.empty[Attribute]
+ for (p <- hiveTableScan.output) {
+ var flag = false
+ for (q <- prunedOutput if !flag) {
+ if (p.name.equals(q.name)) {
+ finalOutput :+= q
+ flag = true
+ }
+ }
+ }
+ HiveTableScanExecTransformer(
+ hiveTableScan.requestedAttributes,
+ relation,
+ hiveTableScan.partitionPruningPred,
+ finalOutput)(hiveTableScan.session)
+ }
+
+ // Prune the given output to make it consistent with `requiredSchema`.
+ private def getPrunedOutput(
+ output: Seq[AttributeReference],
+ requiredSchema: StructType): Seq[Attribute] = {
+ // We need to update the data type of the output attributes to use the
pruned ones.
+ // so that references to the original relation's output are not broken
+ val nameAttributeMap = output.map(att => (att.name, att)).toMap
+ val requiredAttributes =
+ requiredSchema.map(f => AttributeReference(f.name, f.dataType,
f.nullable, f.metadata)())
+ requiredAttributes.map {
+ case att if nameAttributeMap.contains(att.name) =>
+ nameAttributeMap(att.name).withDataType(att.dataType)
+ case att => att
+ }
+ }
+
+ /**
+ * Counts the "leaf" fields of the given dataType. Informally, this is the
number of fields of
+ * non-complex data type in the tree representation of [[DataType]].
+ */
+ private def countLeaves(dataType: DataType): Int = {
+ dataType match {
+ case array: ArrayType => countLeaves(array.elementType)
+ case map: MapType => countLeaves(map.keyType) +
countLeaves(map.valueType)
+ case struct: StructType =>
+ struct.map(field => countLeaves(field.dataType)).sum
+ case _ => 1
+ }
+ }
+}
diff --git a/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
b/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
index f049e045c7..5b15faf646 100644
--- a/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
+++ b/shims/common/src/main/scala/org/apache/gluten/GlutenConfig.scala
@@ -50,6 +50,9 @@ class GlutenConfig(conf: SQLConf) extends Logging {
def enableColumnarHiveTableScan: Boolean =
conf.getConf(COLUMNAR_HIVETABLESCAN_ENABLED)
+ def enableColumnarHiveTableScanNestedColumnPruning: Boolean =
+ conf.getConf(COLUMNAR_HIVETABLESCAN_NESTED_COLUMN_PRUNING_ENABLED)
+
def enableVanillaVectorizedReaders: Boolean =
conf.getConf(VANILLA_VECTORIZED_READERS_ENABLED)
def enableColumnarHashAgg: Boolean = conf.getConf(COLUMNAR_HASHAGG_ENABLED)
@@ -865,6 +868,13 @@ object GlutenConfig {
.booleanConf
.createWithDefault(true)
+ val COLUMNAR_HIVETABLESCAN_NESTED_COLUMN_PRUNING_ENABLED =
+
buildConf("spark.gluten.sql.columnar.enableNestedColumnPruningInHiveTableScan")
+ .internal()
+ .doc("Enable or disable nested column pruning in hivetablescan.")
+ .booleanConf
+ .createWithDefault(true)
+
val VANILLA_VECTORIZED_READERS_ENABLED =
buildStaticConf("spark.gluten.sql.columnar.enableVanillaVectorizedReaders")
.internal()
diff --git
a/shims/spark32/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
b/shims/spark32/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
index 46b59ac306..f38c85a49d 100644
---
a/shims/spark32/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
+++
b/shims/spark32/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
@@ -22,12 +22,13 @@ import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.CastSupport
import org.apache.spark.sql.catalyst.catalog.HiveTableRelation
import org.apache.spark.sql.catalyst.expressions._
+import org.apache.spark.sql.catalyst.expressions.SchemaPruning.RootField
import org.apache.spark.sql.execution._
import org.apache.spark.sql.execution.metric.SQLMetrics
import org.apache.spark.sql.hive._
import org.apache.spark.sql.hive.client.HiveClientImpl
import org.apache.spark.sql.internal.SQLConf
-import org.apache.spark.sql.types.{BooleanType, DataType}
+import org.apache.spark.sql.types.{BooleanType, DataType, StructType}
import org.apache.spark.util.Utils
import org.apache.hadoop.conf.Configuration
@@ -232,4 +233,8 @@ abstract private[hive] class AbstractHiveTableScanExec(
}
override def otherCopyArgs: Seq[AnyRef] = Seq(sparkSession)
+
+ def pruneSchema(schema: StructType, requestedFields: Seq[RootField]):
StructType = {
+ SchemaPruning.pruneDataSchema(schema, requestedFields)
+ }
}
diff --git
a/shims/spark33/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
b/shims/spark33/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
index dd095f0ff2..d9b6bb936f 100644
---
a/shims/spark33/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
+++
b/shims/spark33/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
@@ -22,12 +22,13 @@ import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.CastSupport
import org.apache.spark.sql.catalyst.catalog.HiveTableRelation
import org.apache.spark.sql.catalyst.expressions._
+import org.apache.spark.sql.catalyst.expressions.SchemaPruning.RootField
import org.apache.spark.sql.execution._
import org.apache.spark.sql.execution.metric.SQLMetrics
import org.apache.spark.sql.hive._
import org.apache.spark.sql.hive.client.HiveClientImpl
import org.apache.spark.sql.internal.SQLConf
-import org.apache.spark.sql.types.{BooleanType, DataType}
+import org.apache.spark.sql.types.{BooleanType, DataType, StructType}
import org.apache.spark.util.Utils
import org.apache.hadoop.conf.Configuration
@@ -239,4 +240,8 @@ abstract private[hive] class AbstractHiveTableScanExec(
}
override def otherCopyArgs: Seq[AnyRef] = Seq(sparkSession)
+
+ def pruneSchema(schema: StructType, requestedFields: Seq[RootField]):
StructType = {
+ SchemaPruning.pruneSchema(schema, requestedFields)
+ }
}
diff --git
a/shims/spark34/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
b/shims/spark34/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
index 87aba00b0f..3521d49654 100644
---
a/shims/spark34/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
+++
b/shims/spark34/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
@@ -22,12 +22,13 @@ import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.CastSupport
import org.apache.spark.sql.catalyst.catalog.HiveTableRelation
import org.apache.spark.sql.catalyst.expressions._
+import org.apache.spark.sql.catalyst.expressions.SchemaPruning.RootField
import org.apache.spark.sql.execution._
import org.apache.spark.sql.execution.metric.SQLMetrics
import org.apache.spark.sql.hive._
import org.apache.spark.sql.hive.client.HiveClientImpl
import org.apache.spark.sql.internal.SQLConf
-import org.apache.spark.sql.types.{BooleanType, DataType}
+import org.apache.spark.sql.types.{BooleanType, DataType, StructType}
import org.apache.spark.util.Utils
import org.apache.hadoop.conf.Configuration
@@ -257,4 +258,8 @@ abstract private[hive] class AbstractHiveTableScanExec(
}
override def otherCopyArgs: Seq[AnyRef] = Seq(sparkSession)
+
+ def pruneSchema(schema: StructType, requestedFields: Seq[RootField]):
StructType = {
+ SchemaPruning.pruneSchema(schema, requestedFields)
+ }
}
diff --git
a/shims/spark35/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
b/shims/spark35/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
index 87aba00b0f..3521d49654 100644
---
a/shims/spark35/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
+++
b/shims/spark35/src/main/scala/org/apache/spark/sql/hive/execution/AbstractHiveTableScanExec.scala
@@ -22,12 +22,13 @@ import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.CastSupport
import org.apache.spark.sql.catalyst.catalog.HiveTableRelation
import org.apache.spark.sql.catalyst.expressions._
+import org.apache.spark.sql.catalyst.expressions.SchemaPruning.RootField
import org.apache.spark.sql.execution._
import org.apache.spark.sql.execution.metric.SQLMetrics
import org.apache.spark.sql.hive._
import org.apache.spark.sql.hive.client.HiveClientImpl
import org.apache.spark.sql.internal.SQLConf
-import org.apache.spark.sql.types.{BooleanType, DataType}
+import org.apache.spark.sql.types.{BooleanType, DataType, StructType}
import org.apache.spark.util.Utils
import org.apache.hadoop.conf.Configuration
@@ -257,4 +258,8 @@ abstract private[hive] class AbstractHiveTableScanExec(
}
override def otherCopyArgs: Seq[AnyRef] = Seq(sparkSession)
+
+ def pruneSchema(schema: StructType, requestedFields: Seq[RootField]):
StructType = {
+ SchemaPruning.pruneSchema(schema, requestedFields)
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]