@@ -85652,7 +85652,7 @@ int vectorIdxParseColumnType(const char *, int *, int *, const char **);
85652
85652
int vectorIndexCreate(Parse*, const Index*, const char *, const IdList*);
85653
85653
int vectorIndexClear(sqlite3 *, const char *, const char *);
85654
85654
int vectorIndexDrop(sqlite3 *, const char *, const char *);
85655
- int vectorIndexSearch(sqlite3 *, const char *, int, sqlite3_value **, VectorOutRows *, int *, int *, char **);
85655
+ int vectorIndexSearch(sqlite3 *, int, sqlite3_value **, VectorOutRows *, int *, int *, char **);
85656
85656
int vectorIndexCursorInit(sqlite3 *, const char *, const char *, VectorIdxCursor **);
85657
85657
void vectorIndexCursorClose(sqlite3 *, VectorIdxCursor *, int *, int *);
85658
85658
int vectorIndexInsert(VectorIdxCursor *, const UnpackedRecord *, char **);
@@ -215829,17 +215829,25 @@ int vectorIndexTryGetParametersFromBinFormat(sqlite3 *db, const char *zSql, cons
215829
215829
215830
215830
int vectorIndexGetParameters(
215831
215831
sqlite3 *db,
215832
+ const char *zDbSName,
215832
215833
const char *zIdxName,
215833
215834
VectorIdxParams *pParams
215834
215835
) {
215835
215836
int rc = SQLITE_OK;
215837
+ assert( zDbSName != NULL );
215836
215838
215837
- static const char* zSelectSql = "SELECT metadata FROM " VECTOR_INDEX_GLOBAL_META_TABLE " WHERE name = ?";
215839
+ static const char *zSelectSqlTemplate = "SELECT metadata FROM \"%w\"." VECTOR_INDEX_GLOBAL_META_TABLE " WHERE name = ?";
215840
+ char* zSelectSql;
215841
+ zSelectSql = sqlite3_mprintf(zSelectSqlTemplate, zDbSName);
215842
+ if( zSelectSql == NULL ){
215843
+ return SQLITE_NOMEM_BKPT;
215844
+ }
215838
215845
// zSelectSqlPekkaLegacy handles the case when user created DB before 04 July 2024 (https://discord.com/channels/933071162680958986/1225560924526477322/1258367912402489397)
215839
215846
// when instead of table with binary parameters rigid schema was used for index settings
215840
215847
// we should drop this eventually - but for now we postponed this decision
215841
215848
static const char* zSelectSqlPekkaLegacy = "SELECT vector_type, block_size, dims, distance_ops FROM libsql_vector_index WHERE name = ?";
215842
215849
rc = vectorIndexTryGetParametersFromBinFormat(db, zSelectSql, zIdxName, pParams);
215850
+ sqlite3_free(zSelectSql);
215843
215851
if( rc == SQLITE_OK ){
215844
215852
return SQLITE_OK;
215845
215853
}
@@ -216022,19 +216030,46 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co
216022
216030
return CREATE_OK;
216023
216031
}
216024
216032
216033
+ // extracts schema and index name part if full index name is composite (e.g. schema_name.index_name)
216034
+ // if full index name has no schema part - function returns SQLITE_OK but leaves pzIdxDbSName and pzIdxName untouched
216035
+ int getIndexNameParts(sqlite3 *db, const char *zIdxFullName, char **pzIdxDbSName, char **pzIdxName) {
216036
+ int nFullName, nDbSName;
216037
+ const char *pDot = zIdxFullName;
216038
+ while( *pDot != '.' && *pDot != '\0' ){
216039
+ pDot++;
216040
+ }
216041
+ if( *pDot == '\0' ){
216042
+ return SQLITE_OK;
216043
+ }
216044
+ assert( *pDot == '.' );
216045
+ nFullName = sqlite3Strlen30(zIdxFullName);
216046
+ nDbSName = pDot - zIdxFullName;
216047
+ *pzIdxDbSName = sqlite3DbStrNDup(db, zIdxFullName, nDbSName);
216048
+ *pzIdxName = sqlite3DbStrNDup(db, pDot + 1, nFullName - nDbSName - 1);
216049
+ if( pzIdxName == NULL || pzIdxDbSName == NULL ){
216050
+ sqlite3DbFree(db, *pzIdxName);
216051
+ sqlite3DbFree(db, *pzIdxDbSName);
216052
+ return SQLITE_NOMEM_BKPT;
216053
+ }
216054
+ return SQLITE_OK;
216055
+ }
216056
+
216025
216057
int vectorIndexSearch(
216026
216058
sqlite3 *db,
216027
- const char* zDbSName,
216028
216059
int argc,
216029
216060
sqlite3_value **argv,
216030
216061
VectorOutRows *pRows,
216031
216062
int *nReads,
216032
216063
int *nWrites,
216033
216064
char **pzErrMsg
216034
216065
) {
216035
- int type, dims, k, rc;
216066
+ int type, dims, k, rc, iDb = -1 ;
216036
216067
double kDouble;
216037
- const char *zIdxName;
216068
+ const char *zIdxFullName;
216069
+ char *zIdxDbSNameAlloc = NULL; // allocated managed schema name string - must be freed if not null
216070
+ char *zIdxNameAlloc = NULL; // allocated managed index name string - must be freed if not null
216071
+ const char *zIdxDbSName = NULL; // schema name of the index (can be static in cases where explicit schema is omitted - so must not be freed)
216072
+ const char *zIdxName = NULL; // index name (can be extracted with sqlite3_value_text and managed by SQLite - so must not be freed)
216038
216073
const char *zErrMsg;
216039
216074
Vector *pVector = NULL;
216040
216075
DiskAnnIndex *pDiskAnn = NULL;
@@ -216043,8 +216078,6 @@ int vectorIndexSearch(
216043
216078
VectorIdxParams idxParams;
216044
216079
vectorIdxParamsInit(&idxParams, NULL, 0);
216045
216080
216046
- assert( zDbSName != NULL );
216047
-
216048
216081
if( argc != 3 ){
216049
216082
*pzErrMsg = sqlite3_mprintf("vector index(search): got %d parameters, expected 3", argc);
216050
216083
rc = SQLITE_ERROR;
@@ -216095,19 +216128,45 @@ int vectorIndexSearch(
216095
216128
rc = SQLITE_ERROR;
216096
216129
goto out;
216097
216130
}
216098
- zIdxName = (const char*)sqlite3_value_text(argv[0]);
216099
- if( vectorIndexGetParameters(db, zIdxName, &idxParams) != 0 ){
216131
+ zIdxFullName = (const char*)sqlite3_value_text(argv[0]);
216132
+ rc = getIndexNameParts(db, zIdxFullName, &zIdxDbSNameAlloc, &zIdxNameAlloc);
216133
+ if( rc != SQLITE_OK ){
216134
+ *pzErrMsg = sqlite3_mprintf("vector index(search): failed to parse index name");
216135
+ goto out;
216136
+ }
216137
+ assert( (zIdxDbSNameAlloc == NULL && zIdxNameAlloc == NULL) || (zIdxDbSNameAlloc != NULL && zIdxNameAlloc != NULL) );
216138
+ if( zIdxDbSNameAlloc == NULL && zIdxNameAlloc == NULL ){
216139
+ zIdxDbSName = "main";
216140
+ zIdxName = zIdxFullName;
216141
+ } else{
216142
+ zIdxDbSName = zIdxDbSNameAlloc;
216143
+ zIdxName = zIdxNameAlloc;
216144
+ iDb = sqlite3FindDbName(db, zIdxDbSName);
216145
+ if( iDb < 0 ){
216146
+ *pzErrMsg = sqlite3_mprintf("vector index(search): unknown schema '%s'", zIdxDbSName);
216147
+ rc = SQLITE_ERROR;
216148
+ goto out;
216149
+ }
216150
+ // we need to hold mutex to protect schema against unwanted changes
216151
+ // this code is necessary, otherwise sqlite3SchemaMutexHeld assert will fail
216152
+ if( iDb !=1 ){
216153
+ // not "main" DB which we already hold mutex for
216154
+ sqlite3BtreeEnter(db->aDb[iDb].pBt);
216155
+ }
216156
+ }
216157
+
216158
+ if( vectorIndexGetParameters(db, zIdxDbSName, zIdxName, &idxParams) != 0 ){
216100
216159
*pzErrMsg = sqlite3_mprintf("vector index(search): failed to parse vector index parameters");
216101
216160
rc = SQLITE_ERROR;
216102
216161
goto out;
216103
216162
}
216104
- pIndex = sqlite3FindIndex(db, zIdxName, zDbSName );
216163
+ pIndex = sqlite3FindIndex(db, zIdxName, zIdxDbSName );
216105
216164
if( pIndex == NULL ){
216106
216165
*pzErrMsg = sqlite3_mprintf("vector index(search): index not found");
216107
216166
rc = SQLITE_ERROR;
216108
216167
goto out;
216109
216168
}
216110
- rc = diskAnnOpenIndex(db, zDbSName , zIdxName, &idxParams, &pDiskAnn);
216169
+ rc = diskAnnOpenIndex(db, zIdxDbSName , zIdxName, &idxParams, &pDiskAnn);
216111
216170
if( rc != SQLITE_OK ){
216112
216171
*pzErrMsg = sqlite3_mprintf("vector index(search): failed to open diskann index");
216113
216172
goto out;
@@ -216127,6 +216186,11 @@ int vectorIndexSearch(
216127
216186
if( pVector != NULL ){
216128
216187
vectorFree(pVector);
216129
216188
}
216189
+ sqlite3DbFree(db, zIdxNameAlloc);
216190
+ sqlite3DbFree(db, zIdxDbSNameAlloc);
216191
+ if( iDb >= 0 && iDb != 1 ){
216192
+ sqlite3BtreeLeave(db->aDb[iDb].pBt);
216193
+ }
216130
216194
return rc;
216131
216195
}
216132
216196
@@ -216176,7 +216240,7 @@ int vectorIndexCursorInit(
216176
216240
216177
216241
assert( zDbSName != NULL );
216178
216242
216179
- if( vectorIndexGetParameters(db, zIndexName, ¶ms) != 0 ){
216243
+ if( vectorIndexGetParameters(db, zDbSName, zIndexName, ¶ms) != 0 ){
216180
216244
return SQLITE_ERROR;
216181
216245
}
216182
216246
pCursor = sqlite3DbMallocZero(db, sizeof(VectorIdxCursor));
@@ -216240,7 +216304,6 @@ typedef struct vectorVtab vectorVtab;
216240
216304
struct vectorVtab {
216241
216305
sqlite3_vtab base; /* Base class - must be first */
216242
216306
sqlite3 *db; /* Database connection */
216243
- char* zDbSName; /* Database schema name */
216244
216307
};
216245
216308
216246
216309
typedef struct vectorVtab_cursor vectorVtab_cursor;
@@ -216266,7 +216329,6 @@ static int vectorVtabConnect(
216266
216329
sqlite3_vtab **ppVtab,
216267
216330
char **pzErr
216268
216331
){
216269
- char *zDbSName = NULL;
216270
216332
vectorVtab *pVtab = NULL;
216271
216333
int rc;
216272
216334
/*
@@ -216281,21 +216343,17 @@ static int vectorVtabConnect(
216281
216343
if( pVtab == NULL ){
216282
216344
return SQLITE_NOMEM_BKPT;
216283
216345
}
216284
- zDbSName = sqlite3DbStrDup(db, argv[1]); // argv[1] is the database schema name by spec (see https://www.sqlite.org/vtab.html#the_xcreate_method)
216285
- if( zDbSName == NULL ){
216286
- sqlite3_free(pVtab);
216287
- return SQLITE_NOMEM_BKPT;
216288
- }
216346
+ // > Eponymous virtual tables exist in the "main" schema only, so they will not work if prefixed with a different schema name.
216347
+ // so, argv[1] always equal to "main" and we can safely ignore it
216348
+ // (see https://www.sqlite.org/vtab.html#epovtab)
216289
216349
memset(pVtab, 0, sizeof(*pVtab));
216290
216350
pVtab->db = db;
216291
- pVtab->zDbSName = zDbSName;
216292
216351
*ppVtab = (sqlite3_vtab*)pVtab;
216293
216352
return SQLITE_OK;
216294
216353
}
216295
216354
216296
216355
static int vectorVtabDisconnect(sqlite3_vtab *pVtab){
216297
216356
vectorVtab *pVTab = (vectorVtab*)pVtab;
216298
- sqlite3DbFree(pVTab->db, pVTab->zDbSName);
216299
216357
sqlite3_free(pVtab);
216300
216358
return SQLITE_OK;
216301
216359
}
@@ -216362,7 +216420,7 @@ static int vectorVtabFilter(
216362
216420
pCur->rows.aIntValues = NULL;
216363
216421
pCur->rows.ppValues = NULL;
216364
216422
216365
- if( vectorIndexSearch(pVTab->db, pVTab->zDbSName, argc, argv, &pCur->rows, &pCur->nReads, &pCur->nWrites, &pVTab->base.zErrMsg) != 0 ){
216423
+ if( vectorIndexSearch(pVTab->db, argc, argv, &pCur->rows, &pCur->nReads, &pCur->nWrites, &pVTab->base.zErrMsg) != 0 ){
216366
216424
return SQLITE_ERROR;
216367
216425
}
216368
216426
0 commit comments