diff --git a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c index dd850402d2..9d51c1d645 100644 --- a/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c +++ b/libsql-ffi/bundled/SQLite3MultipleCiphers/src/sqlite3.c @@ -214238,7 +214238,7 @@ int insertIndexParameters(sqlite3* db, const char *zDbSName, const char *zName, goto clear_and_exit; } rc = sqlite3_step(pStatement); - if( rc == SQLITE_CONSTRAINT ){ + if( (rc&0xff) == SQLITE_CONSTRAINT ){ rc = SQLITE_CONSTRAINT; }else if( rc != SQLITE_DONE ){ rc = SQLITE_ERROR; @@ -214546,7 +214546,10 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co return CREATE_FAIL; } rc = insertIndexParameters(db, zDbSName, pIdx->zName, &idxParams); - if( rc == SQLITE_CONSTRAINT ){ + + // we must consider only lower bits because with sqlite3_extended_result_codes on + // we can recieve different subtypes of CONSTRAINT error + if( (rc&0xff) == SQLITE_CONSTRAINT ){ // we are violating unique constraint here which means that someone inserted parameters in the table before us // taking aside corruption scenarios, this can be in case of loading dump (because tables and data are loaded before indices) // this case is valid and we must proceed with index creating but avoid index-refill step as it is already filled diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index dd850402d2..9d51c1d645 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -214238,7 +214238,7 @@ int insertIndexParameters(sqlite3* db, const char *zDbSName, const char *zName, goto clear_and_exit; } rc = sqlite3_step(pStatement); - if( rc == SQLITE_CONSTRAINT ){ + if( (rc&0xff) == SQLITE_CONSTRAINT ){ rc = SQLITE_CONSTRAINT; }else if( rc != SQLITE_DONE ){ rc = SQLITE_ERROR; @@ -214546,7 +214546,10 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co return CREATE_FAIL; } rc = insertIndexParameters(db, zDbSName, pIdx->zName, &idxParams); - if( rc == SQLITE_CONSTRAINT ){ + + // we must consider only lower bits because with sqlite3_extended_result_codes on + // we can recieve different subtypes of CONSTRAINT error + if( (rc&0xff) == SQLITE_CONSTRAINT ){ // we are violating unique constraint here which means that someone inserted parameters in the table before us // taking aside corruption scenarios, this can be in case of loading dump (because tables and data are loaded before indices) // this case is valid and we must proceed with index creating but avoid index-refill step as it is already filled diff --git a/libsql-server/tests/hrana/batch.rs b/libsql-server/tests/hrana/batch.rs index 68b6c43d03..f521d6295f 100644 --- a/libsql-server/tests/hrana/batch.rs +++ b/libsql-server/tests/hrana/batch.rs @@ -379,3 +379,26 @@ fn reindex_statement() { sim.run().unwrap(); } + +#[test] +fn test_simulate_vector_index_load_from_dump() { + let mut sim = turmoil::Builder::new() + .simulation_duration(Duration::from_secs(1000)) + .build(); + sim.host("primary", super::make_standalone_server); + sim.client("client", async { + let db = Database::open_remote_with_connector("http://primary:8080", "", TurmoilConnector)?; + let conn = db.connect()?; + + conn.execute("CREATE TABLE t ( v FLOAT32(2) );", ()).await?; + conn.execute("CREATE TABLE t_idx_shadow(index_key INTEGER , data BLOB, PRIMARY KEY (index_key));", ()).await?; + conn.execute("CREATE TABLE libsql_vector_meta_shadow ( name TEXT PRIMARY KEY, metadata BLOB ) WITHOUT ROWID", ()).await?; + conn.execute("INSERT INTO libsql_vector_meta_shadow VALUES ('t_idx', x'');", ()).await?; + conn.execute("INSERT INTO t VALUES (vector('[1,2]')), (vector('[2,3]'));", ()).await?; + conn.execute("CREATE INDEX t_idx ON t (libsql_vector_idx(v));", ()).await?; + + Ok(()) + }); + + sim.run().unwrap(); +} diff --git a/libsql-sqlite3/src/vectorIndex.c b/libsql-sqlite3/src/vectorIndex.c index 78266ed462..f627c98e00 100644 --- a/libsql-sqlite3/src/vectorIndex.c +++ b/libsql-sqlite3/src/vectorIndex.c @@ -629,7 +629,7 @@ int insertIndexParameters(sqlite3* db, const char *zDbSName, const char *zName, goto clear_and_exit; } rc = sqlite3_step(pStatement); - if( rc == SQLITE_CONSTRAINT ){ + if( (rc&0xff) == SQLITE_CONSTRAINT ){ rc = SQLITE_CONSTRAINT; }else if( rc != SQLITE_DONE ){ rc = SQLITE_ERROR; @@ -937,7 +937,10 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co return CREATE_FAIL; } rc = insertIndexParameters(db, zDbSName, pIdx->zName, &idxParams); - if( rc == SQLITE_CONSTRAINT ){ + + // we must consider only lower bits because with sqlite3_extended_result_codes on + // we can recieve different subtypes of CONSTRAINT error + if( (rc&0xff) == SQLITE_CONSTRAINT ){ // we are violating unique constraint here which means that someone inserted parameters in the table before us // taking aside corruption scenarios, this can be in case of loading dump (because tables and data are loaded before indices) // this case is valid and we must proceed with index creating but avoid index-refill step as it is already filled