Skip to content

Commit ad766c4

Browse files
committed
refine errors for vector search
1 parent 21f405b commit ad766c4

File tree

7 files changed

+113
-103
lines changed

7 files changed

+113
-103
lines changed

libsql-sqlite3/src/vector.c

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,22 @@ float vectorDistanceL2(const Vector *pVector1, const Vector *pVector2){
130130
return 0;
131131
}
132132

133+
const char *sqlite3_type_repr(int type){
134+
switch( type ){
135+
case SQLITE_NULL:
136+
return "NULL";
137+
case SQLITE_INTEGER:
138+
return "INTEGER";
139+
case SQLITE_FLOAT:
140+
return "FLOAT";
141+
case SQLITE_BLOB:
142+
return "BLOB";
143+
case SQLITE_TEXT:
144+
return "TEXT";
145+
default:
146+
return "UNKNOWN";
147+
}
148+
}
133149
/*
134150
* Parses vector from text representation (e.g. '[1,2,3]'); vector type must be set
135151
*/
@@ -149,26 +165,22 @@ static int vectorParseSqliteText(
149165
int iBuf = 0;
150166

151167
assert( pVector->type == VECTOR_TYPE_FLOAT32 || pVector->type == VECTOR_TYPE_FLOAT64 );
168+
assert( sqlite3_value_type(arg) == SQLITE_TEXT );
152169

153170
if( pVector->type == VECTOR_TYPE_FLOAT32 ){
154171
elemsFloat = pVector->data;
155172
} else if( pVector->type == VECTOR_TYPE_FLOAT64 ){
156173
elemsDouble = pVector->data;
157174
}
158175

159-
if( sqlite3_value_type(arg) != SQLITE_TEXT ){
160-
*pzErrMsg = sqlite3_mprintf("invalid vector: not a text type");
161-
goto error;
162-
}
163-
164176
pzText = sqlite3_value_text(arg);
165177
if ( pzText == NULL ) return 0;
166178

167179
while( sqlite3Isspace(*pzText) )
168180
pzText++;
169181

170182
if( *pzText != '[' ){
171-
*pzErrMsg = sqlite3_mprintf("invalid vector: doesn't start with '['");
183+
*pzErrMsg = sqlite3_mprintf("invalid vector: must start with '['");
172184
goto error;
173185
}
174186
pzText++;
@@ -183,7 +195,7 @@ static int vectorParseSqliteText(
183195
}
184196
if( this != ',' && this != ']' ){
185197
if( iBuf > MAX_FLOAT_CHAR_SZ ){
186-
*pzErrMsg = sqlite3_mprintf("float too big while parsing vector: '%s'", valueBuf);
198+
*pzErrMsg = sqlite3_mprintf("invalid vector: float string length exceeded %d characters: '%s'", MAX_FLOAT_CHAR_SZ, valueBuf);
187199
goto error;
188200
}
189201
valueBuf[iBuf++] = this;
@@ -194,11 +206,11 @@ static int vectorParseSqliteText(
194206
break;
195207
}
196208
if( sqlite3AtoF(valueBuf, &elem, iBuf, SQLITE_UTF8) <= 0 ){
197-
*pzErrMsg = sqlite3_mprintf("invalid number: '%s'", valueBuf);
209+
*pzErrMsg = sqlite3_mprintf("invalid vector: invalid float at position %d: '%s'", iElem, valueBuf);
198210
goto error;
199211
}
200212
if( iElem >= MAX_VECTOR_SZ ){
201-
*pzErrMsg = sqlite3_mprintf("vector is larger than the maximum: (%d)", MAX_VECTOR_SZ);
213+
*pzErrMsg = sqlite3_mprintf("invalid vector: max size exceeded %d", MAX_VECTOR_SZ);
202214
goto error;
203215
}
204216
// clear only first bufidx positions - all other are zero
@@ -217,7 +229,7 @@ static int vectorParseSqliteText(
217229
pzText++;
218230

219231
if( *pzText != ']' ){
220-
*pzErrMsg = sqlite3_mprintf("malformed vector, doesn't end with ']'");
232+
*pzErrMsg = sqlite3_mprintf("invalid vector: must end with ']'");
221233
goto error;
222234
}
223235
pzText++;
@@ -226,7 +238,7 @@ static int vectorParseSqliteText(
226238
pzText++;
227239

228240
if( *pzText != '\0' ){
229-
*pzErrMsg = sqlite3_mprintf("malformed vector, extra data after closing ']'");
241+
*pzErrMsg = sqlite3_mprintf("invalid vector: non-space symbols after closing ']' are forbidden");
230242
goto error;
231243
}
232244
pVector->dims = iElem;
@@ -271,11 +283,11 @@ int detectBlobVectorParameters(sqlite3_value *arg, int *pType, int *pDims, char
271283
} else if( *pType == VECTOR_TYPE_FLOAT64 ){
272284
*pDims = nBlobSize / sizeof(double);
273285
} else{
274-
*pzErrMsg = sqlite3_mprintf("invalid binary vector: unexpected type: %d", *pType);
286+
*pzErrMsg = sqlite3_mprintf("invalid vector: unexpected binary type: got %d, expected %d or %d", *pType, VECTOR_TYPE_FLOAT32, VECTOR_TYPE_FLOAT64);
275287
return -1;
276288
}
277289
if( *pDims > MAX_VECTOR_SZ ){
278-
*pzErrMsg = sqlite3_mprintf("invalid binary vector: max size exceeded: %d > %d", *pDims, MAX_VECTOR_SZ);
290+
*pzErrMsg = sqlite3_mprintf("invalid vector: max size exceeded: %d > %d", *pDims, MAX_VECTOR_SZ);
279291
return -1;
280292
}
281293
return 0;
@@ -317,15 +329,12 @@ int detectTextVectorParameters(sqlite3_value *arg, int typeHint, int *pType, int
317329

318330
int detectVectorParameters(sqlite3_value *arg, int typeHint, int *pType, int *pDims, char **pzErrMsg) {
319331
switch( sqlite3_value_type(arg) ){
320-
case SQLITE_NULL:
321-
*pzErrMsg = sqlite3_mprintf("invalid vector: NULL");
322-
return -1;
323332
case SQLITE_BLOB:
324333
return detectBlobVectorParameters(arg, pType, pDims, pzErrMsg);
325334
case SQLITE_TEXT:
326335
return detectTextVectorParameters(arg, typeHint, pType, pDims, pzErrMsg);
327336
default:
328-
*pzErrMsg = sqlite3_mprintf("invalid vector: not a text or blob type");
337+
*pzErrMsg = sqlite3_mprintf("invalid vector: unexpected value type: got %s, expected TEXT or BLOB", sqlite3_type_repr(sqlite3_value_type(arg)));
329338
return -1;
330339
}
331340
}
@@ -336,15 +345,12 @@ int vectorParse(
336345
char **pzErrMsg
337346
){
338347
switch( sqlite3_value_type(arg) ){
339-
case SQLITE_NULL:
340-
*pzErrMsg = sqlite3_mprintf("invalid vector: NULL");
341-
return -1;
342348
case SQLITE_BLOB:
343349
return vectorParseSqliteBlob(arg, pVector, pzErrMsg);
344350
case SQLITE_TEXT:
345351
return vectorParseSqliteText(arg, pVector, pzErrMsg);
346352
default:
347-
*pzErrMsg = sqlite3_mprintf("invalid vector: not a text or blob type");
353+
*pzErrMsg = sqlite3_mprintf("invalid vector: unexpected value type: got %s, expected TEXT or BLOB", sqlite3_type_repr(sqlite3_value_type(arg)));
348354
return -1;
349355
}
350356
}
@@ -545,11 +551,15 @@ static void vectorDistanceCosFunc(
545551
goto out_free;
546552
}
547553
if( type1 != type2 ){
548-
sqlite3_result_error(context, "vectors must have the same type", -1);
554+
pzErrMsg = sqlite3_mprintf("vector_distance_cos: vectors must have the same type: %d != %d", type1, type2);
555+
sqlite3_result_error(context, pzErrMsg, -1);
556+
sqlite3_free(pzErrMsg);
549557
goto out_free;
550558
}
551559
if( dims1 != dims2 ){
552-
sqlite3_result_error(context, "vectors must have the same length", -1);
560+
pzErrMsg = sqlite3_mprintf("vector_distance_cos: vectors must have the same length: %d != %d", dims1, dims2);
561+
sqlite3_result_error(context, pzErrMsg, -1);
562+
sqlite3_free(pzErrMsg);
553563
goto out_free;
554564
}
555565
pVector1 = vectorContextAlloc(context, type1, dims1);

libsql-sqlite3/src/vectorIndex.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -830,9 +830,9 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co
830830
// backward compatibility: preserve old indices with deprecated syntax but forbid creation of new indices with this syntax
831831
if( pParse->db->init.busy == 0 && pUsing != NULL ){
832832
if( pIdx->zName != NULL && pTable->zName != NULL && pIdx->nKeyCol == 1 && pIdx->aiColumn != NULL && pIdx->aiColumn[0] < pTable->nCol ){
833-
sqlite3ErrorMsg(pParse, "USING syntax is deprecated, please use plain CREATE INDEX: CREATE INDEX %s ON %s ( " VECTOR_INDEX_MARKER_FUNCTION "(%s) )", pIdx->zName, pTable->zName, pTable->aCol[pIdx->aiColumn[0]].zCnName);
833+
sqlite3ErrorMsg(pParse, "vector index: USING syntax is deprecated, please use plain CREATE INDEX: CREATE INDEX %s ON %s ( " VECTOR_INDEX_MARKER_FUNCTION "(%s) )", pIdx->zName, pTable->zName, pTable->aCol[pIdx->aiColumn[0]].zCnName);
834834
} else {
835-
sqlite3ErrorMsg(pParse, "USING syntax is deprecated, please use plain CREATE INDEX: CREATE INDEX xxx ON yyy ( " VECTOR_INDEX_MARKER_FUNCTION "(zzz) )");
835+
sqlite3ErrorMsg(pParse, "vector index: USING syntax is deprecated, please use plain CREATE INDEX: CREATE INDEX xxx ON yyy ( " VECTOR_INDEX_MARKER_FUNCTION "(zzz) )");
836836
}
837837
return CREATE_FAIL;
838838
}
@@ -860,40 +860,40 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co
860860
return CREATE_IGNORE;
861861
}
862862
if( hasCollation ){
863-
sqlite3ErrorMsg(pParse, "vector index can't have collation");
863+
sqlite3ErrorMsg(pParse, "vector index: collation in expression is forbidden");
864864
return CREATE_FAIL;
865865
}
866866
if( pIdx->aColExpr->nExpr != 1 ) {
867-
sqlite3ErrorMsg(pParse, "vector index must contain exactly one column wrapped into the " VECTOR_INDEX_MARKER_FUNCTION " function");
867+
sqlite3ErrorMsg(pParse, "vector index: must contain exactly one column wrapped into the " VECTOR_INDEX_MARKER_FUNCTION " function");
868868
return CREATE_FAIL;
869869
}
870870
// we are able to support this but I doubt this works for now - more polishing required to make this work
871871
if( pIdx->pPartIdxWhere != NULL ) {
872-
sqlite3ErrorMsg(pParse, "partial vector index is not supported");
872+
sqlite3ErrorMsg(pParse, "vector index: where condition is forbidden");
873873
return CREATE_FAIL;
874874
}
875875

876876
pArgsList = pIdx->aColExpr->a[0].pExpr->x.pList;
877877
pListItem = pArgsList->a;
878878

879879
if( pArgsList->nExpr < 1 ){
880-
sqlite3ErrorMsg(pParse, VECTOR_INDEX_MARKER_FUNCTION " must contain at least one argument");
880+
sqlite3ErrorMsg(pParse, "vector idnex: " VECTOR_INDEX_MARKER_FUNCTION " must contain at least one argument");
881881
return CREATE_FAIL;
882882
}
883883
if( pListItem[0].pExpr->op != TK_COLUMN ) {
884-
sqlite3ErrorMsg(pParse, VECTOR_INDEX_MARKER_FUNCTION " first argument must be a column token");
884+
sqlite3ErrorMsg(pParse, "vector index: " VECTOR_INDEX_MARKER_FUNCTION " first argument must be a column token");
885885
return CREATE_FAIL;
886886
}
887887
iEmbeddingColumn = pListItem[0].pExpr->iColumn;
888888
if( iEmbeddingColumn < 0 ) {
889-
sqlite3ErrorMsg(pParse, VECTOR_INDEX_MARKER_FUNCTION " first argument must be column with vector type");
889+
sqlite3ErrorMsg(pParse, "vector index: " VECTOR_INDEX_MARKER_FUNCTION " first argument must be column with vector type");
890890
return CREATE_FAIL;
891891
}
892892
assert( iEmbeddingColumn >= 0 && iEmbeddingColumn < pTable->nCol );
893893

894894
zEmbeddingColumnTypeName = sqlite3ColumnType(&pTable->aCol[iEmbeddingColumn], "");
895895
if( vectorIdxParseColumnType(zEmbeddingColumnTypeName, &type, &dims, &pzErrMsg) != 0 ){
896-
sqlite3ErrorMsg(pParse, "%s: %s", pzErrMsg, zEmbeddingColumnTypeName);
896+
sqlite3ErrorMsg(pParse, "vector index: %s: %s", pzErrMsg, zEmbeddingColumnTypeName);
897897
return CREATE_FAIL;
898898
}
899899

@@ -904,25 +904,25 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co
904904

905905
rc = initVectorIndexMetaTable(db, zDbSName);
906906
if( rc != SQLITE_OK ){
907-
sqlite3ErrorMsg(pParse, "failed to init vector index meta table: %s", sqlite3_errmsg(db));
907+
sqlite3ErrorMsg(pParse, "vector index: failed to init meta table: %s", sqlite3_errmsg(db));
908908
return CREATE_FAIL;
909909
}
910910
rc = parseVectorIdxParams(pParse, &idxParams, type, dims, pListItem + 1, pArgsList->nExpr - 1);
911911
if( rc != SQLITE_OK ){
912-
sqlite3ErrorMsg(pParse, "failed to parse vector idx params");
912+
sqlite3ErrorMsg(pParse, "vector index: failed to parse binary parameters");
913913
return CREATE_FAIL;
914914
}
915915
if( vectorIdxKeyGet(pTable, &idxKey, &pzErrMsg) != 0 ){
916-
sqlite3ErrorMsg(pParse, "failed to detect underlying table key: %s", pzErrMsg);
916+
sqlite3ErrorMsg(pParse, "vector index: failed to detect underlying table key: %s", pzErrMsg);
917917
return CREATE_FAIL;
918918
}
919919
if( idxKey.nKeyColumns != 1 ){
920-
sqlite3ErrorMsg(pParse, "vector index for tables without ROWID and composite primary key are not supported");
920+
sqlite3ErrorMsg(pParse, "vector index: unsupported for tables without ROWID and composite primary key");
921921
return CREATE_FAIL;
922922
}
923923
rc = diskAnnCreateIndex(db, zDbSName, pIdx->zName, &idxKey, &idxParams);
924924
if( rc != SQLITE_OK ){
925-
sqlite3ErrorMsg(pParse, "unable to initialize diskann vector index");
925+
sqlite3ErrorMsg(pParse, "vector index: unable to initialize diskann");
926926
return CREATE_FAIL;
927927
}
928928
rc = insertIndexParameters(db, zDbSName, pIdx->zName, &idxParams);
@@ -933,7 +933,7 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co
933933
return CREATE_OK_SKIP_REFILL;
934934
}
935935
if( rc != SQLITE_OK ){
936-
sqlite3ErrorMsg(pParse, "unable to update global metadata table");
936+
sqlite3ErrorMsg(pParse, "vector index: unable to update global metadata table");
937937
return CREATE_FAIL;
938938
}
939939
return CREATE_OK;
@@ -954,7 +954,7 @@ int vectorIndexSearch(sqlite3 *db, const char* zDbSName, int argc, sqlite3_value
954954
assert( zDbSName != NULL );
955955

956956
if( argc != 3 ){
957-
*pzErrMsg = sqlite3_mprintf("vector search must have exactly 3 parameters");
957+
*pzErrMsg = sqlite3_mprintf("vector index(search): got %d parameters, expected 3", argc);
958958
rc = SQLITE_ERROR;
959959
goto out;
960960
}
@@ -963,7 +963,7 @@ int vectorIndexSearch(sqlite3 *db, const char* zDbSName, int argc, sqlite3_value
963963
goto out;
964964
}
965965
if( type != VECTOR_TYPE_FLOAT32 ){
966-
*pzErrMsg = sqlite3_mprintf("only f32 vectors are supported");
966+
*pzErrMsg = sqlite3_mprintf("vector index(search): only f32 vectors are supported");
967967
rc = SQLITE_ERROR;
968968
goto out;
969969
}
@@ -977,40 +977,40 @@ int vectorIndexSearch(sqlite3 *db, const char* zDbSName, int argc, sqlite3_value
977977
goto out;
978978
}
979979
if( sqlite3_value_type(argv[2]) != SQLITE_INTEGER ){
980-
*pzErrMsg = sqlite3_mprintf("vector search third parameter (k) must be an integer");
980+
*pzErrMsg = sqlite3_mprintf("vector index(search): third parameter (k) must be a non-negative integer");
981981
rc = SQLITE_ERROR;
982982
goto out;
983983
}
984984
k = sqlite3_value_int(argv[2]);
985985
if( k < 0 ){
986-
*pzErrMsg = sqlite3_mprintf("k must be a non-negative integer");
986+
*pzErrMsg = sqlite3_mprintf("vector index(search): third parameter (k) must be a non-negative integer");
987987
rc = SQLITE_ERROR;
988988
goto out;
989989
}
990990
if( sqlite3_value_type(argv[0]) != SQLITE_TEXT ){
991-
*pzErrMsg = sqlite3_mprintf("vector search first parameter (index) must be a string");
991+
*pzErrMsg = sqlite3_mprintf("vector index(search): first parameter (index) must be a string");
992992
rc = SQLITE_ERROR;
993993
goto out;
994994
}
995995
zIdxName = (const char*)sqlite3_value_text(argv[0]);
996996
if( vectorIndexGetParameters(db, zIdxName, &idxParams) != 0 ){
997-
*pzErrMsg = sqlite3_mprintf("failed to parse vector index parameters");
997+
*pzErrMsg = sqlite3_mprintf("vector index(search): failed to parse vector index parameters");
998998
rc = SQLITE_ERROR;
999999
goto out;
10001000
}
10011001
pIndex = sqlite3FindIndex(db, zIdxName, zDbSName);
10021002
if( pIndex == NULL ){
1003-
*pzErrMsg = sqlite3_mprintf("vector index not found");
1003+
*pzErrMsg = sqlite3_mprintf("vector index(search): index not found");
10041004
rc = SQLITE_ERROR;
10051005
goto out;
10061006
}
10071007
rc = diskAnnOpenIndex(db, zDbSName, zIdxName, &idxParams, &pDiskAnn);
10081008
if( rc != SQLITE_OK ){
1009-
*pzErrMsg = sqlite3_mprintf("failed to open diskann index");
1009+
*pzErrMsg = sqlite3_mprintf("vector index(search): failed to open diskann index");
10101010
goto out;
10111011
}
10121012
if( vectorIdxKeyGet(pIndex->pTable, &pKey, &zErrMsg) != 0 ){
1013-
*pzErrMsg = sqlite3_mprintf("failed to extract table key: %s", zErrMsg);
1013+
*pzErrMsg = sqlite3_mprintf("vector index(search): failed to extract table key: %s", zErrMsg);
10141014
rc = SQLITE_ERROR;
10151015
goto out;
10161016
}

0 commit comments

Comments
 (0)