diff --git a/libsql-ffi/bundled/bindings/bindgen.rs b/libsql-ffi/bundled/bindings/bindgen.rs index 343361ba38..cf25a88564 100644 --- a/libsql-ffi/bundled/bindings/bindgen.rs +++ b/libsql-ffi/bundled/bindings/bindgen.rs @@ -23,7 +23,6 @@ extern "C" { ) -> ::std::os::raw::c_int; } -pub const __GNUC_VA_LIST: i32 = 1; pub const SQLITE_VERSION: &[u8; 7] = b"3.45.1\0"; pub const SQLITE_VERSION_NUMBER: i32 = 3045001; pub const SQLITE_SOURCE_ID: &[u8; 85] = @@ -502,8 +501,8 @@ pub const FTS5_TOKENIZE_DOCUMENT: i32 = 4; pub const FTS5_TOKENIZE_AUX: i32 = 8; pub const FTS5_TOKEN_COLOCATED: i32 = 1; pub const WAL_SAVEPOINT_NDATA: i32 = 4; -pub type va_list = __builtin_va_list; -pub type __gnuc_va_list = __builtin_va_list; +pub type __gnuc_va_list = [u64; 4usize]; +pub type va_list = [u64; 4usize]; extern "C" { pub static sqlite3_version: [::std::os::raw::c_char; 0usize]; } @@ -940,7 +939,7 @@ extern "C" { extern "C" { pub fn sqlite3_vmprintf( arg1: *const ::std::os::raw::c_char, - arg2: *mut __va_list_tag, + arg2: va_list, ) -> *mut ::std::os::raw::c_char; } extern "C" { @@ -956,7 +955,7 @@ extern "C" { arg1: ::std::os::raw::c_int, arg2: *mut ::std::os::raw::c_char, arg3: *const ::std::os::raw::c_char, - arg4: *mut __va_list_tag, + arg4: va_list, ) -> *mut ::std::os::raw::c_char; } extern "C" { @@ -2506,7 +2505,7 @@ extern "C" { pub fn sqlite3_str_vappendf( arg1: *mut sqlite3_str, zFormat: *const ::std::os::raw::c_char, - arg2: *mut __va_list_tag, + arg2: va_list, ); } extern "C" { @@ -3574,12 +3573,3 @@ extern "C" { extern "C" { pub static sqlite3_wal_manager: libsql_wal_manager; } -pub type __builtin_va_list = [__va_list_tag; 1usize]; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __va_list_tag { - pub gp_offset: ::std::os::raw::c_uint, - pub fp_offset: ::std::os::raw::c_uint, - pub overflow_arg_area: *mut ::std::os::raw::c_void, - pub reg_save_area: *mut ::std::os::raw::c_void, -} diff --git a/libsql-ffi/bundled/src/sqlite3.c b/libsql-ffi/bundled/src/sqlite3.c index 265c94ad12..e15910b14e 100644 --- a/libsql-ffi/bundled/src/sqlite3.c +++ b/libsql-ffi/bundled/src/sqlite3.c @@ -85618,6 +85618,16 @@ float vectorFB16DistanceL2(const Vector *, const Vector *); float vectorF32DistanceL2 (const Vector *, const Vector *); double vectorF64DistanceL2(const Vector *, const Vector *); +/* + * Add/sub vectors +*/ +void vectorAdd (Vector *, const Vector *); +void vectorF32Add(Vector *, const Vector *); +void vectorF64Add(Vector *, const Vector *); +void vectorSub (Vector *, const Vector *); +void vectorF32Sub(Vector *, const Vector *); +void vectorF64Sub(Vector *, const Vector *); + /* * Serializes vector to the sqlite_blob in little-endian format according to the IEEE-754 standard * LibSQL can append one trailing byte in the end of final blob. This byte will be later used to determine type of the blob @@ -211619,6 +211629,32 @@ float vectorDistanceL2(const Vector *pVector1, const Vector *pVector2){ return 0; } +void vectorAdd(Vector *pVector1, const Vector *pVector2){ + assert( pVector1->type == pVector2->type ); + switch (pVector1->type) { + case VECTOR_TYPE_FLOAT32: + return vectorF32Add(pVector1, pVector2); + case VECTOR_TYPE_FLOAT64: + return vectorF64Add(pVector1, pVector2); + default: + assert(0); + } + return; +} + +void vectorSub(Vector *pVector1, const Vector *pVector2){ + assert( pVector1->type == pVector2->type ); + switch (pVector1->type) { + case VECTOR_TYPE_FLOAT32: + return vectorF32Sub(pVector1, pVector2); + case VECTOR_TYPE_FLOAT64: + return vectorF64Sub(pVector1, pVector2); + default: + assert(0); + } + return; +} + SQLITE_API const char *sqlite3_type_repr(int type){ switch( type ){ case SQLITE_NULL: @@ -212709,6 +212745,130 @@ static void vectorDistanceL2Func(sqlite3_context *context, int argc, sqlite3_val vectorDistanceFunc(context, argc, argv, vectorDistanceL2); } +/* +** Implementation of vector_add(X, Y) function. +*/ +static void vectorAddFn(sqlite3_context *context, int argc, sqlite3_value **argv){ + char *pzErrMsg = NULL; + Vector *pVector1 = NULL, *pVector2 = NULL; + int type1, type2; + int dims1, dims2; + if( argc < 2 ) { + return; + } + if( detectVectorParameters(argv[0], 0, &type1, &dims1, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( detectVectorParameters(argv[1], 0, &type2, &dims2, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( type1 != type2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same type: %d != %d", type1, type2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( dims1 != dims2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same length: %d != %d", dims1, dims2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + pVector1 = vectorContextAlloc(context, type1, dims1); + if( pVector1==NULL ){ + goto out_free; + } + pVector2 = vectorContextAlloc(context, type2, dims2); + if( pVector2==NULL ){ + goto out_free; + } + if( vectorParseWithType(argv[0], pVector1, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( vectorParseWithType(argv[1], pVector2, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + vectorAdd(pVector1, pVector2); + vectorSerializeWithMeta(context, pVector1); +out_free: + if( pVector2 ){ + vectorFree(pVector2); + } + if( pVector1 ){ + vectorFree(pVector1); + } +} + +/* +** Implementation of vector_sub(X, Y) function. +*/ +static void vectorSubFn(sqlite3_context *context, int argc, sqlite3_value **argv){ + char *pzErrMsg = NULL; + Vector *pVector1 = NULL, *pVector2 = NULL; + int type1, type2; + int dims1, dims2; + if( argc < 2 ) { + return; + } + if( detectVectorParameters(argv[0], 0, &type1, &dims1, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( detectVectorParameters(argv[1], 0, &type2, &dims2, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( type1 != type2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same type: %d != %d", type1, type2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( dims1 != dims2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same length: %d != %d", dims1, dims2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + pVector1 = vectorContextAlloc(context, type1, dims1); + if( pVector1==NULL ){ + goto out_free; + } + pVector2 = vectorContextAlloc(context, type2, dims2); + if( pVector2==NULL ){ + goto out_free; + } + if( vectorParseWithType(argv[0], pVector1, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( vectorParseWithType(argv[1], pVector2, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + vectorSub(pVector1, pVector2); + vectorSerializeWithMeta(context, pVector1); +out_free: + if( pVector2 ){ + vectorFree(pVector2); + } + if( pVector1 ){ + vectorFree(pVector1); + } +} + /* * Marker function which is used in index creation syntax: CREATE INDEX idx ON t(libsql_vector_idx(emb)); */ @@ -212732,6 +212892,8 @@ SQLITE_PRIVATE void sqlite3RegisterVectorFunctions(void){ FUNCTION(vector_extract, 1, 0, 0, vectorExtractFunc), FUNCTION(vector_distance_cos, 2, 0, 0, vectorDistanceCosFunc), FUNCTION(vector_distance_l2, 2, 0, 0, vectorDistanceL2Func), + FUNCTION(vector_add, 2, 0, 0, vectorAddFn), + FUNCTION(vector_sub, 2, 0, 0, vectorSubFn), FUNCTION(libsql_vector_idx, -1, 0, 0, libsqlVectorIdx), }; @@ -214828,6 +214990,36 @@ float vectorF32DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } +void vectorF32Add(Vector *v1, const Vector *v2){ + float sum = 0; + float *e1 = v1->data; + float *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT32 ); + assert( v2->type == VECTOR_TYPE_FLOAT32 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] += e2[i]; + } +} + +void vectorF32Sub(Vector *v1, const Vector *v2){ + float sum = 0; + float *e1 = v1->data; + float *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT32 ); + assert( v2->type == VECTOR_TYPE_FLOAT32 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] -= e2[i]; + } +} + void vectorF32DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, @@ -215026,6 +215218,36 @@ double vectorF64DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } +void vectorF64Add(Vector *v1, const Vector *v2){ + double sum = 0; + double *e1 = v1->data; + double *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT64 ); + assert( v2->type == VECTOR_TYPE_FLOAT64 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] += e2[i]; + } +} + +void vectorF64Sub(Vector *v1, const Vector *v2){ + double sum = 0; + double *e1 = v1->data; + double *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT64 ); + assert( v2->type == VECTOR_TYPE_FLOAT64 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] -= e2[i]; + } +} + void vectorF64DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, diff --git a/libsql-sqlite3/src/vector.c b/libsql-sqlite3/src/vector.c index 51f8af5d05..cdbc8508b4 100644 --- a/libsql-sqlite3/src/vector.c +++ b/libsql-sqlite3/src/vector.c @@ -153,6 +153,32 @@ float vectorDistanceL2(const Vector *pVector1, const Vector *pVector2){ return 0; } +void vectorAdd(Vector *pVector1, const Vector *pVector2){ + assert( pVector1->type == pVector2->type ); + switch (pVector1->type) { + case VECTOR_TYPE_FLOAT32: + return vectorF32Add(pVector1, pVector2); + case VECTOR_TYPE_FLOAT64: + return vectorF64Add(pVector1, pVector2); + default: + assert(0); + } + return; +} + +void vectorSub(Vector *pVector1, const Vector *pVector2){ + assert( pVector1->type == pVector2->type ); + switch (pVector1->type) { + case VECTOR_TYPE_FLOAT32: + return vectorF32Sub(pVector1, pVector2); + case VECTOR_TYPE_FLOAT64: + return vectorF64Sub(pVector1, pVector2); + default: + assert(0); + } + return; +} + const char *sqlite3_type_repr(int type){ switch( type ){ case SQLITE_NULL: @@ -1243,6 +1269,130 @@ static void vectorDistanceL2Func(sqlite3_context *context, int argc, sqlite3_val vectorDistanceFunc(context, argc, argv, vectorDistanceL2); } +/* +** Implementation of vector_add(X, Y) function. +*/ +static void vectorAddFn(sqlite3_context *context, int argc, sqlite3_value **argv){ + char *pzErrMsg = NULL; + Vector *pVector1 = NULL, *pVector2 = NULL; + int type1, type2; + int dims1, dims2; + if( argc < 2 ) { + return; + } + if( detectVectorParameters(argv[0], 0, &type1, &dims1, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( detectVectorParameters(argv[1], 0, &type2, &dims2, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( type1 != type2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same type: %d != %d", type1, type2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( dims1 != dims2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same length: %d != %d", dims1, dims2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + pVector1 = vectorContextAlloc(context, type1, dims1); + if( pVector1==NULL ){ + goto out_free; + } + pVector2 = vectorContextAlloc(context, type2, dims2); + if( pVector2==NULL ){ + goto out_free; + } + if( vectorParseWithType(argv[0], pVector1, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( vectorParseWithType(argv[1], pVector2, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + vectorAdd(pVector1, pVector2); + vectorSerializeWithMeta(context, pVector1); +out_free: + if( pVector2 ){ + vectorFree(pVector2); + } + if( pVector1 ){ + vectorFree(pVector1); + } +} + +/* +** Implementation of vector_sub(X, Y) function. +*/ +static void vectorSubFn(sqlite3_context *context, int argc, sqlite3_value **argv){ + char *pzErrMsg = NULL; + Vector *pVector1 = NULL, *pVector2 = NULL; + int type1, type2; + int dims1, dims2; + if( argc < 2 ) { + return; + } + if( detectVectorParameters(argv[0], 0, &type1, &dims1, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( detectVectorParameters(argv[1], 0, &type2, &dims2, &pzErrMsg) != 0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( type1 != type2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same type: %d != %d", type1, type2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( dims1 != dims2 ){ + pzErrMsg = sqlite3_mprintf("vector_add: vectors must have the same length: %d != %d", dims1, dims2); + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + pVector1 = vectorContextAlloc(context, type1, dims1); + if( pVector1==NULL ){ + goto out_free; + } + pVector2 = vectorContextAlloc(context, type2, dims2); + if( pVector2==NULL ){ + goto out_free; + } + if( vectorParseWithType(argv[0], pVector1, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + if( vectorParseWithType(argv[1], pVector2, &pzErrMsg)<0 ){ + sqlite3_result_error(context, pzErrMsg, -1); + sqlite3_free(pzErrMsg); + goto out_free; + } + vectorSub(pVector1, pVector2); + vectorSerializeWithMeta(context, pVector1); +out_free: + if( pVector2 ){ + vectorFree(pVector2); + } + if( pVector1 ){ + vectorFree(pVector1); + } +} + /* * Marker function which is used in index creation syntax: CREATE INDEX idx ON t(libsql_vector_idx(emb)); */ @@ -1266,6 +1416,8 @@ void sqlite3RegisterVectorFunctions(void){ FUNCTION(vector_extract, 1, 0, 0, vectorExtractFunc), FUNCTION(vector_distance_cos, 2, 0, 0, vectorDistanceCosFunc), FUNCTION(vector_distance_l2, 2, 0, 0, vectorDistanceL2Func), + FUNCTION(vector_add, 2, 0, 0, vectorAddFn), + FUNCTION(vector_sub, 2, 0, 0, vectorSubFn), FUNCTION(libsql_vector_idx, -1, 0, 0, libsqlVectorIdx), }; diff --git a/libsql-sqlite3/src/vectorInt.h b/libsql-sqlite3/src/vectorInt.h index 81811e9faa..da6278fdc7 100644 --- a/libsql-sqlite3/src/vectorInt.h +++ b/libsql-sqlite3/src/vectorInt.h @@ -134,6 +134,16 @@ float vectorFB16DistanceL2(const Vector *, const Vector *); float vectorF32DistanceL2 (const Vector *, const Vector *); double vectorF64DistanceL2(const Vector *, const Vector *); +/* + * Add/sub vectors +*/ +void vectorAdd (Vector *, const Vector *); +void vectorF32Add(Vector *, const Vector *); +void vectorF64Add(Vector *, const Vector *); +void vectorSub (Vector *, const Vector *); +void vectorF32Sub(Vector *, const Vector *); +void vectorF64Sub(Vector *, const Vector *); + /* * Serializes vector to the sqlite_blob in little-endian format according to the IEEE-754 standard * LibSQL can append one trailing byte in the end of final blob. This byte will be later used to determine type of the blob diff --git a/libsql-sqlite3/src/vectorfloat32.c b/libsql-sqlite3/src/vectorfloat32.c index 56d022ae9c..9ccd3bdc77 100644 --- a/libsql-sqlite3/src/vectorfloat32.c +++ b/libsql-sqlite3/src/vectorfloat32.c @@ -149,6 +149,36 @@ float vectorF32DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } +void vectorF32Add(Vector *v1, const Vector *v2){ + float sum = 0; + float *e1 = v1->data; + float *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT32 ); + assert( v2->type == VECTOR_TYPE_FLOAT32 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] += e2[i]; + } +} + +void vectorF32Sub(Vector *v1, const Vector *v2){ + float sum = 0; + float *e1 = v1->data; + float *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT32 ); + assert( v2->type == VECTOR_TYPE_FLOAT32 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] -= e2[i]; + } +} + void vectorF32DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob, diff --git a/libsql-sqlite3/src/vectorfloat64.c b/libsql-sqlite3/src/vectorfloat64.c index dca6bda773..295958efb5 100644 --- a/libsql-sqlite3/src/vectorfloat64.c +++ b/libsql-sqlite3/src/vectorfloat64.c @@ -174,6 +174,36 @@ double vectorF64DistanceL2(const Vector *v1, const Vector *v2){ return sqrt(sum); } +void vectorF64Add(Vector *v1, const Vector *v2){ + double sum = 0; + double *e1 = v1->data; + double *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT64 ); + assert( v2->type == VECTOR_TYPE_FLOAT64 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] += e2[i]; + } +} + +void vectorF64Sub(Vector *v1, const Vector *v2){ + double sum = 0; + double *e1 = v1->data; + double *e2 = v2->data; + int i; + + assert( v1->dims == v2->dims ); + assert( v1->type == VECTOR_TYPE_FLOAT64 ); + assert( v2->type == VECTOR_TYPE_FLOAT64 ); + + for(i = 0; i < v1->dims; i++){ + e1[i] -= e2[i]; + } +} + void vectorF64DeserializeFromBlob( Vector *pVector, const unsigned char *pBlob,