[SPARK-36011][SQL] Disallow altering permanent views based on temporary views or UDFs

### What changes were proposed in this pull request?
PR #15764 disabled creating permanent views based on temporary views or UDFs.  But AlterViewCommand didn't block temporary objects.

### Why are the changes needed?
More robust view canonicalization.

### Does this PR introduce _any_ user-facing change?
Yes, now if you alter a permanent view based on temporary views or UDFs, the operation will fail.

### How was this patch tested?
Add new unit tests.

Closes #33204 from jerqi/alter_view.

Authored-by: RoryQi <1242949407@qq.com>
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
(cherry picked from commit e0c6b2e965)
Signed-off-by: Wenchen Fan <wenchen@databricks.com>
This commit is contained in:
RoryQi 2021-07-06 14:56:12 +08:00 committed by Wenchen Fan
parent e09feda1d2
commit 176b055c12
2 changed files with 32 additions and 2 deletions

View file

@ -259,7 +259,10 @@ case class AlterViewAsCommand(
def markAsAnalyzed(): LogicalPlan = copy(isAnalyzed = true)
override def run(session: SparkSession): Seq[Row] = {
if (session.sessionState.catalog.isTempView(name)) {
val isTemporary = session.sessionState.catalog.isTempView(name)
verifyTemporaryObjectsNotExists(session.sessionState.catalog, isTemporary, name, query)
verifyAutoGeneratedAliasesNotExists(query, isTemporary, name)
if (isTemporary) {
alterTemporaryView(session, query)
} else {
alterPermanentView(session, query)
@ -286,7 +289,6 @@ case class AlterViewAsCommand(
}
private def alterPermanentView(session: SparkSession, analyzedPlan: LogicalPlan): Unit = {
verifyAutoGeneratedAliasesNotExists(analyzedPlan, isTemporary = false, name)
val viewMeta = session.sessionState.catalog.getTableMetadata(name)
// Detect cyclic view reference on ALTER VIEW.

View file

@ -465,4 +465,32 @@ class PersistedViewTestSuite extends SQLViewTestSuite with SharedSparkSession {
}
}
}
test("SPARK-36011: Disallow altering permanent views based on temporary views or UDFs") {
import testImplicits._
withTable("t") {
(1 to 10).toDF("id").write.saveAsTable("t")
withView("v1") {
withTempView("v2") {
sql("CREATE VIEW v1 AS SELECT * FROM t")
sql("CREATE TEMPORARY VIEW v2 AS SELECT * FROM t")
var e = intercept[AnalysisException] {
sql("ALTER VIEW v1 AS SELECT * FROM v2")
}.getMessage
assert(e.contains("Not allowed to create a permanent view `default`.`v1` by " +
"referencing a temporary view v2"))
val tempFunctionName = "temp_udf"
val functionClass = "test.org.apache.spark.sql.MyDoubleAvg"
withUserDefinedFunction(tempFunctionName -> true) {
sql(s"CREATE TEMPORARY FUNCTION $tempFunctionName AS '$functionClass'")
e = intercept[AnalysisException] {
sql(s"ALTER VIEW v1 AS SELECT $tempFunctionName(id) from t")
}.getMessage
assert(e.contains("Not allowed to create a permanent view `default`.`v1` by " +
s"referencing a temporary function `$tempFunctionName`"))
}
}
}
}
}
}