DELETE support

This commit is contained in:
Alex Garcia 2024-11-14 10:37:05 -08:00
parent 8132f26f3b
commit ae601dcbc3
4 changed files with 462 additions and 6 deletions

4
TODO
View file

@ -14,9 +14,7 @@
# metadata filtering # metadata filtering
- boolean value handling - UPDATE support
- DELETE and UPDATE support
- large strings
- date/datetime - date/datetime
- later - later
- `v in (...)` handling - `v in (...)` handling

View file

@ -7462,7 +7462,7 @@ int vec0_insert_metadata_values(vec0_vtab *p, int argc, sqlite3_value ** argv, i
break; break;
} }
} }
printf("rc=%d\n", rc);
if(rc != SQLITE_OK) { if(rc != SQLITE_OK) {
} }
@ -7832,6 +7832,82 @@ cleanup:
return rc; return rc;
} }
int vec0Update_Delete_ClearMetadata(vec0_vtab *p, int metadata_idx, i64 rowid, i64 chunk_id,
u64 chunk_offset) {
int rc;
sqlite3_blob * blobValue;
vec0_metadata_column_kind kind = p->metadata_columns[metadata_idx].kind;
rc = sqlite3_blob_open(p->db, p->schemaName, p->shadowMetadataChunksNames[metadata_idx], "data", chunk_id, 1, &blobValue);
if(rc != SQLITE_OK) {
return rc;
}
switch(kind) {
case VEC0_METADATA_COLUMN_KIND_BOOLEAN: {
u8 block;
rc = sqlite3_blob_read(blobValue, &block, sizeof(u8), (int) (chunk_offset / CHAR_BIT));
if(rc != SQLITE_OK) {
goto done;
}
block &= ~(1 << (chunk_offset % CHAR_BIT));
rc = sqlite3_blob_write(blobValue, &block, sizeof(u8), chunk_offset / CHAR_BIT);
break;
}
case VEC0_METADATA_COLUMN_KIND_INTEGER: {
i64 v = 0;
rc = sqlite3_blob_write(blobValue, &v, sizeof(v), chunk_offset * sizeof(i64));
break;
}
case VEC0_METADATA_COLUMN_KIND_FLOAT: {
double v = 0;
rc = sqlite3_blob_write(blobValue, &v, sizeof(v), chunk_offset * sizeof(double));
break;
}
case VEC0_METADATA_COLUMN_KIND_TEXT: {
int n;
rc = sqlite3_blob_read(blobValue, &n, sizeof(int), chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH);
if(rc != SQLITE_OK) {
goto done;
}
u8 view[VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH];
memset(view, 0, VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH);
rc = sqlite3_blob_write(blobValue, &view, sizeof(view), chunk_offset * VEC0_METADATA_TEXT_VIEW_BUFFER_LENGTH);
if(rc != SQLITE_OK) {
goto done;
}
if(n > 12) {
const char * zSql = sqlite3_mprintf("DELETE FROM " VEC0_SHADOW_METADATA_TEXT_DATA_NAME " WHERE rowid = ?", p->schemaName, p->tableName, metadata_idx);
if(!zSql) {
rc = SQLITE_NOMEM;
goto done;
}
sqlite3_stmt * stmt;
rc = sqlite3_prepare_v2(p->db, zSql, -1, &stmt, NULL);
if(rc != SQLITE_OK) {
goto done;
}
sqlite3_bind_int64(stmt, 1, rowid);
rc = sqlite3_step(stmt);
if(rc != SQLITE_DONE) {
rc = SQLITE_ERROR;
goto done;
}
sqlite3_finalize(stmt);
}
break;
}
}
done:
int rc2 = sqlite3_blob_close(blobValue);
if(rc == SQLITE_OK) {
return rc2;
}
return rc;
}
int vec0Update_Delete(sqlite3_vtab *pVTab, sqlite3_value *idValue) { int vec0Update_Delete(sqlite3_vtab *pVTab, sqlite3_value *idValue) {
vec0_vtab *p = (vec0_vtab *)pVTab; vec0_vtab *p = (vec0_vtab *)pVTab;
int rc; int rc;
@ -7885,7 +7961,10 @@ int vec0Update_Delete(sqlite3_vtab *pVTab, sqlite3_value *idValue) {
} }
} }
// TODO delete metadata rows // 6. delete metadata
for(int i = 0; i < p->numMetadataColumns; i++) {
rc = vec0Update_Delete_ClearMetadata(p, i, rowid, chunk_id, chunk_offset);
}
return SQLITE_OK; return SQLITE_OK;
} }

View file

@ -5,6 +5,364 @@
'message': 'vec0 constructor error: More than 16 metadata columns were provided', 'message': 'vec0 constructor error: More than 16 metadata columns were provided',
}) })
# --- # ---
# name: test_deletes
OrderedDict({
'sql': 'insert into v(rowid, vector, b, n, f, t) values (?, ?, ?, ?, ?, ?)',
'rows': list([
]),
})
# ---
# name: test_deletes.1
OrderedDict({
'sql': 'insert into v(rowid, vector, b, n, f, t) values (?, ?, ?, ?, ?, ?)',
'rows': list([
]),
})
# ---
# name: test_deletes.10
dict({
'v_chunks': OrderedDict({
'sql': 'select * from v_chunks',
'rows': list([
OrderedDict({
'chunk_id': 1,
'size': 8,
'validity': b'\x02',
'rowids': b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks00': OrderedDict({
'sql': 'select * from v_metadata_chunks00',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x02',
}),
]),
}),
'v_metadata_chunks01': OrderedDict({
'sql': 'select * from v_metadata_chunks01',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks02': OrderedDict({
'sql': 'select * from v_metadata_chunks02',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x99\x99\x99\x99\x99\x01@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks03': OrderedDict({
'sql': 'select * from v_metadata_chunks03',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00test2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_text_data_03': OrderedDict({
'sql': 'select * from v_metadata_text_data_03',
'rows': list([
]),
}),
'v_rowids': OrderedDict({
'sql': 'select * from v_rowids',
'rows': list([
OrderedDict({
'rowid': 2,
'id': None,
'chunk_id': 1,
'chunk_offset': 1,
}),
]),
}),
'v_vector_chunks00': OrderedDict({
'sql': 'select * from v_vector_chunks00',
'rows': list([
OrderedDict({
'rowid': 1,
'vectors': b'\x11\x11\x11\x11""""3333\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
})
# ---
# name: test_deletes.2
OrderedDict({
'sql': 'insert into v(rowid, vector, b, n, f, t) values (?, ?, ?, ?, ?, ?)',
'rows': list([
]),
})
# ---
# name: test_deletes.3
OrderedDict({
'sql': 'select * from v',
'rows': list([
OrderedDict({
'rowid': 1,
'vector': b'\x11\x11\x11\x11',
'b': 1,
'n': 1,
'f': 1.1,
't': 'test1',
}),
OrderedDict({
'rowid': 2,
'vector': b'""""',
'b': 1,
'n': 2,
'f': 2.2,
't': 'test2',
}),
OrderedDict({
'rowid': 3,
'vector': b'3333',
'b': 1,
'n': 3,
'f': 3.3,
't': '1234567890123',
}),
]),
})
# ---
# name: test_deletes.4
dict({
'v_chunks': OrderedDict({
'sql': 'select * from v_chunks',
'rows': list([
OrderedDict({
'chunk_id': 1,
'size': 8,
'validity': b'\x07',
'rowids': b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks00': OrderedDict({
'sql': 'select * from v_metadata_chunks00',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x07',
}),
]),
}),
'v_metadata_chunks01': OrderedDict({
'sql': 'select * from v_metadata_chunks01',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks02': OrderedDict({
'sql': 'select * from v_metadata_chunks02',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x9a\x99\x99\x99\x99\x99\xf1?\x9a\x99\x99\x99\x99\x99\x01@ffffff\n@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks03': OrderedDict({
'sql': 'select * from v_metadata_chunks03',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x05\x00\x00\x00test1\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00test2\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00123456789012\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_text_data_03': OrderedDict({
'sql': 'select * from v_metadata_text_data_03',
'rows': list([
OrderedDict({
'rowid': 3,
'data': '1234567890123',
}),
]),
}),
'v_rowids': OrderedDict({
'sql': 'select * from v_rowids',
'rows': list([
OrderedDict({
'rowid': 1,
'id': None,
'chunk_id': 1,
'chunk_offset': 0,
}),
OrderedDict({
'rowid': 2,
'id': None,
'chunk_id': 1,
'chunk_offset': 1,
}),
OrderedDict({
'rowid': 3,
'id': None,
'chunk_id': 1,
'chunk_offset': 2,
}),
]),
}),
'v_vector_chunks00': OrderedDict({
'sql': 'select * from v_vector_chunks00',
'rows': list([
OrderedDict({
'rowid': 1,
'vectors': b'\x11\x11\x11\x11""""3333\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
})
# ---
# name: test_deletes.5
OrderedDict({
'sql': 'DELETE FROM v where rowid = 1',
'rows': list([
]),
})
# ---
# name: test_deletes.6
OrderedDict({
'sql': 'select * from v',
'rows': list([
OrderedDict({
'rowid': 2,
'vector': b'""""',
'b': 1,
'n': 2,
'f': 2.2,
't': 'test2',
}),
OrderedDict({
'rowid': 3,
'vector': b'3333',
'b': 1,
'n': 3,
'f': 3.3,
't': '1234567890123',
}),
]),
})
# ---
# name: test_deletes.7
dict({
'v_chunks': OrderedDict({
'sql': 'select * from v_chunks',
'rows': list([
OrderedDict({
'chunk_id': 1,
'size': 8,
'validity': b'\x06',
'rowids': b'\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks00': OrderedDict({
'sql': 'select * from v_metadata_chunks00',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x06',
}),
]),
}),
'v_metadata_chunks01': OrderedDict({
'sql': 'select * from v_metadata_chunks01',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks02': OrderedDict({
'sql': 'select * from v_metadata_chunks02',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x99\x99\x99\x99\x99\x01@ffffff\n@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_chunks03': OrderedDict({
'sql': 'select * from v_metadata_chunks03',
'rows': list([
OrderedDict({
'rowid': 1,
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00test2\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00123456789012\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
'v_metadata_text_data_03': OrderedDict({
'sql': 'select * from v_metadata_text_data_03',
'rows': list([
OrderedDict({
'rowid': 3,
'data': '1234567890123',
}),
]),
}),
'v_rowids': OrderedDict({
'sql': 'select * from v_rowids',
'rows': list([
OrderedDict({
'rowid': 2,
'id': None,
'chunk_id': 1,
'chunk_offset': 1,
}),
OrderedDict({
'rowid': 3,
'id': None,
'chunk_id': 1,
'chunk_offset': 2,
}),
]),
}),
'v_vector_chunks00': OrderedDict({
'sql': 'select * from v_vector_chunks00',
'rows': list([
OrderedDict({
'rowid': 1,
'vectors': b'\x11\x11\x11\x11""""3333\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
}),
]),
}),
})
# ---
# name: test_deletes.8
OrderedDict({
'sql': 'DELETE FROM v where rowid = 3',
'rows': list([
]),
})
# ---
# name: test_deletes.9
OrderedDict({
'sql': 'select * from v',
'rows': list([
OrderedDict({
'rowid': 2,
'vector': b'""""',
'b': 1,
'n': 2,
'f': 2.2,
't': 'test2',
}),
]),
})
# ---
# name: test_idxstr # name: test_idxstr
OrderedDict({ OrderedDict({
'sql': "select * from vec_movies where synopsis_embedding match '' and k = 0 and is_favorited = true", 'sql': "select * from vec_movies where synopsis_embedding match '' and k = 0 and is_favorited = true",

View file

@ -86,7 +86,28 @@ def test_updates(db, snapshot):
def test_deletes(db, snapshot): def test_deletes(db, snapshot):
pass db.execute(
"create virtual table v using vec0(vector float[1], b boolean, n int, f float, t text, chunk_size=8)"
)
INSERT = "insert into v(rowid, vector, b, n, f, t) values (?, ?, ?, ?, ?, ?)"
assert exec(db, INSERT, [1, b"\x11\x11\x11\x11", 1, 1, 1.1, "test1"]) == snapshot()
assert exec(db, INSERT, [2, b"\x22\x22\x22\x22", 1, 2, 2.2, "test2"]) == snapshot()
assert (
exec(db, INSERT, [3, b"\x33\x33\x33\x33", 1, 3, 3.3, "1234567890123"])
== snapshot()
)
assert exec(db, "select * from v") == snapshot()
assert vec0_shadow_table_contents(db, "v") == snapshot()
assert exec(db, "DELETE FROM v where rowid = 1") == snapshot()
assert exec(db, "select * from v") == snapshot()
assert vec0_shadow_table_contents(db, "v") == snapshot()
assert exec(db, "DELETE FROM v where rowid = 3") == snapshot()
assert exec(db, "select * from v") == snapshot()
assert vec0_shadow_table_contents(db, "v") == snapshot()
def test_knn(db, snapshot): def test_knn(db, snapshot):