@@ -85652,7 +85652,7 @@ int vectorIdxParseColumnType(const char *, int *, int *, const char **);
8565285652int vectorIndexCreate(Parse*, const Index*, const char *, const IdList*);
8565385653int vectorIndexClear(sqlite3 *, const char *, const char *);
8565485654int 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 **);
8565685656int vectorIndexCursorInit(sqlite3 *, const char *, const char *, VectorIdxCursor **);
8565785657void vectorIndexCursorClose(sqlite3 *, VectorIdxCursor *, int *, int *);
8565885658int vectorIndexInsert(VectorIdxCursor *, const UnpackedRecord *, char **);
@@ -215829,17 +215829,25 @@ int vectorIndexTryGetParametersFromBinFormat(sqlite3 *db, const char *zSql, cons
215829215829
215830215830int vectorIndexGetParameters(
215831215831 sqlite3 *db,
215832+ const char *zDbSName,
215832215833 const char *zIdxName,
215833215834 VectorIdxParams *pParams
215834215835) {
215835215836 int rc = SQLITE_OK;
215837+ assert( zDbSName != NULL );
215836215838
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+ }
215838215845 // zSelectSqlPekkaLegacy handles the case when user created DB before 04 July 2024 (https://discord.com/channels/933071162680958986/1225560924526477322/1258367912402489397)
215839215846 // when instead of table with binary parameters rigid schema was used for index settings
215840215847 // we should drop this eventually - but for now we postponed this decision
215841215848 static const char* zSelectSqlPekkaLegacy = "SELECT vector_type, block_size, dims, distance_ops FROM libsql_vector_index WHERE name = ?";
215842215849 rc = vectorIndexTryGetParametersFromBinFormat(db, zSelectSql, zIdxName, pParams);
215850+ sqlite3_free(zSelectSql);
215843215851 if( rc == SQLITE_OK ){
215844215852 return SQLITE_OK;
215845215853 }
@@ -216022,19 +216030,46 @@ int vectorIndexCreate(Parse *pParse, const Index *pIdx, const char *zDbSName, co
216022216030 return CREATE_OK;
216023216031}
216024216032
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+
216025216057int vectorIndexSearch(
216026216058 sqlite3 *db,
216027- const char* zDbSName,
216028216059 int argc,
216029216060 sqlite3_value **argv,
216030216061 VectorOutRows *pRows,
216031216062 int *nReads,
216032216063 int *nWrites,
216033216064 char **pzErrMsg
216034216065) {
216035- int type, dims, k, rc;
216066+ int type, dims, k, rc, iDb = -1 ;
216036216067 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)
216038216073 const char *zErrMsg;
216039216074 Vector *pVector = NULL;
216040216075 DiskAnnIndex *pDiskAnn = NULL;
@@ -216043,8 +216078,6 @@ int vectorIndexSearch(
216043216078 VectorIdxParams idxParams;
216044216079 vectorIdxParamsInit(&idxParams, NULL, 0);
216045216080
216046- assert( zDbSName != NULL );
216047-
216048216081 if( argc != 3 ){
216049216082 *pzErrMsg = sqlite3_mprintf("vector index(search): got %d parameters, expected 3", argc);
216050216083 rc = SQLITE_ERROR;
@@ -216095,19 +216128,45 @@ int vectorIndexSearch(
216095216128 rc = SQLITE_ERROR;
216096216129 goto out;
216097216130 }
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 ){
216100216159 *pzErrMsg = sqlite3_mprintf("vector index(search): failed to parse vector index parameters");
216101216160 rc = SQLITE_ERROR;
216102216161 goto out;
216103216162 }
216104- pIndex = sqlite3FindIndex(db, zIdxName, zDbSName );
216163+ pIndex = sqlite3FindIndex(db, zIdxName, zIdxDbSName );
216105216164 if( pIndex == NULL ){
216106216165 *pzErrMsg = sqlite3_mprintf("vector index(search): index not found");
216107216166 rc = SQLITE_ERROR;
216108216167 goto out;
216109216168 }
216110- rc = diskAnnOpenIndex(db, zDbSName , zIdxName, &idxParams, &pDiskAnn);
216169+ rc = diskAnnOpenIndex(db, zIdxDbSName , zIdxName, &idxParams, &pDiskAnn);
216111216170 if( rc != SQLITE_OK ){
216112216171 *pzErrMsg = sqlite3_mprintf("vector index(search): failed to open diskann index");
216113216172 goto out;
@@ -216127,6 +216186,11 @@ int vectorIndexSearch(
216127216186 if( pVector != NULL ){
216128216187 vectorFree(pVector);
216129216188 }
216189+ sqlite3DbFree(db, zIdxNameAlloc);
216190+ sqlite3DbFree(db, zIdxDbSNameAlloc);
216191+ if( iDb >= 0 && iDb != 1 ){
216192+ sqlite3BtreeLeave(db->aDb[iDb].pBt);
216193+ }
216130216194 return rc;
216131216195}
216132216196
@@ -216176,7 +216240,7 @@ int vectorIndexCursorInit(
216176216240
216177216241 assert( zDbSName != NULL );
216178216242
216179- if( vectorIndexGetParameters(db, zIndexName, ¶ms) != 0 ){
216243+ if( vectorIndexGetParameters(db, zDbSName, zIndexName, ¶ms) != 0 ){
216180216244 return SQLITE_ERROR;
216181216245 }
216182216246 pCursor = sqlite3DbMallocZero(db, sizeof(VectorIdxCursor));
@@ -216240,7 +216304,6 @@ typedef struct vectorVtab vectorVtab;
216240216304struct vectorVtab {
216241216305 sqlite3_vtab base; /* Base class - must be first */
216242216306 sqlite3 *db; /* Database connection */
216243- char* zDbSName; /* Database schema name */
216244216307};
216245216308
216246216309typedef struct vectorVtab_cursor vectorVtab_cursor;
@@ -216266,7 +216329,6 @@ static int vectorVtabConnect(
216266216329 sqlite3_vtab **ppVtab,
216267216330 char **pzErr
216268216331){
216269- char *zDbSName = NULL;
216270216332 vectorVtab *pVtab = NULL;
216271216333 int rc;
216272216334 /*
@@ -216281,21 +216343,17 @@ static int vectorVtabConnect(
216281216343 if( pVtab == NULL ){
216282216344 return SQLITE_NOMEM_BKPT;
216283216345 }
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)
216289216349 memset(pVtab, 0, sizeof(*pVtab));
216290216350 pVtab->db = db;
216291- pVtab->zDbSName = zDbSName;
216292216351 *ppVtab = (sqlite3_vtab*)pVtab;
216293216352 return SQLITE_OK;
216294216353}
216295216354
216296216355static int vectorVtabDisconnect(sqlite3_vtab *pVtab){
216297216356 vectorVtab *pVTab = (vectorVtab*)pVtab;
216298- sqlite3DbFree(pVTab->db, pVTab->zDbSName);
216299216357 sqlite3_free(pVtab);
216300216358 return SQLITE_OK;
216301216359}
@@ -216362,7 +216420,7 @@ static int vectorVtabFilter(
216362216420 pCur->rows.aIntValues = NULL;
216363216421 pCur->rows.ppValues = NULL;
216364216422
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 ){
216366216424 return SQLITE_ERROR;
216367216425 }
216368216426
0 commit comments