Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -170,6 +170,36 @@ object SQLConf {
}
}

/**
* Holds information about keys that have been removed.
*
* @param key The removed config key.
* @param version Version of Spark where key was removed.
* @param defaultValue The default config value. It can be used to notice
* users that they set non-default value to an already removed config.
* @param comment Additional info regarding to the removed config.
*/
case class RemovedConfig(key: String, version: String, defaultValue: String, comment: String)

/**
* The map contains info about removed SQL configs. Keys are SQL config names,
* map values contain extra information like the version in which the config was removed,
* config's default value and a comment.
*/
val removedSQLConfigs: Map[String, RemovedConfig] = {
val configs = Seq(
RemovedConfig("spark.sql.fromJsonForceNullableSchema", "3.0.0", "true",
"It was removed to prevent errors like SPARK-23173 for non-default value."),
RemovedConfig(
"spark.sql.legacy.allowCreatingManagedTableUsingNonemptyLocation", "3.0.0", "false",
"It was removed to prevent loosing of users data for non-default value."),
RemovedConfig("spark.sql.legacy.compareDateTimestampInTimestamp", "3.0.0", "true",
"It was removed to prevent errors like SPARK-23549 for non-default value.")
)
Copy link
Member

Choose a reason for hiding this comment

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

Looks a nice feature. Just a question; any policy about when these entries will be removed in this list? We need to keep them forever, or we can remove them sometime?

Copy link
Member

Choose a reason for hiding this comment

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

I think we can remove those after few minor releases or when we bump up the major release.


Map(configs.map { cfg => cfg.key -> cfg } : _*)
}

val ANALYZER_MAX_ITERATIONS = buildConf("spark.sql.analyzer.maxIterations")
.internal()
.doc("The max number of iterations the analyzer runs.")
Expand Down
12 changes: 12 additions & 0 deletions sql/core/src/main/scala/org/apache/spark/sql/RuntimeConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package org.apache.spark.sql
import org.apache.spark.annotation.Stable
import org.apache.spark.internal.config.{ConfigEntry, OptionalConfigEntry}
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.internal.SQLConf.RemovedConfig

/**
* Runtime configuration interface for Spark. To access this, use `SparkSession.conf`.
Expand All @@ -38,6 +39,7 @@ class RuntimeConfig private[sql](sqlConf: SQLConf = new SQLConf) {
*/
def set(key: String, value: String): Unit = {
requireNonStaticConf(key)
requireDefaultValueOfRemovedConf(key, value)
sqlConf.setConfString(key, value)
}

Expand Down Expand Up @@ -156,4 +158,14 @@ class RuntimeConfig private[sql](sqlConf: SQLConf = new SQLConf) {
throw new AnalysisException(s"Cannot modify the value of a Spark config: $key")
}
}

private def requireDefaultValueOfRemovedConf(key: String, value: String): Unit = {
SQLConf.removedSQLConfigs.get(key).foreach {
case RemovedConfig(configName, version, defaultValue, comment) =>
if (value != defaultValue) {
throw new AnalysisException(
s"The SQL config '$configName' was removed in the version $version. $comment")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import org.apache.spark.sql.test.{SharedSparkSession, TestSQLContext}
import org.apache.spark.util.Utils

class SQLConfSuite extends QueryTest with SharedSparkSession {
import testImplicits._

private val testKey = "test.key.0"
private val testVal = "test.val.0"
Expand Down Expand Up @@ -320,4 +319,15 @@ class SQLConfSuite extends QueryTest with SharedSparkSession {
assert(e2.getMessage.contains("spark.sql.shuffle.partitions"))
}

test("set removed config to non-default value") {
val config = "spark.sql.fromJsonForceNullableSchema"
val defaultValue = true

spark.conf.set(config, defaultValue)

val e = intercept[AnalysisException] {
spark.conf.set(config, !defaultValue)
}
assert(e.getMessage.contains(config))
}
}