@@ -1951,4 +1951,69 @@ abstract class SessionCatalogSuite extends AnalysisTest with Eventually {
19511951 assert(catalog.getCachedTable(qualifiedName2) != null )
19521952 }
19531953 }
1954+
1955+ test(" corrupted view metadata: mismatch between viewQueryColumnNames and schema" ) {
1956+ withSQLConf(" spark.sql.viewSchemaBinding.enabled" -> " true" ) {
1957+ val catalog = new SessionCatalog (newBasicCatalog())
1958+ val db = " test_db"
1959+ catalog.createDatabase(newDb(db), ignoreIfExists = false )
1960+
1961+ // First create a base table for the view to reference
1962+ val baseTable = CatalogTable (
1963+ identifier = TableIdentifier (" base_table" , Some (db)),
1964+ tableType = CatalogTableType .MANAGED ,
1965+ storage = CatalogStorageFormat .empty,
1966+ schema = new StructType ()
1967+ .add(" id" , IntegerType )
1968+ .add(" name" , StringType )
1969+ .add(" value" , DoubleType )
1970+ )
1971+ catalog.createTable(baseTable, ignoreIfExists = false )
1972+
1973+ // Create a view with corrupted metadata where viewQueryColumnNames length
1974+ // doesn't match schema length
1975+ // We need to set the properties to define viewQueryColumnNames
1976+ val properties = Map (
1977+ " view.query.out.numCols" -> " 2" ,
1978+ " view.query.out.col.0" -> " id" ,
1979+ " view.query.out.col.1" -> " name" ,
1980+ " view.schema.mode" -> " binding" // Ensure it's not SchemaEvolution
1981+ )
1982+ val corruptedView = CatalogTable (
1983+ identifier = TableIdentifier (" corrupted_view" , Some (db)),
1984+ tableType = CatalogTableType .VIEW ,
1985+ storage = CatalogStorageFormat .empty,
1986+ schema = new StructType ()
1987+ .add(" id" , IntegerType )
1988+ .add(" name" , StringType )
1989+ .add(" value" , DoubleType ),
1990+ viewText = Some (" SELECT * FROM test_db.base_table" ),
1991+ provider = Some (" spark" ), // Ensure it's not Hive-created
1992+ properties = properties // Only 2 query column names but schema has 3 columns
1993+ )
1994+
1995+ catalog.createTable(corruptedView, ignoreIfExists = false )
1996+
1997+ // Verify the view was created with corrupted metadata
1998+ val retrievedView = catalog.getTableMetadata(TableIdentifier (" corrupted_view" , Some (db)))
1999+ assert(retrievedView.viewQueryColumnNames.length == 2 )
2000+ assert(retrievedView.schema.length == 3 )
2001+
2002+ // Attempting to look up the view should throw an assertion error with detailed message
2003+ val exception = intercept[AssertionError ] {
2004+ catalog.lookupRelation(TableIdentifier (" corrupted_view" , Some (db)))
2005+ }
2006+
2007+ // The expected message pattern allows for optional catalog prefix
2008+ val expectedPattern =
2009+ " assertion failed: Corrupted view metadata detected for view " +
2010+ " (\\ `\\ w+\\ `\\ .)?\\ `test_db\\ `\\ .\\ `corrupted_view\\ `\\ . " +
2011+ " The number of view query column names 2 " +
2012+ " does not match the number of columns in the view schema 3\\ . " +
2013+ " View query column names: \\ [id, name\\ ], " +
2014+ " View schema columns: \\ [id, name, value\\ ]\\ . " +
2015+ " This indicates corrupted view metadata that needs to be repaired\\ ."
2016+ assert(exception.getMessage.matches(expectedPattern))
2017+ }
2018+ }
19542019}
0 commit comments