aboutsummaryrefslogtreecommitdiff
path: root/sql/core/src/test
diff options
context:
space:
mode:
authorjiangxingbo <jiangxb1987@gmail.com>2017-03-07 20:25:38 -0800
committerWenchen Fan <wenchen@databricks.com>2017-03-07 20:25:38 -0800
commitb9783a92f7ba0c3b22d7dceae7a3185de17dedcc (patch)
tree9d8c55dd20ce14862393511a07210cc98a1f3bca /sql/core/src/test
parentc96d14abae5962a7b15239319c2a151b95f7db94 (diff)
downloadspark-b9783a92f7ba0c3b22d7dceae7a3185de17dedcc.tar.gz
spark-b9783a92f7ba0c3b22d7dceae7a3185de17dedcc.tar.bz2
spark-b9783a92f7ba0c3b22d7dceae7a3185de17dedcc.zip
[SPARK-18389][SQL] Disallow cyclic view reference
## What changes were proposed in this pull request? Disallow cyclic view references, a cyclic view reference may be created by the following queries: ``` CREATE VIEW testView AS SELECT id FROM tbl CREATE VIEW testView2 AS SELECT id FROM testView ALTER VIEW testView AS SELECT * FROM testView2 ``` In the above example, a reference cycle (testView -> testView2 -> testView) exsits. We disallow cyclic view references by checking that in ALTER VIEW command, when the `analyzedPlan` contains the same `View` node with the altered view, we should prevent the behavior and throw an AnalysisException. ## How was this patch tested? Test by `SQLViewSuite.test("correctly handle a cyclic view reference")`. Author: jiangxingbo <jiangxb1987@gmail.com> Closes #17152 from jiangxb1987/cyclic-view.
Diffstat (limited to 'sql/core/src/test')
-rw-r--r--sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala35
1 files changed, 31 insertions, 4 deletions
diff --git a/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala
index 0e5a1dc6ab..2ca2206bb9 100644
--- a/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala
+++ b/sql/core/src/test/scala/org/apache/spark/sql/execution/SQLViewSuite.scala
@@ -609,12 +609,39 @@ abstract class SQLViewSuite extends QueryTest with SQLTestUtils {
}
}
- // TODO: Check for cyclic view references on ALTER VIEW.
- ignore("correctly handle a cyclic view reference") {
- withView("view1", "view2") {
+ test("correctly handle a cyclic view reference") {
+ withView("view1", "view2", "view3") {
sql("CREATE VIEW view1 AS SELECT * FROM jt")
sql("CREATE VIEW view2 AS SELECT * FROM view1")
- intercept[AnalysisException](sql("ALTER VIEW view1 AS SELECT * FROM view2"))
+ sql("CREATE VIEW view3 AS SELECT * FROM view2")
+
+ // Detect cyclic view reference on ALTER VIEW.
+ val e1 = intercept[AnalysisException] {
+ sql("ALTER VIEW view1 AS SELECT * FROM view2")
+ }.getMessage
+ assert(e1.contains("Recursive view `default`.`view1` detected (cycle: `default`.`view1` " +
+ "-> `default`.`view2` -> `default`.`view1`)"))
+
+ // Detect the most left cycle when there exists multiple cyclic view references.
+ val e2 = intercept[AnalysisException] {
+ sql("ALTER VIEW view1 AS SELECT * FROM view3 JOIN view2")
+ }.getMessage
+ assert(e2.contains("Recursive view `default`.`view1` detected (cycle: `default`.`view1` " +
+ "-> `default`.`view3` -> `default`.`view2` -> `default`.`view1`)"))
+
+ // Detect cyclic view reference on CREATE OR REPLACE VIEW.
+ val e3 = intercept[AnalysisException] {
+ sql("CREATE OR REPLACE VIEW view1 AS SELECT * FROM view2")
+ }.getMessage
+ assert(e3.contains("Recursive view `default`.`view1` detected (cycle: `default`.`view1` " +
+ "-> `default`.`view2` -> `default`.`view1`)"))
+
+ // Detect cyclic view reference from subqueries.
+ val e4 = intercept[AnalysisException] {
+ sql("ALTER VIEW view1 AS SELECT * FROM jt WHERE EXISTS (SELECT 1 FROM view2)")
+ }.getMessage
+ assert(e4.contains("Recursive view `default`.`view1` detected (cycle: `default`.`view1` " +
+ "-> `default`.`view2` -> `default`.`view1`)"))
}
}
}