Fossil SCM

Show document, ticket, and wiki titles on the result page of unindexed search.

drh 2015-02-13 23:43 UTC search-enhancements
Commit 0e77f1fbc08a5f1f8acf758a7b882e85c4cde584
1 file changed +94 -18
+94 -18
--- src/search.c
+++ src/search.c
@@ -213,11 +213,11 @@
213213
aiLastDoc[j] = iDoc;
214214
aiLastOfst[j] = i;
215215
for(k=1; j-k>=0 && anMatch[j-k] && aiWordIdx[j-k]==iWord-k; k++){}
216216
for(ii=0; ii<k; ii++){
217217
if( anMatch[j-ii]<k ){
218
- anMatch[j-ii] = k;
218
+ anMatch[j-ii] = k*(nDoc-iDoc);
219219
aiBestDoc[j-ii] = aiLastDoc[j-ii];
220220
aiBestOfst[j-ii] = aiLastOfst[j-ii];
221221
}
222222
}
223223
break;
@@ -396,14 +396,18 @@
396396
static void search_match_sqlfunc(
397397
sqlite3_context *context,
398398
int argc,
399399
sqlite3_value **argv
400400
){
401
- const char *zSText = (const char*)sqlite3_value_text(argv[0]);
401
+ const char *azDoc[5];
402
+ int nDoc;
402403
int rc;
403
- if( zSText==0 ) return;
404
- rc = search_match(&gSearch, 1, &zSText);
404
+ for(nDoc=0; nDoc<ArraySize(azDoc) && nDoc<argc; nDoc++){
405
+ azDoc[nDoc] = (const char*)sqlite3_value_text(argv[nDoc]);
406
+ if( azDoc[nDoc]==0 ) azDoc[nDoc] = "";
407
+ }
408
+ rc = search_match(&gSearch, nDoc, azDoc);
405409
sqlite3_result_int(context, rc);
406410
}
407411
408412
/*
409413
** These SQL functions return the results of the last
@@ -435,16 +439,43 @@
435439
static void search_stext_sqlfunc(
436440
sqlite3_context *context,
437441
int argc,
438442
sqlite3_value **argv
439443
){
440
- Blob txt;
444
+ const char *zType = (const char*)sqlite3_value_text(argv[0]);
445
+ int rid = sqlite3_value_int(argv[1]);
446
+ const char *zName = (const char*)sqlite3_value_text(argv[2]);
447
+ sqlite3_result_text(context, search_stext_cached(zType[0],rid,zName,0), -1,
448
+ SQLITE_TRANSIENT);
449
+}
450
+static void search_title_sqlfunc(
451
+ sqlite3_context *context,
452
+ int argc,
453
+ sqlite3_value **argv
454
+){
455
+ const char *zType = (const char*)sqlite3_value_text(argv[0]);
456
+ int rid = sqlite3_value_int(argv[1]);
457
+ const char *zName = (const char*)sqlite3_value_text(argv[2]);
458
+ int nHdr;
459
+ char *z = search_stext_cached(zType[0], rid, zName, &nHdr);
460
+ if( nHdr || zType[0]!='d' ){
461
+ sqlite3_result_text(context, z, nHdr, SQLITE_TRANSIENT);
462
+ }else{
463
+ sqlite3_result_value(context, argv[2]);
464
+ }
465
+}
466
+static void search_body_sqlfunc(
467
+ sqlite3_context *context,
468
+ int argc,
469
+ sqlite3_value **argv
470
+){
441471
const char *zType = (const char*)sqlite3_value_text(argv[0]);
442472
int rid = sqlite3_value_int(argv[1]);
443473
const char *zName = (const char*)sqlite3_value_text(argv[2]);
444
- search_stext(zType[0], rid, zName, &txt);
445
- sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
474
+ int nHdr;
475
+ char *z = search_stext_cached(zType[0], rid, zName, &nHdr);
476
+ sqlite3_result_text(context, z+nHdr+1, -1, SQLITE_TRANSIENT);
446477
}
447478
448479
/*
449480
** Encode a string for use as a query parameter in a URL
450481
*/
@@ -463,20 +494,24 @@
463494
** do not delete the Search object.
464495
*/
465496
void search_sql_setup(sqlite3 *db){
466497
static int once = 0;
467498
if( once++ ) return;
468
- sqlite3_create_function(db, "search_match", 1, SQLITE_UTF8, 0,
499
+ sqlite3_create_function(db, "search_match", -1, SQLITE_UTF8, 0,
469500
search_match_sqlfunc, 0, 0);
470501
sqlite3_create_function(db, "search_score", 0, SQLITE_UTF8, 0,
471502
search_score_sqlfunc, 0, 0);
472503
sqlite3_create_function(db, "search_snippet", 0, SQLITE_UTF8, 0,
473504
search_snippet_sqlfunc, 0, 0);
474505
sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
475506
search_init_sqlfunc, 0, 0);
476507
sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
477508
search_stext_sqlfunc, 0, 0);
509
+ sqlite3_create_function(db, "title", 3, SQLITE_UTF8, 0,
510
+ search_title_sqlfunc, 0, 0);
511
+ sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0,
512
+ search_body_sqlfunc, 0, 0);
478513
sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
479514
search_urlencode_sqlfunc, 0, 0);
480515
}
481516
482517
/*
@@ -617,20 +652,21 @@
617652
db_multi_exec(
618653
"CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
619654
);
620655
db_multi_exec(
621656
"INSERT INTO x(label,url,score,date,snip)"
622
- " SELECT printf('Document: %%s',foci.filename),"
657
+ " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
623658
" printf('/doc/%T/%%s',foci.filename),"
624659
" search_score(),"
625660
" (SELECT datetime(event.mtime) FROM event"
626661
" WHERE objid=symbolic_name_to_rid('trunk')),"
627662
" search_snippet()"
628663
" FROM foci CROSS JOIN blob"
629664
" WHERE checkinID=symbolic_name_to_rid('trunk')"
630665
" AND blob.uuid=foci.uuid"
631
- " AND search_match(stext('d',blob.rid,foci.filename))"
666
+ " AND search_match(title('d',blob.rid,foci.filename),"
667
+ " body('d',blob.rid,foci.filename))"
632668
" AND %z",
633669
zDocBr, glob_expr("foci.filename", zDocGlob)
634670
);
635671
}
636672
}
@@ -648,11 +684,11 @@
648684
" printf('/wiki?name=%%s',urlencode(name)),"
649685
" search_score(),"
650686
" datetime(mtime),"
651687
" search_snippet()"
652688
" FROM wiki"
653
- " WHERE search_match(stext('w',rid,name));"
689
+ " WHERE search_match(title('w',rid,name),body('w',rid,name));"
654690
);
655691
}
656692
if( (srchFlags & SRCH_CKIN)!=0 ){
657693
db_multi_exec(
658694
"WITH ckin(uuid,rid,mtime) AS ("
@@ -666,24 +702,24 @@
666702
" printf('/timeline?c=%%s&n=8&y=ci',uuid),"
667703
" search_score(),"
668704
" datetime(mtime),"
669705
" search_snippet()"
670706
" FROM ckin"
671
- " WHERE search_match(stext('c',rid,NULL));"
707
+ " WHERE search_match('',body('c',rid,NULL));"
672708
);
673709
}
674710
if( (srchFlags & SRCH_TKT)!=0 ){
675711
db_multi_exec(
676712
"INSERT INTO x(label,url,score, date,snip)"
677
- " SELECT printf('Ticket [%%.17s] on %%s',"
678
- "tkt_uuid,datetime(tkt_mtime)),"
713
+ " SELECT printf('Ticket: %%s (%%s)',title('t',tkt_id,NULL),"
714
+ "datetime(tkt_mtime)),"
679715
" printf('/tktview/%%.20s',tkt_uuid),"
680716
" search_score(),"
681717
" datetime(tkt_mtime),"
682718
" search_snippet()"
683719
" FROM ticket"
684
- " WHERE search_match(stext('t',tkt_id,NULL));"
720
+ " WHERE search_match(title('t',tkt_id,NULL),body('t',tkt_id,NULL));"
685721
);
686722
}
687723
}
688724
689725
/*
@@ -1023,12 +1059,11 @@
10231059
if( doc_is_embedded_html(pIn, &title) ){
10241060
blob_appendf(pOut, "%s\n", blob_str(&title));
10251061
}
10261062
html_to_plaintext(blob_str(pIn), pOut);
10271063
}else{
1028
- *pOut = *pIn;
1029
- blob_init(pIn, 0, 0);
1064
+ blob_append(pOut, blob_buffer(pIn), blob_size(pIn));
10301065
}
10311066
blob_reset(&html);
10321067
blob_reset(&title);
10331068
}
10341069
@@ -1038,11 +1073,11 @@
10381073
*/
10391074
static void append_all_ticket_fields(Blob *pAccum, Stmt *pQuery, int iTitle){
10401075
int n = db_column_count(pQuery);
10411076
int i;
10421077
const char *zMime = 0;
1043
- if( iTitle>=0 ){
1078
+ if( iTitle>=0 && iTitle<n ){
10441079
if( db_column_type(pQuery,iTitle)==SQLITE_TEXT ){
10451080
blob_append(pAccum, db_column_text(pQuery,iTitle), -1);
10461081
}
10471082
blob_append(pAccum, "\n", 1);
10481083
}
@@ -1170,10 +1205,51 @@
11701205
}
11711206
break;
11721207
}
11731208
}
11741209
}
1210
+
1211
+/*
1212
+** This routine is a wrapper around search_stext().
1213
+**
1214
+** This routine looks up the search text, stores it in an internal
1215
+** buffer, and returns a pointer to the text. Subsequent requests
1216
+** for the same document return the same pointer. The returned pointer
1217
+** is valid until the next invocation of this routine. Call this routine
1218
+** with an eType of 0 to clear the cache.
1219
+*/
1220
+char *search_stext_cached(
1221
+ char cType, /* Type of document */
1222
+ int rid, /* BLOB.RID or TAG.TAGID value for document */
1223
+ const char *zName, /* Auxiliary information */
1224
+ int *pnTitle /* OUT: length of title in bytes excluding \n */
1225
+){
1226
+ static struct {
1227
+ Blob stext; /* Cached search text */
1228
+ char cType; /* The type */
1229
+ int rid; /* The RID */
1230
+ int nTitle; /* Number of bytes in title */
1231
+ } cache;
1232
+ int i;
1233
+ char *z;
1234
+ if( cType!=cache.cType || rid!=cache.rid ){
1235
+ if( cache.rid>0 ){
1236
+ blob_reset(&cache.stext);
1237
+ }else{
1238
+ blob_init(&cache.stext,0,0);
1239
+ }
1240
+ cache.cType = cType;
1241
+ cache.rid = rid;
1242
+ if( cType==0 ) return 0;
1243
+ search_stext(cType, rid, zName, &cache.stext);
1244
+ z = blob_str(&cache.stext);
1245
+ for(i=0; z[i] && z[i]!='\n'; i++){}
1246
+ cache.nTitle = i;
1247
+ }
1248
+ if( pnTitle ) *pnTitle = cache.nTitle;
1249
+ return blob_str(&cache.stext);
1250
+}
11751251
11761252
/*
11771253
** COMMAND: test-search-stext
11781254
**
11791255
** Usage: fossil test-search-stext TYPE ARG1 ARG2
11801256
--- src/search.c
+++ src/search.c
@@ -213,11 +213,11 @@
213 aiLastDoc[j] = iDoc;
214 aiLastOfst[j] = i;
215 for(k=1; j-k>=0 && anMatch[j-k] && aiWordIdx[j-k]==iWord-k; k++){}
216 for(ii=0; ii<k; ii++){
217 if( anMatch[j-ii]<k ){
218 anMatch[j-ii] = k;
219 aiBestDoc[j-ii] = aiLastDoc[j-ii];
220 aiBestOfst[j-ii] = aiLastOfst[j-ii];
221 }
222 }
223 break;
@@ -396,14 +396,18 @@
396 static void search_match_sqlfunc(
397 sqlite3_context *context,
398 int argc,
399 sqlite3_value **argv
400 ){
401 const char *zSText = (const char*)sqlite3_value_text(argv[0]);
 
402 int rc;
403 if( zSText==0 ) return;
404 rc = search_match(&gSearch, 1, &zSText);
 
 
 
405 sqlite3_result_int(context, rc);
406 }
407
408 /*
409 ** These SQL functions return the results of the last
@@ -435,16 +439,43 @@
435 static void search_stext_sqlfunc(
436 sqlite3_context *context,
437 int argc,
438 sqlite3_value **argv
439 ){
440 Blob txt;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
441 const char *zType = (const char*)sqlite3_value_text(argv[0]);
442 int rid = sqlite3_value_int(argv[1]);
443 const char *zName = (const char*)sqlite3_value_text(argv[2]);
444 search_stext(zType[0], rid, zName, &txt);
445 sqlite3_result_text(context, blob_materialize(&txt), -1, fossil_free);
 
446 }
447
448 /*
449 ** Encode a string for use as a query parameter in a URL
450 */
@@ -463,20 +494,24 @@
463 ** do not delete the Search object.
464 */
465 void search_sql_setup(sqlite3 *db){
466 static int once = 0;
467 if( once++ ) return;
468 sqlite3_create_function(db, "search_match", 1, SQLITE_UTF8, 0,
469 search_match_sqlfunc, 0, 0);
470 sqlite3_create_function(db, "search_score", 0, SQLITE_UTF8, 0,
471 search_score_sqlfunc, 0, 0);
472 sqlite3_create_function(db, "search_snippet", 0, SQLITE_UTF8, 0,
473 search_snippet_sqlfunc, 0, 0);
474 sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
475 search_init_sqlfunc, 0, 0);
476 sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
477 search_stext_sqlfunc, 0, 0);
 
 
 
 
478 sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
479 search_urlencode_sqlfunc, 0, 0);
480 }
481
482 /*
@@ -617,20 +652,21 @@
617 db_multi_exec(
618 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
619 );
620 db_multi_exec(
621 "INSERT INTO x(label,url,score,date,snip)"
622 " SELECT printf('Document: %%s',foci.filename),"
623 " printf('/doc/%T/%%s',foci.filename),"
624 " search_score(),"
625 " (SELECT datetime(event.mtime) FROM event"
626 " WHERE objid=symbolic_name_to_rid('trunk')),"
627 " search_snippet()"
628 " FROM foci CROSS JOIN blob"
629 " WHERE checkinID=symbolic_name_to_rid('trunk')"
630 " AND blob.uuid=foci.uuid"
631 " AND search_match(stext('d',blob.rid,foci.filename))"
 
632 " AND %z",
633 zDocBr, glob_expr("foci.filename", zDocGlob)
634 );
635 }
636 }
@@ -648,11 +684,11 @@
648 " printf('/wiki?name=%%s',urlencode(name)),"
649 " search_score(),"
650 " datetime(mtime),"
651 " search_snippet()"
652 " FROM wiki"
653 " WHERE search_match(stext('w',rid,name));"
654 );
655 }
656 if( (srchFlags & SRCH_CKIN)!=0 ){
657 db_multi_exec(
658 "WITH ckin(uuid,rid,mtime) AS ("
@@ -666,24 +702,24 @@
666 " printf('/timeline?c=%%s&n=8&y=ci',uuid),"
667 " search_score(),"
668 " datetime(mtime),"
669 " search_snippet()"
670 " FROM ckin"
671 " WHERE search_match(stext('c',rid,NULL));"
672 );
673 }
674 if( (srchFlags & SRCH_TKT)!=0 ){
675 db_multi_exec(
676 "INSERT INTO x(label,url,score, date,snip)"
677 " SELECT printf('Ticket [%%.17s] on %%s',"
678 "tkt_uuid,datetime(tkt_mtime)),"
679 " printf('/tktview/%%.20s',tkt_uuid),"
680 " search_score(),"
681 " datetime(tkt_mtime),"
682 " search_snippet()"
683 " FROM ticket"
684 " WHERE search_match(stext('t',tkt_id,NULL));"
685 );
686 }
687 }
688
689 /*
@@ -1023,12 +1059,11 @@
1023 if( doc_is_embedded_html(pIn, &title) ){
1024 blob_appendf(pOut, "%s\n", blob_str(&title));
1025 }
1026 html_to_plaintext(blob_str(pIn), pOut);
1027 }else{
1028 *pOut = *pIn;
1029 blob_init(pIn, 0, 0);
1030 }
1031 blob_reset(&html);
1032 blob_reset(&title);
1033 }
1034
@@ -1038,11 +1073,11 @@
1038 */
1039 static void append_all_ticket_fields(Blob *pAccum, Stmt *pQuery, int iTitle){
1040 int n = db_column_count(pQuery);
1041 int i;
1042 const char *zMime = 0;
1043 if( iTitle>=0 ){
1044 if( db_column_type(pQuery,iTitle)==SQLITE_TEXT ){
1045 blob_append(pAccum, db_column_text(pQuery,iTitle), -1);
1046 }
1047 blob_append(pAccum, "\n", 1);
1048 }
@@ -1170,10 +1205,51 @@
1170 }
1171 break;
1172 }
1173 }
1174 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1175
1176 /*
1177 ** COMMAND: test-search-stext
1178 **
1179 ** Usage: fossil test-search-stext TYPE ARG1 ARG2
1180
--- src/search.c
+++ src/search.c
@@ -213,11 +213,11 @@
213 aiLastDoc[j] = iDoc;
214 aiLastOfst[j] = i;
215 for(k=1; j-k>=0 && anMatch[j-k] && aiWordIdx[j-k]==iWord-k; k++){}
216 for(ii=0; ii<k; ii++){
217 if( anMatch[j-ii]<k ){
218 anMatch[j-ii] = k*(nDoc-iDoc);
219 aiBestDoc[j-ii] = aiLastDoc[j-ii];
220 aiBestOfst[j-ii] = aiLastOfst[j-ii];
221 }
222 }
223 break;
@@ -396,14 +396,18 @@
396 static void search_match_sqlfunc(
397 sqlite3_context *context,
398 int argc,
399 sqlite3_value **argv
400 ){
401 const char *azDoc[5];
402 int nDoc;
403 int rc;
404 for(nDoc=0; nDoc<ArraySize(azDoc) && nDoc<argc; nDoc++){
405 azDoc[nDoc] = (const char*)sqlite3_value_text(argv[nDoc]);
406 if( azDoc[nDoc]==0 ) azDoc[nDoc] = "";
407 }
408 rc = search_match(&gSearch, nDoc, azDoc);
409 sqlite3_result_int(context, rc);
410 }
411
412 /*
413 ** These SQL functions return the results of the last
@@ -435,16 +439,43 @@
439 static void search_stext_sqlfunc(
440 sqlite3_context *context,
441 int argc,
442 sqlite3_value **argv
443 ){
444 const char *zType = (const char*)sqlite3_value_text(argv[0]);
445 int rid = sqlite3_value_int(argv[1]);
446 const char *zName = (const char*)sqlite3_value_text(argv[2]);
447 sqlite3_result_text(context, search_stext_cached(zType[0],rid,zName,0), -1,
448 SQLITE_TRANSIENT);
449 }
450 static void search_title_sqlfunc(
451 sqlite3_context *context,
452 int argc,
453 sqlite3_value **argv
454 ){
455 const char *zType = (const char*)sqlite3_value_text(argv[0]);
456 int rid = sqlite3_value_int(argv[1]);
457 const char *zName = (const char*)sqlite3_value_text(argv[2]);
458 int nHdr;
459 char *z = search_stext_cached(zType[0], rid, zName, &nHdr);
460 if( nHdr || zType[0]!='d' ){
461 sqlite3_result_text(context, z, nHdr, SQLITE_TRANSIENT);
462 }else{
463 sqlite3_result_value(context, argv[2]);
464 }
465 }
466 static void search_body_sqlfunc(
467 sqlite3_context *context,
468 int argc,
469 sqlite3_value **argv
470 ){
471 const char *zType = (const char*)sqlite3_value_text(argv[0]);
472 int rid = sqlite3_value_int(argv[1]);
473 const char *zName = (const char*)sqlite3_value_text(argv[2]);
474 int nHdr;
475 char *z = search_stext_cached(zType[0], rid, zName, &nHdr);
476 sqlite3_result_text(context, z+nHdr+1, -1, SQLITE_TRANSIENT);
477 }
478
479 /*
480 ** Encode a string for use as a query parameter in a URL
481 */
@@ -463,20 +494,24 @@
494 ** do not delete the Search object.
495 */
496 void search_sql_setup(sqlite3 *db){
497 static int once = 0;
498 if( once++ ) return;
499 sqlite3_create_function(db, "search_match", -1, SQLITE_UTF8, 0,
500 search_match_sqlfunc, 0, 0);
501 sqlite3_create_function(db, "search_score", 0, SQLITE_UTF8, 0,
502 search_score_sqlfunc, 0, 0);
503 sqlite3_create_function(db, "search_snippet", 0, SQLITE_UTF8, 0,
504 search_snippet_sqlfunc, 0, 0);
505 sqlite3_create_function(db, "search_init", -1, SQLITE_UTF8, 0,
506 search_init_sqlfunc, 0, 0);
507 sqlite3_create_function(db, "stext", 3, SQLITE_UTF8, 0,
508 search_stext_sqlfunc, 0, 0);
509 sqlite3_create_function(db, "title", 3, SQLITE_UTF8, 0,
510 search_title_sqlfunc, 0, 0);
511 sqlite3_create_function(db, "body", 3, SQLITE_UTF8, 0,
512 search_body_sqlfunc, 0, 0);
513 sqlite3_create_function(db, "urlencode", 1, SQLITE_UTF8, 0,
514 search_urlencode_sqlfunc, 0, 0);
515 }
516
517 /*
@@ -617,20 +652,21 @@
652 db_multi_exec(
653 "CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;"
654 );
655 db_multi_exec(
656 "INSERT INTO x(label,url,score,date,snip)"
657 " SELECT printf('Document: %%s',title('d',blob.rid,foci.filename)),"
658 " printf('/doc/%T/%%s',foci.filename),"
659 " search_score(),"
660 " (SELECT datetime(event.mtime) FROM event"
661 " WHERE objid=symbolic_name_to_rid('trunk')),"
662 " search_snippet()"
663 " FROM foci CROSS JOIN blob"
664 " WHERE checkinID=symbolic_name_to_rid('trunk')"
665 " AND blob.uuid=foci.uuid"
666 " AND search_match(title('d',blob.rid,foci.filename),"
667 " body('d',blob.rid,foci.filename))"
668 " AND %z",
669 zDocBr, glob_expr("foci.filename", zDocGlob)
670 );
671 }
672 }
@@ -648,11 +684,11 @@
684 " printf('/wiki?name=%%s',urlencode(name)),"
685 " search_score(),"
686 " datetime(mtime),"
687 " search_snippet()"
688 " FROM wiki"
689 " WHERE search_match(title('w',rid,name),body('w',rid,name));"
690 );
691 }
692 if( (srchFlags & SRCH_CKIN)!=0 ){
693 db_multi_exec(
694 "WITH ckin(uuid,rid,mtime) AS ("
@@ -666,24 +702,24 @@
702 " printf('/timeline?c=%%s&n=8&y=ci',uuid),"
703 " search_score(),"
704 " datetime(mtime),"
705 " search_snippet()"
706 " FROM ckin"
707 " WHERE search_match('',body('c',rid,NULL));"
708 );
709 }
710 if( (srchFlags & SRCH_TKT)!=0 ){
711 db_multi_exec(
712 "INSERT INTO x(label,url,score, date,snip)"
713 " SELECT printf('Ticket: %%s (%%s)',title('t',tkt_id,NULL),"
714 "datetime(tkt_mtime)),"
715 " printf('/tktview/%%.20s',tkt_uuid),"
716 " search_score(),"
717 " datetime(tkt_mtime),"
718 " search_snippet()"
719 " FROM ticket"
720 " WHERE search_match(title('t',tkt_id,NULL),body('t',tkt_id,NULL));"
721 );
722 }
723 }
724
725 /*
@@ -1023,12 +1059,11 @@
1059 if( doc_is_embedded_html(pIn, &title) ){
1060 blob_appendf(pOut, "%s\n", blob_str(&title));
1061 }
1062 html_to_plaintext(blob_str(pIn), pOut);
1063 }else{
1064 blob_append(pOut, blob_buffer(pIn), blob_size(pIn));
 
1065 }
1066 blob_reset(&html);
1067 blob_reset(&title);
1068 }
1069
@@ -1038,11 +1073,11 @@
1073 */
1074 static void append_all_ticket_fields(Blob *pAccum, Stmt *pQuery, int iTitle){
1075 int n = db_column_count(pQuery);
1076 int i;
1077 const char *zMime = 0;
1078 if( iTitle>=0 && iTitle<n ){
1079 if( db_column_type(pQuery,iTitle)==SQLITE_TEXT ){
1080 blob_append(pAccum, db_column_text(pQuery,iTitle), -1);
1081 }
1082 blob_append(pAccum, "\n", 1);
1083 }
@@ -1170,10 +1205,51 @@
1205 }
1206 break;
1207 }
1208 }
1209 }
1210
1211 /*
1212 ** This routine is a wrapper around search_stext().
1213 **
1214 ** This routine looks up the search text, stores it in an internal
1215 ** buffer, and returns a pointer to the text. Subsequent requests
1216 ** for the same document return the same pointer. The returned pointer
1217 ** is valid until the next invocation of this routine. Call this routine
1218 ** with an eType of 0 to clear the cache.
1219 */
1220 char *search_stext_cached(
1221 char cType, /* Type of document */
1222 int rid, /* BLOB.RID or TAG.TAGID value for document */
1223 const char *zName, /* Auxiliary information */
1224 int *pnTitle /* OUT: length of title in bytes excluding \n */
1225 ){
1226 static struct {
1227 Blob stext; /* Cached search text */
1228 char cType; /* The type */
1229 int rid; /* The RID */
1230 int nTitle; /* Number of bytes in title */
1231 } cache;
1232 int i;
1233 char *z;
1234 if( cType!=cache.cType || rid!=cache.rid ){
1235 if( cache.rid>0 ){
1236 blob_reset(&cache.stext);
1237 }else{
1238 blob_init(&cache.stext,0,0);
1239 }
1240 cache.cType = cType;
1241 cache.rid = rid;
1242 if( cType==0 ) return 0;
1243 search_stext(cType, rid, zName, &cache.stext);
1244 z = blob_str(&cache.stext);
1245 for(i=0; z[i] && z[i]!='\n'; i++){}
1246 cache.nTitle = i;
1247 }
1248 if( pnTitle ) *pnTitle = cache.nTitle;
1249 return blob_str(&cache.stext);
1250 }
1251
1252 /*
1253 ** COMMAND: test-search-stext
1254 **
1255 ** Usage: fossil test-search-stext TYPE ARG1 ARG2
1256

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button