@@ -30,6 +30,8 @@ SQLITE_EXTENSION_INIT3
3030#define SEARCH_COLUMN_HASH 3
3131#define SEARCH_COLUMN_SEQ 4
3232#define SEARCH_COLUMN_RANKING 5
33+ #define SEARCH_COLUMN_PATH 6
34+ #define SEARCH_COLUMN_SNIPPET 7
3335
3436typedef struct {
3537 sqlite3_vtab base ; // Base class - must be first
@@ -39,7 +41,7 @@ typedef struct {
3941
4042typedef struct {
4143 sqlite3_vtab_cursor base ; // Base class - must be first
42- int max_items ;
44+ int max_results ;
4345 bool perform_fts ;
4446
4547 int index ;
@@ -117,7 +119,7 @@ int vMemorySearchCursorAllocate (vMemorySearchCursor *c, int entries, bool perfo
117119 if (!buffer ) return SQLITE_NOMEM ;
118120
119121 // adjust all internal pointers
120- c -> max_items = entries ;
122+ c -> max_results = entries ;
121123 c -> perform_fts = perform_fts ;
122124 c -> buffer = buffer ;
123125
@@ -162,7 +164,7 @@ int vMemorySearchCursorAllocate (vMemorySearchCursor *c, int entries, bool perfo
162164 return SQLITE_OK ;
163165}
164166
165- int vMemorySearchCursorMerge (vMemorySearchCursor * c , double vectorWeight , double textWeight , double min_score , int max_items ) {
167+ int vMemorySearchCursorMerge (vMemorySearchCursor * c , double vectorWeight , double textWeight , double min_score , int max_results ) {
166168 c -> merge .count = 0 ;
167169
168170 // add semantic (vector) results
@@ -244,7 +246,7 @@ int vMemorySearchCursorMerge(vMemorySearchCursor *c, double vectorWeight, double
244246
245247 // copy top results to final cursor arrays, filtering by min_score
246248 c -> count = 0 ;
247- for (int i = 0 ; i < c -> merge .count && c -> count < max_items ; i ++ ) {
249+ for (int i = 0 ; i < c -> merge .count && c -> count < max_results ; i ++ ) {
248250 if (c -> merge .textScore [i ] < min_score ) break ; // sorted descending, so stop at first below threshold
249251 c -> hash [c -> count ] = c -> merge .hash [i ];
250252 c -> seq [c -> count ] = c -> merge .seq [i ];
@@ -430,7 +432,7 @@ static int vMemorySearchConnect (sqlite3 *db, void *pAux, int argc, const char *
430432 }
431433
432434 // https://www.sqlite.org/vtab.html#table_valued_functions
433- int rc = sqlite3_declare_vtab (db , "CREATE TABLE x(query hidden, max_entries hidden, context hidden, hash, seq, ranking);" );
435+ int rc = sqlite3_declare_vtab (db , "CREATE TABLE x(query hidden, max_entries hidden, context hidden, hash, seq, ranking, path, snippet );" );
434436 if (rc != SQLITE_OK ) return rc ;
435437
436438 vMemorySearchTable * vtab = (vMemorySearchTable * )dbmem_zeroalloc (sizeof (vMemorySearchTable ));
@@ -506,20 +508,37 @@ static int vMemorySearchCursorEof (sqlite3_vtab_cursor *cur){
506508}
507509
508510static int vMemorySearchCursorColumn (sqlite3_vtab_cursor * cur , sqlite3_context * context , int iCol ) {
511+ static const char * path_sql = "SELECT path FROM dbmem_content WHERE hash = ?1;" ;
512+ static const char * snippet_sql = "SELECT substr(c.value, v.offset + 1, v.length) FROM dbmem_vault v JOIN dbmem_content c ON v.hash = c.hash WHERE v.hash = ?1 AND v.seq = ?2;" ;
513+
509514 vMemorySearchCursor * c = (vMemorySearchCursor * )cur ;
515+ sqlite3 * db = ((vMemorySearchTable * )cur -> pVtab )-> db ;
510516
511517 switch (iCol ) {
512518 case SEARCH_COLUMN_HASH :
513- sqlite3_result_int64 (context , ( sqlite3_int64 ) c -> hash [c -> index ]);
519+ sqlite3_result_int64 (context , c -> hash [c -> index ]);
514520 break ;
515521
516522 case SEARCH_COLUMN_SEQ :
517- sqlite3_result_int64 (context , ( sqlite3_int64 ) c -> seq [c -> index ]);
523+ sqlite3_result_int64 (context , c -> seq [c -> index ]);
518524 break ;
519525
520526 case SEARCH_COLUMN_RANKING :
521527 sqlite3_result_double (context , c -> rank [c -> index ]);
522528 break ;
529+
530+ case SEARCH_COLUMN_PATH :
531+ case SEARCH_COLUMN_SNIPPET :{
532+ const char * sql = (iCol == SEARCH_COLUMN_PATH ) ? path_sql : snippet_sql ;
533+ sqlite3_stmt * vm = NULL ;
534+ if (sqlite3_prepare_v2 (db , sql , -1 , & vm , NULL ) == SQLITE_OK ) {
535+ sqlite3_bind_int64 (vm , 1 , c -> hash [c -> index ]);
536+ if (iCol == SEARCH_COLUMN_SNIPPET ) sqlite3_bind_int64 (vm , 2 , c -> seq [c -> index ]);
537+ if (sqlite3_step (vm ) == SQLITE_ROW ) sqlite3_result_value (context , sqlite3_column_value (vm , 0 ));
538+ }
539+ if (vm ) sqlite3_finalize (vm );
540+ }
541+ break ;
523542 }
524543
525544 return SQLITE_OK ;
@@ -540,7 +559,7 @@ static int vMemorySearchCursorFilter (sqlite3_vtab_cursor *cur, int idxNum, cons
540559 sqlite3 * db = searchTab -> db ;
541560
542561 // check and retrieve arguments
543- int max_items = dbmem_context_max_items (ctx );
562+ int max_results = dbmem_context_max_results (ctx );
544563 bool perform_fts = dbmem_context_perform_fts (ctx );
545564 const char * query = NULL ;
546565 const char * context = NULL ;
@@ -559,14 +578,14 @@ static int vMemorySearchCursorFilter (sqlite3_vtab_cursor *cur, int idxNum, cons
559578 if (argc > 1 ) {
560579 // only the next two arguments are handled
561580 for (int i = 1 ; i < argc && i <=2 ; ++ i ) {
562- if (sqlite3_value_type (argv [i ]) == SQLITE_INTEGER ) max_items = sqlite3_value_int (argv [i ]);
581+ if (sqlite3_value_type (argv [i ]) == SQLITE_INTEGER ) max_results = sqlite3_value_int (argv [i ]);
563582 else if (sqlite3_value_type (argv [i ]) == SQLITE_TEXT ) context = (const char * )sqlite3_value_text (argv [i ]);
564583 // ignore any other type
565584 }
566585 }
567586
568587 // allocate internal cursor buffer
569- int rc = vMemorySearchCursorAllocate (c , max_items , perform_fts );
588+ int rc = vMemorySearchCursorAllocate (c , max_results , perform_fts );
570589 if (rc != SQLITE_OK ) return SQLITE_NOMEM ;
571590
572591 // perform semantic search
@@ -608,7 +627,7 @@ static int vMemorySearchCursorFilter (sqlite3_vtab_cursor *cur, int idxNum, cons
608627 }
609628
610629 // perform search
611- rc = dbmem_semantic_search (db , c , result .embedding , (int )(result .n_embd * sizeof (float )), context , max_items );
630+ rc = dbmem_semantic_search (db , c , result .embedding , (int )(result .n_embd * sizeof (float )), context , max_results );
612631 if (rc != 0 ) {
613632 sqlvTab -> zErrMsg = sqlite3_mprintf ("%s" , sqlite3_errmsg (db ));
614633 return SQLITE_ERROR ;
@@ -617,7 +636,7 @@ static int vMemorySearchCursorFilter (sqlite3_vtab_cursor *cur, int idxNum, cons
617636 // perform fts search
618637 if (perform_fts ) {
619638 // in case of FTS error ignore its contribution
620- rc = dbmem_fts_search (db , c , query , context , max_items );
639+ rc = dbmem_fts_search (db , c , query , context , max_results );
621640 if (rc != SQLITE_OK ) perform_fts = false;
622641 }
623642
@@ -632,7 +651,7 @@ static int vMemorySearchCursorFilter (sqlite3_vtab_cursor *cur, int idxNum, cons
632651 double vectorWeight = dbmem_context_vector_weight (ctx );
633652 double textWeight = dbmem_context_text_weight (ctx );
634653 double min_score = dbmem_context_min_score (ctx );
635- vMemorySearchCursorMerge (c , vectorWeight , textWeight , min_score , max_items );
654+ vMemorySearchCursorMerge (c , vectorWeight , textWeight , min_score , max_results );
636655
637656 // update last_accessed timestamps for returned results
638657 if (dbmem_context_update_access (ctx ) && c -> count > 0 ) {
0 commit comments