From 1a216a684d60e87f689dd26bbf87ddf967c2641d Mon Sep 17 00:00:00 2001 From: Alex Garcia Date: Sun, 17 Nov 2024 15:12:39 -0800 Subject: [PATCH] fix aux column error when using non-default rowid values, needs test --- TODO | 1 + sqlite-vec.c | 117 ++++++++++++++++++++++++--------------------------- test.sql | 28 +++++++++++- 3 files changed, 84 insertions(+), 62 deletions(-) diff --git a/TODO b/TODO index b8e09c0..e0bcc21 100644 --- a/TODO +++ b/TODO @@ -17,6 +17,7 @@ - skip invalid validity entries in knn filter? - null! - date/datetime +- [ ] test accessing aux values when rowid is different than 1,2,3 etc. - later - `v in (...)` handling - remaining TODO items diff --git a/sqlite-vec.c b/sqlite-vec.c index 7e49fe7..db8e756 100644 --- a/sqlite-vec.c +++ b/sqlite-vec.c @@ -7680,67 +7680,6 @@ int vec0Update_Insert(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, } } - if(p->numAuxiliaryColumns > 0) { - sqlite3_stmt *stmt; - sqlite3_str * s = sqlite3_str_new(NULL); - sqlite3_str_appendf(s, "INSERT INTO " VEC0_SHADOW_AUXILIARY_NAME "(", p->schemaName, p->tableName); - for(int i = 0; i < p->numAuxiliaryColumns; i++) { - if(i!=0) { - sqlite3_str_appendchar(s, 1, ','); - } - sqlite3_str_appendf(s, "value%02d", i); - } - sqlite3_str_appendall(s, ") VALUES ("); - for(int i = 0; i < p->numAuxiliaryColumns; i++) { - if(i!=0) { - sqlite3_str_appendchar(s, 1, ','); - } - sqlite3_str_appendchar(s, 1, '?'); - } - sqlite3_str_appendall(s, ")"); - char * zSql = sqlite3_str_finish(s); - // TODO double check error handling ehre - if(!zSql) { - rc = SQLITE_NOMEM; - goto cleanup; - } - rc = sqlite3_prepare_v2(p->db, zSql, -1, &stmt, NULL); - if(rc != SQLITE_OK) { - goto cleanup; - } - - for (int i = 0; i < vec0_num_defined_user_columns(p); i++) { - if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY) { - continue; - } - int auxiliary_key_idx = p->user_column_idxs[i]; - sqlite3_value * v = argv[2+VEC0_COLUMN_USERN_START + i]; - int v_type = sqlite3_value_type(v); - if(v_type != SQLITE_NULL && (v_type != p->auxiliary_columns[auxiliary_key_idx].type)) { - sqlite3_finalize(stmt); - rc = SQLITE_ERROR; - vtab_set_error( - pVTab, - "Auxiliary column type mismatch: The auxiliary column %.*s has type %s, but %s was provided.", - p->auxiliary_columns[auxiliary_key_idx].name_length, - p->auxiliary_columns[auxiliary_key_idx].name, - type_name(p->auxiliary_columns[auxiliary_key_idx].type), - type_name(v_type) - ); - goto cleanup; - } - sqlite3_bind_value(stmt, 1 + auxiliary_key_idx, v); - } - - rc = sqlite3_step(stmt); - if(rc != SQLITE_DONE) { - sqlite3_finalize(stmt); - rc = SQLITE_ERROR; - goto cleanup; - } - sqlite3_finalize(stmt); - } - // read all the inserted vectors into vectorDatas, validate their lengths. for (int i = 0; i < vec0_num_defined_user_columns(p); i++) { if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_VECTOR) { @@ -7832,6 +7771,62 @@ int vec0Update_Insert(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, goto cleanup; } + if(p->numAuxiliaryColumns > 0) { + sqlite3_stmt *stmt; + sqlite3_str * s = sqlite3_str_new(NULL); + sqlite3_str_appendf(s, "INSERT INTO " VEC0_SHADOW_AUXILIARY_NAME "(rowid ", p->schemaName, p->tableName); + for(int i = 0; i < p->numAuxiliaryColumns; i++) { + sqlite3_str_appendf(s, ", value%02d", i); + } + sqlite3_str_appendall(s, ") VALUES (? "); + for(int i = 0; i < p->numAuxiliaryColumns; i++) { + sqlite3_str_appendall(s, ", ?"); + } + sqlite3_str_appendall(s, ")"); + char * zSql = sqlite3_str_finish(s); + // TODO double check error handling ehre + if(!zSql) { + rc = SQLITE_NOMEM; + goto cleanup; + } + rc = sqlite3_prepare_v2(p->db, zSql, -1, &stmt, NULL); + if(rc != SQLITE_OK) { + goto cleanup; + } + sqlite3_bind_int64(stmt, 1, rowid); + + for (int i = 0; i < vec0_num_defined_user_columns(p); i++) { + if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_AUXILIARY) { + continue; + } + int auxiliary_key_idx = p->user_column_idxs[i]; + sqlite3_value * v = argv[2+VEC0_COLUMN_USERN_START + i]; + int v_type = sqlite3_value_type(v); + if(v_type != SQLITE_NULL && (v_type != p->auxiliary_columns[auxiliary_key_idx].type)) { + sqlite3_finalize(stmt); + rc = SQLITE_ERROR; + vtab_set_error( + pVTab, + "Auxiliary column type mismatch: The auxiliary column %.*s has type %s, but %s was provided.", + p->auxiliary_columns[auxiliary_key_idx].name_length, + p->auxiliary_columns[auxiliary_key_idx].name, + type_name(p->auxiliary_columns[auxiliary_key_idx].type), + type_name(v_type) + ); + goto cleanup; + } + sqlite3_bind_value(stmt, 1 + 1 + auxiliary_key_idx, v); + } + + rc = sqlite3_step(stmt); + if(rc != SQLITE_DONE) { + sqlite3_finalize(stmt); + rc = SQLITE_ERROR; + goto cleanup; + } + sqlite3_finalize(stmt); + } + for(int i = 0; i < vec0_num_defined_user_columns(p); i++) { if(p->user_column_kinds[i] != SQLITE_VEC0_USER_COLUMN_KIND_METADATA) { diff --git a/test.sql b/test.sql index c11b11a..93bb20a 100644 --- a/test.sql +++ b/test.sql @@ -1,10 +1,36 @@ .load dist/vec0 -.echo on .bail on .mode qbox +create virtual table v using vec0( + vector float[1], + +description text +); +insert into v(rowid, vector, description) values (1, '[1]', 'aaa'); +select * from v; + +.exit + +create virtual table vec_articles using vec0( + article_id integer primary key, + year integer partition key, + headline_embedding float[1], + +headline text, + +url text, + word_count integer, + print_section text, + print_page integer, + pub_date text, +); + +insert into vec_articles values (1111, 2020, '[1]', 'headline', 'https://...', 200, 'A', 1, '2020-01-01'); + +select * from vec_articles; + +.exit + create table movies(movie_id integer primary key, synopsis text); INSERT INTO movies(movie_id, synopsis)