[SPARK-48031][SQL] Support view schema evolution - #46267
Conversation
3520d00 to
aa89f73
Compare
7ddc1e6 to
b615e46
Compare
|
@cloud-fan @gengliangwang This is ready for an initial review. |
3d1f21f to
8996d76
Compare
a731139 to
3b67105
Compare
|
@cloud-fan @gengliangwang This is ready now. Please review. |
@srielau The PR description seems wrong. The default is |
4166648 to
179f2f9
Compare
|
+CC @shardulm94, @robreeves |
|
@cloud-fan @gengliangwang I have addressed all comments (except the "override" on the, which intelij and Wenchen appear to be of different opinions).
I don't see a good way to have one file with 4 distinct modes since they have sufficient syntax and test differences that I think "spaghetti" is more readable than trying to maximize shared text. |
1345224 to
2fdbe35
Compare
|
@cloud-fan @gengliangwang All of @cloud-fan comments have been accepted and addressed. |
|
the k8s test failure is unrelated, thanks, merging to master! |
| import org.apache.spark.sql.catalyst.dsl.expressions._ | ||
| val projectList = metadata.schema.map { field => | ||
| UpCast( | ||
| Cast( |
There was a problem hiding this comment.
Seems like this breaks non-ANSI build. Made a followup: #46614
### What changes were proposed in this pull request? This PR is a followup of #46267 that uses ANSI-enabled cast in the tests. It intentionally uses ANSI-enabled cast in `castColToType` when you look up a view. ### Why are the changes needed? In order to fix the scheduled CI build without ANSI: - https://github.com/apache/spark/actions/runs/9072308206/job/24960016975 - https://github.com/apache/spark/actions/runs/9072308206/job/24960019187 ``` [info] - look up view relation *** FAILED *** (72 milliseconds) [info] == FAIL: Plans do not match === [info] 'SubqueryAlias spark_catalog.db3.view1 'SubqueryAlias spark_catalog.db3.view1 [info] +- View (`spark_catalog`.`db3`.`view1`, ['col1, 'col2, 'a, 'b]) +- View (`spark_catalog`.`db3`.`view1`, ['col1, 'col2, 'a, 'b]) [info] +- 'Project [cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, col1, 0, 1) as int) AS col1#0, cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, col2, 0, 1) as string) AS col2#0, cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, a, 0, 1) as int) AS a#0, cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, b, 0, 1) as string) AS b#0] +- 'Project [cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, col1, 0, 1) as int) AS col1#0, cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, col2, 0, 1) as string) AS col2#0, cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, a, 0, 1) as int) AS a#0, cast(getviewcolumnbynameandordinal(`spark_catalog`.`db3`.`view1`, b, 0, 1) as string) AS b#0] [info] +- 'Project [*] +- 'Project [*] [info] +- 'UnresolvedRelation [tbl1], [], false ``` ``` [info] - look up view created before Spark 3.0 *** FAILED *** (452 milliseconds) [info] == FAIL: Plans do not match === [info] 'SubqueryAlias spark_catalog.db3.view2 'SubqueryAlias spark_catalog.db3.view2 [info] +- View (`db3`.`view2`, ['col1, 'col2, 'a, 'b]) +- View (`db3`.`view2`, ['col1, 'col2, 'a, 'b]) [info] +- 'Project [cast(getviewcolumnbynameandordinal(`db3`.`view2`, col1, 0, 1) as int) AS col1#0, cast(getviewcolumnbynameandordinal(`db3`.`view2`, col2, 0, 1) as string) AS col2#0, cast(getviewcolumnbynameandordinal(`db3`.`view2`, a, 0, 1) as int) AS a#0, cast(getviewcolumnbynameandordinal(`db3`.`view2`, b, 0, 1) as string) AS b#0] +- 'Project [cast(getviewcolumnbynameandordinal(`db3`.`view2`, col1, 0, 1) as int) AS col1#0, cast(getviewcolumnbynameandordinal(`db3`.`view2`, col2, 0, 1) as string) AS col2#0, cast(getviewcolumnbynameandordinal(`db3`.`view2`, a, 0, 1) as int) AS a#0, cast(getviewcolumnbynameandordinal(`db3`.`view2`, b, 0, 1) as string) AS b#0] [info] +- 'Project [*] +- 'Project [*] [info] +- 'UnresolvedRelation [tbl1], [], false +- 'UnresolvedRelation [tbl1], [], false (PlanTest.scala:179) ``` ### Does this PR introduce _any_ user-facing change? No, the main change has not been released yet. ### How was this patch tested? Manually ran the tests after ANSI disabled. ### Was this patch authored or co-authored using generative AI tooling? No. Closes #46614 from HyukjinKwon/SPARK-48031-followup. Authored-by: Hyukjin Kwon <gurwls223@apache.org> Signed-off-by: Hyukjin Kwon <gurwls223@apache.org>
What changes were proposed in this pull request?
Add the following syntax to CREATE VIEW... WITH SCHEMA ...:
Allow changing of the schema binding in:
The semantic is:
Schema_binding
Optionally specifies how the view adapts to changes to the schema of the query due to changes in the underlying object definitions.
This clause is not supported for temporary views.
BINDING
The view will become invalid if the query column-list changes except for the following conditions:
The column-list includes a star clause, and there are additional columns. These additional columns are ignored.
The type of one or more columns changed in a way that allows them to be safely cast to the types using implicit casting rules.
COMPENSATION
The view will become invalid if the query column list changes except for the following conditions:
The column-list includes a star clause, and there are additional columns. These additional columns are ignored.
The type of one or more columns changed in a way that allows them to be cast using explicit cast rules.
This is the default behavior.
TYPE EVOLUTION
The view will adopt any changes to types in the query column list into is own definition when such a change is detected upon reference of the view.
EVOLUTION
Behaves like TYPE EVOLUTION and also adopts changes in column names or added and dropped columns if the view does not include an explicit column list.
The view will only be invalidated if the query cannot be parsed anymore, or the optional view column_list does not match the number of expressions in the query select-list anymore.
We also introduce a new SQL Config:
spark.sql.defaultViewSchemaBinding
Control the default behavior of views when the underlying schema changes.
Valid values are:
Why are the changes needed?
Schema changes are a frequent occurrence, especially when ingesting data.
In the course of it most frequently:
The traditional SCHEMA BINDING behavior makes schema evolution very hard since it invalidates views agressively.
This causes erros, requiring user intervention.
Allowing views to be created to "roll with the punches" or tolerate changes in the underlying schema improves uptime.
Does this PR introduce any user-facing change?
Yes, this is a new feature with new grammar and a new config to influence its default.
How was this patch tested?
New tests are added
Was this patch authored or co-authored using generative AI tooling?
No