Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bb12708
[SPARK-58945][SQL] Fix `messageParameters` keys that do not match the…
subhramit Aug 23, 2026
6cc8eb3
[SPARK-58945][SQL] Supply searchPath for TABLE_OR_VIEW_NOT_FOUND in H…
subhramit Aug 23, 2026
a1ec54a
[SPARK-58945][SQL] Restore the correct message template for `_LEGACY_…
subhramit Aug 23, 2026
327192b
[SPARK-58945][SQL] Inline the SparkThrowable cast to match existing t…
subhramit Aug 23, 2026
970f868
[SPARK-58945][SQL] Test the H2 dialect directly since loadTable is in…
subhramit Aug 23, 2026
ec20e15
SPARK-58945][SQL] Put imports in one line in JDBCTableCatalogSuite
subhramit Aug 23, 2026
7e78270
[SPARK-58945][SQL] Fix CURSOR_OUTSIDE_SCRIPT message parameters
subhramit Aug 31, 2026
6bd5bec
[SPARK-58945][SQL] Add cursor outside script test
subhramit Aug 31, 2026
e37e909
[SPARK-58945][SQL] Reuse empty search path rendering in H2Dialect
subhramit Aug 31, 2026
9a47641
[SPARK-58945][SQL] Use csv in invalid extension errors
subhramit Aug 31, 2026
bdec4c9
[SPARK-58945][SQL] Move error parameter tests to owning suite
subhramit Aug 31, 2026
4faca26
[SPARK-58945][SQL] Fix import order in QueryCompilationErrorsSuite
subhramit Aug 31, 2026
4886995
[SPARK-58945][SQL] Lint: Group imports in QueryCompilationErrorsSuite
subhramit Aug 31, 2026
7e4262a
[SPARK-58945][SQL] Fix H2 rename table-not-found error
subhramit Sep 4, 2026
b524b6e
[SPARK-58945][SQL] Fix semi-structured parse syntax error params
subhramit Sep 4, 2026
2c7626a
[SPARK-58945][SQL] Remove obsolete imports in JDBCTableCatalogSuite
subhramit Sep 4, 2026
856cc11
[SPARK-58945][SQL] Fix semi-structured extract parser test
subhramit Sep 5, 2026
fecb36e
[SPARK-58945][SQL] Assert semi-structured extract parse context
subhramit Sep 5, 2026
c4237cf
[SPARK-58945][SQL] Fix non-foldable interval input error params
subhramit Sep 5, 2026
9059389
[SPARK-58945][SQL] Update interval input error test expectations
subhramit Sep 5, 2026
d2809f8
Retrigger CI
subhramit Sep 5, 2026
a2f3be1
Retrigger CI
subhramit Sep 5, 2026
fe4db40
Retrigger CI again
subhramit Sep 5, 2026
09a8f0d
Merge branch 'master' into SPARK-58945
subhramit Sep 5, 2026
54d369c
Retrigger CI
subhramit Sep 5, 2026
a4bb0ad
[SPARK-58945][SQL] Fix error condition parameters
subhramit Sep 7, 2026
2bde57a
Retrigger CI
subhramit Sep 7, 2026
a66d0f4
Retrigger CI again
subhramit Sep 7, 2026
a63d2a2
Merge branch 'master' into SPARK-58945
subhramit Sep 7, 2026
c175dda
Retrigger CI
subhramit Sep 7, 2026
e09887a
Adjust H2 regression coverage
subhramit Sep 8, 2026
9dae75e
[SPARK-58945][SQL] Fix test
subhramit Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11723,7 +11723,7 @@
},
"_LEGACY_ERROR_TEMP_3070" : {
"message" : [
"<internalName> is a reserved column name that cannot be read in combination with <colName> column."
"Unrecognized file metadata field: <field>"
Comment thread
subhramit marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropping the template 3070 had copied from 3069 is right, and 3069 keeps the wording. What is left is the condition itself: error/README.md says You should not introduce new uncategorized errors. Instead, convert them to proper errors whenever encountering them in new code., and _LEGACY_ERROR_TEMP_3070 has no sqlState.

Reaching this throw site requires a third-party FileFormat that declares a metadata field without marking it constant or generated, since every built-in format marks them. That makes it an implementation error rather than a user error, so converting it to INTERNAL_ERROR fits better than minting a user-visible condition. Converting means touching the error-conditions.json entry and the new FileSourceCustomMetadataStructSuite case as well; if that widens this PR too far, naming the follow-up JIRA in the description would do, and the other comment about the <field> rendering then follows the same route.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it's better if we keep this PR scoped to fixing the broken existing path and leave reclassification of _LEGACY_ERROR_TEMP_3070 to a follow-up
I can raise a ticket

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reason being, it will be semantic reclassification, not just a broken-rendering fix which I'm dealing with here

]
},
"_LEGACY_ERROR_TEMP_3071" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4675,7 +4675,7 @@ private[sql] object QueryCompilationErrors extends QueryErrorsBase with Compilat
def invalidUDFClassError(invalidClass: String): Throwable = {
new InvalidUDFClassException(
errorClass = "_LEGACY_ERROR_TEMP_2450",
messageParameters = Map("invalidClass" -> invalidClass))
messageParameters = Map("clazz" -> invalidClass))
}

def cannotInstantiateHiveFunctionError(clazz: String, e: Throwable): Throwable = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3215,8 +3215,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE
messageParameters = Map(
"functionName" -> toSQLId(functionName),
"parameter" -> toSQLId("extension"),
"fileExtension" -> toSQLId(extension),
"acceptable" -> "Extension is limited to exactly 3 letters (e.g. csv, tsv, etc...)"))
"invalidValue" -> toSQLId(extension)))
Comment thread
subhramit marked this conversation as resolved.
}

def invalidCharsetError(functionName: String, charset: String): RuntimeException = {
Expand All @@ -3240,7 +3239,7 @@ private[sql] object QueryExecutionErrors extends QueryErrorsBase with ExecutionE
def invalidWriterCommitMessageError(details: String): Throwable = {
new SparkRuntimeException(
errorClass = "INVALID_WRITER_COMMIT_MESSAGE",
messageParameters = Map("details" -> details))
messageParameters = Map("detail" -> details))
}

def codecNotAvailableError(codecName: String, availableCodecs: String): Throwable = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,9 @@ class StateStoreColumnFamilyMismatch(
extends SparkUnsupportedOperationException(
errorClass = "STATE_STORE_COLUMN_FAMILY_SCHEMA_INCOMPATIBLE",
messageParameters = Map(
"columnFamilyName" -> columnFamilyName,
"oldColumnFamilySchema" -> oldColumnFamilySchema,
"newColumnFamilySchema" -> newColumnFamilySchema))
"colFamilyName" -> columnFamilyName,
"oldSchema" -> oldColumnFamilySchema,
"newSchema" -> newColumnFamilySchema))

class StatefulProcessorCannotPerformOperationWithInvalidTimeMode(
operationType: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,12 @@ private[sql] case class H2Dialect() extends JdbcDialect with NoLegacyJDBCError {
val relationName = messageParameters.getOrElse("tableName", "")
throw new NoSuchTableException(
errorClass = "TABLE_OR_VIEW_NOT_FOUND",
messageParameters = Map("relationName" -> relationName),
messageParameters = Map(
"relationName" -> relationName,
Comment thread
subhramit marked this conversation as resolved.
// classifyException receives only pre-rendered strings, so no Spark-side
// search path exists here; "not available" matches the rendering used for
// an empty search path.
"searchPath" -> "not available"),
Comment thread
subhramit marked this conversation as resolved.
Outdated
cause = Some(e))
// SCHEMA_NOT_FOUND_1
case 90079 =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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.errors

import org.apache.spark.{SparkFunSuite, SparkRuntimeException}
import org.apache.spark.sql.catalyst.catalog.InvalidUDFClassException
import org.apache.spark.sql.execution.streaming.state.StateStoreColumnFamilyMismatch

class ErrorMessageParametersSuite extends SparkFunSuite {
Comment thread
subhramit marked this conversation as resolved.
Outdated

test("SPARK-58945: invalid writer commit message reports detail") {
checkError(
exception = QueryExecutionErrors.invalidWriterCommitMessageError("zero")
.asInstanceOf[SparkRuntimeException],
condition = "INVALID_WRITER_COMMIT_MESSAGE",
parameters = Map("detail" -> "zero"))
}

test("SPARK-58945: invalid UDF class error reports clazz") {
checkError(
exception = QueryCompilationErrors.invalidUDFClassError("example.InvalidFunction")
.asInstanceOf[InvalidUDFClassException],
condition = "_LEGACY_ERROR_TEMP_2450",
parameters = Map("clazz" -> "example.InvalidFunction"))
}

test("SPARK-58945: state store mismatch reports schema details") {
checkError(
exception = new StateStoreColumnFamilyMismatch(
Comment thread
subhramit marked this conversation as resolved.
Outdated
"state", "old_schema", "new_schema"),
condition = "STATE_STORE_COLUMN_FAMILY_SCHEMA_INCOMPATIBLE",
parameters = Map(
"colFamilyName" -> "state",
"oldSchema" -> "old_schema",
"newSchema" -> "new_schema"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,21 @@ class QueryExecutionErrorsSuite
(df1, df2)
}

test("SPARK-58945: invalid file extension reports invalidValue") {
Comment thread
subhramit marked this conversation as resolved.
Outdated
withTempDir { dir =>
val path = new File(dir, "data").getCanonicalPath
checkError(
exception = intercept[SparkIllegalArgumentException] {
spark.range(1).write.option("extension", "12").csv(path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSVOptions.scala:127 reads ext.size != 3 && !ext.forall(_.isLetter), so both conditions must hold before it rejects anything. All-letter values like ab and toolong, and three-character values like 123 and a/b, all pass, while the message says the extension is limited to exactly 3 letters. The intent is clearly ||. The value is concatenated into the output file name (CSVFileFormat.scala:91), so a/b puts a path separator there.

That line is not part of this PR, and 12 is just one of the values the current condition does reject. Flipping && to || and adding an ab case is the cheap fix. If that is out of scope, a separate ticket plus a comment in the test saying which shapes are actually covered would do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see #58226 where I already covered this. That fix is based on this PR as otherwise only INTERNAL_ERROR was being surfaced.

For now, I clarified the test scope in 9a47641

},
condition = "INVALID_PARAMETER_VALUE.EXTENSION",
parameters = Map(
"functionName" -> "`extension`",
Comment thread
subhramit marked this conversation as resolved.
Outdated
"parameter" -> "`extension`",
"invalidValue" -> "`12`"))
}
}

test("INVALID_PARAMETER_VALUE.AES_KEY_LENGTH: invalid key lengths in AES functions") {
val (df1, df2) = getAesInputs()
def checkInvalidKeyLength(df: => DataFrame, inputBytes: Int): Unit = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import java.io.File

import org.apache.hadoop.fs.{FileStatus, Path}

import org.apache.spark.sql.Row
import org.apache.spark.sql.{AnalysisException, Row}
import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.expressions.{Expression, FileSourceConstantMetadataStructField, FileSourceGeneratedMetadataStructField, Literal}
import org.apache.spark.sql.catalyst.util.GenericArrayData
Expand Down Expand Up @@ -413,6 +413,21 @@ class FileSourceCustomMetadataStructSuite extends SharedSparkSession {
Row(1, 112L, 1L, f1.getLen, f1.getPath.getName)))
}
}

test("SPARK-58945: invalid file metadata fields report the field") {
withTempData("parquet", FILE_SCHEMA) { (_, f0, f1) =>
val invalidField = StructField("bad", StringType)
val format = new TestFileFormat(Seq(invalidField))
val df = createDF(format, Seq(FileStatusWithMetadata(f0), FileStatusWithMetadata(f1)))

checkError(
exception = intercept[AnalysisException] {
df.select("_metadata.bad").collect()
},
condition = "_LEGACY_ERROR_TEMP_3070",
parameters = Map("field" -> invalidField.toString))
Comment thread
subhramit marked this conversation as resolved.
}
}
}

object FileSourceCustomMetadataStructSuite {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*/
package org.apache.spark.sql.execution.datasources.v2.jdbc

import java.sql.{Connection, DriverManager}
import java.sql.{Connection, DriverManager, SQLException}
import java.util.Properties

import scala.jdk.CollectionConverters._
Expand All @@ -25,13 +25,14 @@ import org.apache.logging.log4j.Level

import org.apache.spark.{SparkConf, SparkIllegalArgumentException, SparkRuntimeException}
import org.apache.spark.sql.{AnalysisException, Row}
import org.apache.spark.sql.catalyst.analysis.{NoSuchNamespaceException, TableAlreadyExistsException}
import org.apache.spark.sql.catalyst.analysis.{NoSuchNamespaceException, NoSuchTableException, TableAlreadyExistsException}
import org.apache.spark.sql.catalyst.parser.ParseException
import org.apache.spark.sql.catalyst.util.CharVarcharUtils
import org.apache.spark.sql.connector.catalog.{Identifier, TableSummary}
import org.apache.spark.sql.errors.DataTypeErrors.{toSQLConf, toSQLStmt}
import org.apache.spark.sql.execution.columnar.InMemoryTableScanExec
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.jdbc.H2Dialect
import org.apache.spark.sql.test.SharedSparkSession
import org.apache.spark.sql.types._
import org.apache.spark.sql.util.CaseInsensitiveStringMap
Expand Down Expand Up @@ -229,6 +230,21 @@ class JDBCTableCatalogSuite extends SharedSparkSession {
}
}

test("SPARK-58945: H2 dialect supplies searchPath for TABLE_OR_VIEW_NOT_FOUND") {
val e = intercept[NoSuchTableException] {
H2Dialect().classifyException(
new SQLException("""Table "NOT_EXISTING_TABLE" not found""", "42S02", 42102),
condition = "FAILED_JDBC.LOAD_TABLE",
Comment thread
subhramit marked this conversation as resolved.
Outdated
messageParameters = Map("tableName" -> "`test`.`not_existing_table`"),
description = "Failed to load table: [test, not_existing_table]",
isRuntime = false)
}
checkErrorTableNotFoundWithSearchPath(
e,
"`test`.`not_existing_table`",
searchPath = "not available")
}

test("create a table") {
withTable("h2.test.new_table") {
sql("CREATE TABLE h2.test.new_table(i INT, j STRING)")
Expand Down