@@ -2026,4 +2026,69 @@ abstract class SessionCatalogSuite extends AnalysisTest with Eventually {
20262026    assert(partitionSchema.fieldNames.toSeq ==  Seq (" year" " month" 
20272027    assert(partitionSchema.fields.length ==  2 )
20282028  }
2029+ 
2030+   test(" corrupted view metadata: mismatch between viewQueryColumnNames and schema" 
2031+     withSQLConf(" spark.sql.viewSchemaBinding.enabled" ->  " true" 
2032+       val  catalog  =  new  SessionCatalog (newBasicCatalog())
2033+       val  db  =  " test_db" 
2034+       catalog.createDatabase(newDb(db), ignoreIfExists =  false )
2035+ 
2036+       //  First create a base table for the view to reference
2037+       val  baseTable  =  CatalogTable (
2038+         identifier =  TableIdentifier (" base_table" Some (db)),
2039+         tableType =  CatalogTableType .MANAGED ,
2040+         storage =  CatalogStorageFormat .empty,
2041+         schema =  new  StructType ()
2042+           .add(" id" IntegerType )
2043+           .add(" name" StringType )
2044+           .add(" value" DoubleType )
2045+       )
2046+       catalog.createTable(baseTable, ignoreIfExists =  false )
2047+ 
2048+       //  Create a view with corrupted metadata where viewQueryColumnNames length
2049+       //  doesn't match schema length
2050+       //  We need to set the properties to define viewQueryColumnNames
2051+       val  properties  =  Map (
2052+         " view.query.out.numCols" ->  " 2" 
2053+         " view.query.out.col.0" ->  " id" 
2054+         " view.query.out.col.1" ->  " name" 
2055+         " view.schema.mode" ->  " binding" //  Ensure it's not SchemaEvolution
2056+       )
2057+       val  corruptedView  =  CatalogTable (
2058+         identifier =  TableIdentifier (" corrupted_view" Some (db)),
2059+         tableType =  CatalogTableType .VIEW ,
2060+         storage =  CatalogStorageFormat .empty,
2061+         schema =  new  StructType ()
2062+           .add(" id" IntegerType )
2063+           .add(" name" StringType )
2064+           .add(" value" DoubleType ),
2065+         viewText =  Some (" SELECT * FROM test_db.base_table" 
2066+         provider =  Some (" spark" //  Ensure it's not Hive-created
2067+         properties =  properties  //  Only 2 query column names but schema has 3 columns
2068+       )
2069+ 
2070+       catalog.createTable(corruptedView, ignoreIfExists =  false )
2071+ 
2072+       //  Verify the view was created with corrupted metadata
2073+       val  retrievedView  =  catalog.getTableMetadata(TableIdentifier (" corrupted_view" Some (db)))
2074+       assert(retrievedView.viewQueryColumnNames.length ==  2 )
2075+       assert(retrievedView.schema.length ==  3 )
2076+ 
2077+       //  Attempting to look up the view should throw an assertion error with detailed message
2078+       val  exception  =  intercept[AssertionError ] {
2079+         catalog.lookupRelation(TableIdentifier (" corrupted_view" Some (db)))
2080+       }
2081+ 
2082+       //  The expected message pattern allows for optional catalog prefix
2083+       val  expectedPattern  = 
2084+         " assertion failed: Corrupted view metadata detected for view " + 
2085+         " (\\ `\\ w+\\ `\\ .)?\\ `test_db\\ `\\ .\\ `corrupted_view\\ `\\ . " + 
2086+         " The number of view query column names 2 " + 
2087+         " does not match the number of columns in the view schema 3\\ . " + 
2088+         " View query column names: \\ [id, name\\ ], " + 
2089+         " View schema columns: \\ [id, name, value\\ ]\\ . " + 
2090+         " This indicates corrupted view metadata that needs to be repaired\\ ." 
2091+       assert(exception.getMessage.matches(expectedPattern))
2092+     }
2093+   }
20292094}
0 commit comments