srielau commented on code in PR #58317:
URL: https://github.com/apache/spark/pull/58317#discussion_r4112272174
##########
sql/core/src/test/scala/org/apache/spark/sql/connector/DataSourceV2Suite.scala:
##########
@@ -505,6 +506,51 @@ class DataSourceV2Suite extends SharedSparkSession with
AdaptiveSparkPlanHelper
}
}
+ test("SPARK-58814: catalog-less V2 writes recache both CHAR/VARCHAR scan
modes") {
+ val format = classOf[CharVarcharWritableDataSource].getName
+ val preserveConf = Seq(
+ SQLConf.PRESERVE_CHAR_VARCHAR_TYPE_INFO.key -> "true",
+ SQLConf.CHAR_VARCHAR_STANDARD_SEMANTICS.key -> "false")
+ val standardConf = Seq(SQLConf.CHAR_VARCHAR_STANDARD_SEMANTICS.key ->
"true")
+
+ withTempPath { file =>
+ val path = file.getCanonicalPath
+ def readData: DataFrame = spark.read.format(format).option("path",
path).load()
+ def appendData(c: String, v: String): Unit = {
+ Seq((c, v)).toDF("c", "v").write
+ .format(format).option("path", path).mode("append").save()
+ }
+
+ appendData("a", "x")
+ val preserveRead = withSQLConf(preserveConf: _*) {
+ val read = readData.persist(MEMORY_ONLY)
+ checkAnswer(read, Row("a", "x"))
+ read
+ }
+ val standardRead = withSQLConf(standardConf: _*) {
+ val read = readData.persist(DISK_ONLY)
+ checkAnswer(read, Row("a", "x"))
+ read
+ }
+ try {
+ appendData("b", "y")
+ withSQLConf(preserveConf: _*) {
+ checkAnswer(readData, Seq(Row("a", "x"), Row("b", "y")))
Review Comment:
Addressed in 85be94c8b98.
The catalog-less recache test now persists both bound DataFrames, appends,
and `checkAnswer`s those retained frames (first collect after recache, under
the matching scan-mode conf so the VARCHAR encoder is valid). Storage-level
lookups remain. Mutation matching ignores Table identity and extra write
options and uses catalog/identifier or catalog-less name plus path, so
`getTable()` writes hit the cached read relation.
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/CacheManager.scala:
##########
@@ -422,7 +523,9 @@ class CacheManager extends Logging with
AdaptiveSparkPlanHelper {
case r @ ExtractV2CatalogAndIdentifier(catalog, ident) if
r.timeTravelSpec.isEmpty =>
val table = CatalogV2Util.getTable(catalog, ident, options =
r.options)
if (r.table.id == table.id) {
- Some(DataSourceV2Relation.create(table, Some(catalog),
Some(ident), r.options))
+ Some(DataSourceV2Relation
Review Comment:
Addressed in 85be94c8b98.
`tryRebuildCacheEntry` clones a session, applies
`CharVarcharScanMode.configure` for the captured mode, refreshes the plan, and
creates a new `QueryExecution` with `refreshPhaseEnabled = false` under that
session. Rename restoration uses the same helper, so a SparkStandard
write/refresh cannot attach a SparkStandard Project to a PreserveNative cache
key.
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/RelationResolution.scala:
##########
@@ -591,7 +594,10 @@ class RelationResolution(
cached transform {
case r: DataSourceV2Relation if matchesReference(r, ref) =>
V2TableReferenceUtils.validateLoadedTable(r.table, ref)
- r.copy(output = ref.output, options = ref.options)
+ r.copy(
+ output = ref.output,
+ options = ref.options,
+ charVarcharScanMode = None)
Review Comment:
Addressed in 85be94c8b98.
Temp-view reanalysis now drops a stored analyzer-generated CHAR/VARCHAR
Project around `V2TableReference` before `resolveReference`, so
`ApplyCharTypePadding` rebinds both the scan mode and the read-side expressions
under the current SQLConf. Covered by `SPARK-58814: V2 temp view rebinds
CHAR/VARCHAR policy on lookup`, which stores a PreserveNative view over an
over-length VARCHAR and expects `EXCEED_LIMIT_LENGTH` on a SparkStandard lookup.
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/CharVarcharScanMode.scala:
##########
@@ -0,0 +1,64 @@
+/*
+ * 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.catalyst.util
+
+/**
+ * The CHAR/VARCHAR scan mode bound to a relation (and its scan) during
analysis.
+ *
+ * A relation carries `Option[CharVarcharScanMode]`: `None` means no mode was
bound, including for
+ * a relation with no CHAR/VARCHAR columns. A `Some` value pins the mode so
that `sameResult` /
+ * cache reuse keep the two variants distinct.
+ */
+private[sql] sealed trait CharVarcharScanMode
+
+/**
+ * A scan builder that accepts the CHAR/VARCHAR mode captured during relation
analysis.
+ *
+ * For example, if `SELECT c FROM t` is analyzed with standard semantics
enabled, the relation
+ * binds [[CharVarcharScanMode.SparkStandard]] before the builder creates the
physical scan.
+ */
+private[sql] trait SupportsCharVarcharScanMode {
+ def bindCharVarcharScanMode(mode: CharVarcharScanMode): Unit
+}
+
+private[sql] object CharVarcharScanMode {
+ /**
+ * Preserve the native, constrained CHAR/VARCHAR types of the source (e.g.
native ORC
+ * padding/truncation). Corresponds to preserve-only semantics.
+ */
+ case object PreserveNative extends CharVarcharScanMode
+
+ /**
+ * Request physical STRING from the source so Spark observes the original
value and applies
Review Comment:
Addressed in 85be94c8b98.
`SparkStandard` Scaladoc now says physical STRING and Spark-side length
checks apply to readers that honor the mode, and that native Hive ORC with
`CONVERT_METASTORE_ORC=false` still truncates natively.
##########
sql/catalyst/src/main/scala/org/apache/spark/sql/execution/datasources/v2/DataSourceV2Relation.scala:
##########
@@ -115,7 +115,10 @@ case class DataSourceV2Relation(
catalog: Option[CatalogPlugin],
identifier: Option[Identifier],
options: CaseInsensitiveStringMap,
- timeTravelSpec: Option[TimeTravelSpec] = None)
+ timeTravelSpec: Option[TimeTravelSpec] = None,
+ // Bound at analysis so sameResult / cache reuse distinguish preserve-only
vs standard
+ // CHAR/VARCHAR scans. None means the relation was not analyzed under
first-class types.
+ charVarcharScanMode: Option[CharVarcharScanMode] = None)
Review Comment:
Addressed in 85be94c8b98.
The catalog-less micro-batch test now `checkAnswer`s the retained
`preserveRead` and `standardRead` DataFrames after commit (first collect under
the matching scan-mode conf) and still asserts
`lookupCacheDescriptorsByV2Relation` is empty. Streaming write targets that
omit `path` match the cached read by table name so `uncacheByV2Relation`
actually invalidates both bound entries.
##########
sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/LogicalRelation.scala:
##########
@@ -41,7 +41,10 @@ case class LogicalRelation(
output: Seq[AttributeReference],
catalogTable: Option[CatalogTable],
override val isStreaming: Boolean,
- @transient stream: Option[SparkDataStream])
+ @transient stream: Option[SparkDataStream],
+ // Bound at analysis so sameResult / cache reuse distinguish preserve-only
vs standard
+ // CHAR/VARCHAR scans. None means the relation was not analyzed under
first-class types.
+ charVarcharScanMode: Option[CharVarcharScanMode])
Review Comment:
Addressed in 85be94c8b98.
The Hive ORC test no longer calls `clearCache` before `REFRESH TABLE`. Both
CONVERT_METASTORE_ORC paths keep the PreserveNative cache through refresh.
Converted `LogicalRelation` caches are checked for the rewritten padded value;
native `HiveTableRelation` still asserts the PreserveNative cache remains and
SparkStandard stays uncached.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]