@@ -1413,36 +1413,57 @@ impl Table {
14131413 /// # Safety
14141414 ///
14151415 /// Caller must promise that `index` was constructed with the same row type/layout as this table.
1416- pub unsafe fn insert_index ( & mut self , blob_store : & dyn BlobStore , index_id : IndexId , mut index : TableIndex ) {
1416+ pub unsafe fn insert_index (
1417+ & mut self ,
1418+ blob_store : & dyn BlobStore ,
1419+ index_id : IndexId ,
1420+ mut index : TableIndex ,
1421+ ) -> Result < ( ) , String > {
14171422 let rows = self . scan_rows ( blob_store) ;
14181423 // SAFETY: Caller promised that table's row type/layout
14191424 // matches that which `index` was constructed with.
14201425 // It follows that this applies to any `rows`, as required.
14211426 let violation = unsafe { index. build_from_rows ( rows) } ;
1422- violation. unwrap_or_else ( |ptr| {
1423- let index_schema = & self . schema . indexes . iter ( ) . find ( |index_schema| index_schema. index_id == index_id) . expect ( "Index should exist" ) ;
1424- let indexed_column = if let IndexAlgorithm :: BTree ( BTreeAlgorithm { columns } ) = & index_schema. index_algorithm {
1425- Some ( columns)
1426- } else { None } ;
1427- let indexed_column = indexed_column. and_then ( |columns| columns. as_singleton ( ) ) ;
1428- let indexed_column_info = indexed_column. and_then ( |column| self . schema . get_column ( column. idx ( ) ) ) ;
1427+ violation. map_err ( |ptr| {
14291428 // SAFETY: `ptr` just came out of `self.scan_rows`, so it is present.
14301429 let row = unsafe { self . get_row_ref_unchecked ( blob_store, ptr) } . to_product_value ( ) ;
1431- panic ! (
1432- "Adding index `{}` {:?} to table `{}` {:?} on column `{}` {:?} should cause no unique constraint violations.
1433-
1434- Found violation at pointer {ptr:?} to row {:?}." ,
1435- index_schema. index_name,
1436- index_schema. index_id,
1437- self . schema. table_name,
1438- self . schema. table_id,
1439- indexed_column_info. map( |column| & column. col_name[ ..] ) . unwrap_or( "unknown column" ) ,
1440- indexed_column,
1441- row,
1442- ) ;
1443- } ) ;
1430+
1431+ if let Some ( index_schema) = self . schema . indexes . iter ( ) . find ( |index_schema| index_schema. index_id == index_id) {
1432+ let indexed_column = if let IndexAlgorithm :: BTree ( BTreeAlgorithm { columns } ) = & index_schema. index_algorithm {
1433+ Some ( columns)
1434+ } else {
1435+ None
1436+ } ;
1437+ let indexed_column = indexed_column. and_then ( |columns| columns. as_singleton ( ) ) ;
1438+ let indexed_column_info = indexed_column. and_then ( |column| self . schema . get_column ( column. idx ( ) ) ) ;
1439+
1440+ format ! (
1441+ "Adding index `{}` {:?} to table `{}` {:?} on column `{}` {:?} should cause no unique constraint violations.\
1442+ Found violation at pointer {ptr:?} to row {:?}.",
1443+ index_schema. index_name,
1444+ index_schema. index_id,
1445+ self . schema. table_name,
1446+ self . schema. table_id,
1447+ indexed_column_info. map( |column| & column. col_name[ ..] ) . unwrap_or( "unknown column" ) ,
1448+ indexed_column,
1449+ row,
1450+ )
1451+ } else {
1452+ format ! (
1453+ "Adding index to table `{}` {:?} on columns `{:?}` with key type {:?} should cause no unique constraint violations.\
1454+ Found violation at pointer {ptr:?} to row {:?}.",
1455+ self . schema. table_name,
1456+ self . schema. table_id,
1457+ index. indexed_columns,
1458+ index. key_type,
1459+ row,
1460+ )
1461+ }
1462+ } ) ?;
1463+
14441464 // SAFETY: Forward caller requirement.
14451465 unsafe { self . add_index ( index_id, index) } ;
1466+ Ok ( ( ) )
14461467 }
14471468
14481469 /// Adds an index to the table without populating.
@@ -2453,7 +2474,7 @@ pub(crate) mod test {
24532474
24542475 let index = table. new_index ( & algo, true ) . unwrap ( ) ;
24552476 // SAFETY: Index was derived from `table`.
2456- unsafe { table. insert_index ( & NullBlobStore , index_schema. index_id , index) } ;
2477+ unsafe { table. insert_index ( & NullBlobStore , index_schema. index_id , index) } . unwrap ( ) ;
24572478
24582479 // Reserve a page so that we can check the hash.
24592480 let pi = table. inner . pages . reserve_empty_page ( & pool, table. row_size ( ) ) . unwrap ( ) ;
@@ -2553,6 +2574,8 @@ pub(crate) mod test {
25532574 ty : ProductType ,
25542575 vals : Vec < ProductValue > ,
25552576 indexed_columns : ColList ,
2577+ index_kind : IndexKind ,
2578+ is_unique : bool ,
25562579 ) -> Result < ( ) , TestCaseError > {
25572580 let pool = PagePool :: new_for_test ( ) ;
25582581 let mut blob_store = HashMapBlobStore :: default ( ) ;
@@ -2565,13 +2588,13 @@ pub(crate) mod test {
25652588 // We haven't added any indexes yet, so there should be 0 rows in indexes.
25662589 prop_assert_eq ! ( table. num_rows_in_indexes( ) , 0 ) ;
25672590
2568- let index_id = IndexId ( 0 ) ;
2591+ let index_id = IndexId :: SENTINEL ;
25692592
2570- let index = TableIndex :: new ( & ty, indexed_columns. clone ( ) , IndexKind :: BTree , false ) . unwrap ( ) ;
2593+ let index = TableIndex :: new ( & ty, indexed_columns. clone ( ) , index_kind , is_unique ) . unwrap ( ) ;
25712594 // Add an index on column 0.
25722595 // Safety:
25732596 // We're using `ty` as the row type for both `table` and the new index.
2574- unsafe { table. insert_index ( & blob_store, index_id, index) } ;
2597+ prop_assume ! ( unsafe { table. insert_index( & blob_store, index_id, index) } . is_ok ( ) ) ;
25752598
25762599 // We have one index, which should be fully populated,
25772600 // so in total we should have the same number of rows in indexes as we have rows.
@@ -2602,7 +2625,8 @@ pub(crate) mod test {
26022625 // Add a duplicate of the same index, so we can check that all above quantities double.
26032626 // Safety:
26042627 // As above, we're using `ty` as the row type for both `table` and the new index.
2605- unsafe { table. insert_index ( & blob_store, IndexId ( 1 ) , index) } ;
2628+ unsafe { table. insert_index ( & blob_store, IndexId ( 1 ) , index) }
2629+ . expect ( "already inserted this index, should not error" ) ;
26062630
26072631 prop_assert_eq ! ( table. num_rows_in_indexes( ) , table. num_rows( ) * 2 ) ;
26082632 prop_assert_eq ! ( table. bytes_used_by_index_keys( ) , key_size_in_pvs * 2 ) ;
@@ -2722,13 +2746,21 @@ pub(crate) mod test {
27222746 }
27232747
27242748 #[ test]
2725- fn index_size_reporting_matches_slow_implementations_single_column( ( ty, vals) in generate_typed_row_vec( 1 ..SIZE , 128 , 2048 ) ) {
2726- test_index_size_reporting( ty, vals, [ 0 ] . into( ) ) ?;
2749+ fn index_size_reporting_matches_slow_implementations_single_column(
2750+ ( ty, vals) in generate_typed_row_vec( 1 ..SIZE , 128 , 2048 ) ,
2751+ index_kind: IndexKind ,
2752+ is_unique: bool
2753+ ) {
2754+ test_index_size_reporting( ty, vals, [ 0 ] . into( ) , index_kind, is_unique) ?;
27272755 }
27282756
27292757 #[ test]
2730- fn index_size_reporting_matches_slow_implementations_two_column( ( ty, vals) in generate_typed_row_vec( 2 ..SIZE , 128 , 2048 ) ) {
2731- test_index_size_reporting( ty, vals, [ 0 , 1 ] . into( ) ) ?
2758+ fn index_size_reporting_matches_slow_implementations_two_column(
2759+ ( ty, vals) in generate_typed_row_vec( 2 ..SIZE , 128 , 2048 ) ,
2760+ index_kind: IndexKind ,
2761+ is_unique: bool
2762+ ) {
2763+ test_index_size_reporting( ty, vals, [ 0 , 1 ] . into( ) , index_kind, is_unique) ?
27322764 }
27332765 }
27342766
0 commit comments