Fossil SCM

Merge search-technote

andygoth 2017-09-25 15:28 trunk merge
Commit a551d503c290e5457d41335d0c924d1d5910cea1099114db954a355a21b25222
+103 -42
--- src/search.c
+++ src/search.c
@@ -633,15 +633,16 @@
633633
db_finalize(&q);
634634
}
635635
636636
#if INTERFACE
637637
/* What to search for */
638
-#define SRCH_CKIN 0x0001 /* Search over check-in comments */
639
-#define SRCH_DOC 0x0002 /* Search over embedded documents */
640
-#define SRCH_TKT 0x0004 /* Search over tickets */
641
-#define SRCH_WIKI 0x0008 /* Search over wiki */
642
-#define SRCH_ALL 0x000f /* Search over everything */
638
+#define SRCH_CKIN 0x0001 /* Search over check-in comments */
639
+#define SRCH_DOC 0x0002 /* Search over embedded documents */
640
+#define SRCH_TKT 0x0004 /* Search over tickets */
641
+#define SRCH_WIKI 0x0008 /* Search over wiki */
642
+#define SRCH_TECHNOTE 0x0010 /* Search over tech notes */
643
+#define SRCH_ALL 0x001f /* Search over everything */
643644
#endif
644645
645646
/*
646647
** Remove bits from srchFlags which are disallowed by either the
647648
** current server configuration or by user permissions.
@@ -648,17 +649,18 @@
648649
*/
649650
unsigned int search_restrict(unsigned int srchFlags){
650651
static unsigned int knownGood = 0;
651652
static unsigned int knownBad = 0;
652653
static const struct { unsigned m; const char *zKey; } aSetng[] = {
653
- { SRCH_CKIN, "search-ci" },
654
- { SRCH_DOC, "search-doc" },
655
- { SRCH_TKT, "search-tkt" },
656
- { SRCH_WIKI, "search-wiki" },
654
+ { SRCH_CKIN, "search-ci" },
655
+ { SRCH_DOC, "search-doc" },
656
+ { SRCH_TKT, "search-tkt" },
657
+ { SRCH_WIKI, "search-wiki" },
658
+ { SRCH_TECHNOTE, "search-technote" },
657659
};
658660
int i;
659
- if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC);
661
+ if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_TECHNOTE);
660662
if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
661663
if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
662664
for(i=0; i<count(aSetng); i++){
663665
unsigned int m = aSetng[i].m;
664666
if( (srchFlags & m)==0 ) continue;
@@ -770,10 +772,30 @@
770772
" datetime(tkt_mtime),"
771773
" search_snippet()"
772774
" FROM ticket"
773775
" WHERE search_match(title('t',tkt_id,NULL),body('t',tkt_id,NULL));"
774776
);
777
+ }
778
+ if( (srchFlags & SRCH_TECHNOTE)!=0 ){
779
+ db_multi_exec(
780
+ "WITH technote(uuid,rid,mtime) AS ("
781
+ " SELECT substr(tagname,7), tagxref.rid, max(tagxref.mtime)"
782
+ " FROM tag, tagxref"
783
+ " WHERE tag.tagname GLOB 'event-*'"
784
+ " AND tagxref.tagid=tag.tagid"
785
+ " GROUP BY 1"
786
+ ")"
787
+ "INSERT INTO x(label,url,score,id,date,snip)"
788
+ " SELECT printf('Tech Note: %%s',uuid),"
789
+ " printf('/technote/%%s',uuid),"
790
+ " search_score(),"
791
+ " 'e'||rid,"
792
+ " datetime(mtime),"
793
+ " search_snippet()"
794
+ " FROM technote"
795
+ " WHERE search_match('',body('e',rid,NULL));"
796
+ );
775797
}
776798
}
777799
778800
/*
779801
** Number of significant bits in a u32
@@ -886,14 +908,15 @@
886908
zPattern
887909
);
888910
if( srchFlags!=SRCH_ALL ){
889911
const char *zSep = " AND (";
890912
static const struct { unsigned m; char c; } aMask[] = {
891
- { SRCH_CKIN, 'c' },
892
- { SRCH_DOC, 'd' },
893
- { SRCH_TKT, 't' },
894
- { SRCH_WIKI, 'w' },
913
+ { SRCH_CKIN, 'c' },
914
+ { SRCH_DOC, 'd' },
915
+ { SRCH_TKT, 't' },
916
+ { SRCH_WIKI, 'w' },
917
+ { SRCH_TECHNOTE, 'e' },
895918
};
896919
int i;
897920
for(i=0; i<count(aMask); i++){
898921
if( srchFlags & aMask[i].m ){
899922
blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -1037,14 +1060,15 @@
10371060
const char *zDisable2;
10381061
const char *zPattern;
10391062
int fDebug = PB("debug");
10401063
srchFlags = search_restrict(srchFlags);
10411064
switch( srchFlags ){
1042
- case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
1043
- case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
1044
- case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
1045
- case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
1065
+ case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
1066
+ case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
1067
+ case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
1068
+ case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
1069
+ case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break;
10461070
}
10471071
if( srchFlags==0 ){
10481072
zDisable1 = " disabled";
10491073
zDisable2 = " disabled";
10501074
zPattern = "";
@@ -1060,15 +1084,16 @@
10601084
@ <div class='searchForm'>
10611085
}
10621086
@ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)>
10631087
if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){
10641088
static const struct { char *z; char *zNm; unsigned m; } aY[] = {
1065
- { "all", "All", SRCH_ALL },
1066
- { "c", "Check-ins", SRCH_CKIN },
1067
- { "d", "Docs", SRCH_DOC },
1068
- { "t", "Tickets", SRCH_TKT },
1069
- { "w", "Wiki", SRCH_WIKI },
1089
+ { "all", "All", SRCH_ALL },
1090
+ { "c", "Check-ins", SRCH_CKIN },
1091
+ { "d", "Docs", SRCH_DOC },
1092
+ { "t", "Tickets", SRCH_TKT },
1093
+ { "w", "Wiki", SRCH_WIKI },
1094
+ { "e", "Tech Notes", SRCH_TECHNOTE },
10701095
};
10711096
const char *zY = PD("y","all");
10721097
unsigned newFlags = srchFlags;
10731098
int i;
10741099
@ <select size='1' name='y'>
@@ -1116,10 +1141,11 @@
11161141
** y=TYPE What to search.
11171142
** c -> check-ins
11181143
** d -> documentation
11191144
** t -> tickets
11201145
** w -> wiki
1146
+** e -> tech notes
11211147
** all -> everything
11221148
*/
11231149
void search_page(void){
11241150
login_check_credentials();
11251151
style_header("Search");
@@ -1222,10 +1248,11 @@
12221248
**
12231249
** cType: d Embedded documentation
12241250
** w Wiki page
12251251
** c Check-in comment
12261252
** t Ticket text
1253
+** e Tech note
12271254
**
12281255
** rid The RID of an artifact that defines the object
12291256
** being searched.
12301257
**
12311258
** zName Name of the object being searched. This is used
@@ -1247,12 +1274,14 @@
12471274
blob_to_utf8_no_bom(&doc, 0);
12481275
get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
12491276
blob_reset(&doc);
12501277
break;
12511278
}
1279
+ case 'e': /* Tech Notes */
12521280
case 'w': { /* Wiki */
1253
- Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
1281
+ Manifest *pWiki = manifest_get(rid,
1282
+ cType == 'e' ? CFTYPE_EVENT : CFTYPE_WIKI, 0);
12541283
Blob wiki;
12551284
if( pWiki==0 ) break;
12561285
blob_init(&wiki, pWiki->zWiki, -1);
12571286
get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
12581287
pOut);
@@ -1367,11 +1396,11 @@
13671396
** COMMAND: test-search-stext
13681397
**
13691398
** Usage: fossil test-search-stext TYPE RID NAME
13701399
**
13711400
** Compute the search text for document TYPE-RID whose name is NAME.
1372
-** The TYPE is one of "c", "d", "t", or "w". The RID is the document
1401
+** The TYPE is one of "c", "d", "t", "w", or "e". The RID is the document
13731402
** ID. The NAME is used to figure out a mimetype to use for formatting
13741403
** the raw document text.
13751404
*/
13761405
void test_search_stext(void){
13771406
Blob out;
@@ -1484,10 +1513,14 @@
14841513
);
14851514
db_multi_exec(
14861515
"INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
14871516
" SELECT 't', tkt_id, 0 FROM ticket;"
14881517
);
1518
+ db_multi_exec(
1519
+ "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed)"
1520
+ " SELECT 'e', objid, comment, 0 FROM event WHERE type='e';"
1521
+ );
14891522
}
14901523
14911524
/*
14921525
** The document described by cType,rid,zName is about to be added or
14931526
** updated. If the document has already been indexed, then unindex it
@@ -1508,19 +1541,19 @@
15081541
db_multi_exec(
15091542
"REPLACE INTO ftsdocs(type,rid,name,idxed)"
15101543
" VALUES(%Q,%d,%Q,0)",
15111544
zType, rid, zName
15121545
);
1513
- if( cType=='w' ){
1546
+ if( cType=='w' || cType=='e' ){
15141547
db_multi_exec(
15151548
"DELETE FROM ftsidx WHERE docid IN"
1516
- " (SELECT rowid FROM ftsdocs WHERE type='w' AND name=%Q AND idxed)",
1517
- zName
1549
+ " (SELECT rowid FROM ftsdocs WHERE type='%c' AND name=%Q AND idxed)",
1550
+ cType, zName
15181551
);
15191552
db_multi_exec(
1520
- "DELETE FROM ftsdocs WHERE type='w' AND name=%Q AND rid!=%d",
1521
- zName, rid
1553
+ "DELETE FROM ftsdocs WHERE type='%c' AND name=%Q AND rid!=%d",
1554
+ cType, zName, rid
15221555
);
15231556
}
15241557
}
15251558
}
15261559
@@ -1647,10 +1680,34 @@
16471680
" tagxref.mtime"
16481681
" FROM tagxref WHERE tagxref.rid=ftsdocs.rid)"
16491682
" WHERE ftsdocs.type='w' AND NOT ftsdocs.idxed"
16501683
);
16511684
}
1685
+
1686
+/*
1687
+** Deal with all of the unindexed 'e' terms in FTSDOCS
1688
+*/
1689
+static void search_update_technote_index(void){
1690
+ db_multi_exec(
1691
+ "INSERT INTO ftsidx(docid,title,body)"
1692
+ " SELECT rowid, title('e',rid,NULL),body('e',rid,NULL) FROM ftsdocs"
1693
+ " WHERE type='e' AND NOT idxed;"
1694
+ );
1695
+ if( db_changes()==0 ) return;
1696
+ db_multi_exec(
1697
+ "UPDATE ftsdocs SET idxed=1,"
1698
+ " (name,label,url,mtime) = "
1699
+ " (SELECT ftsdocs.name,"
1700
+ " 'Tech Note: '||ftsdocs.name,"
1701
+ " '/technote/'||substr(tag.tagname,7),"
1702
+ " tagxref.mtime"
1703
+ " FROM tagxref, tag USING (tagid)"
1704
+ " WHERE tagxref.rid=ftsdocs.rid"
1705
+ " AND tagname GLOB 'event-*')"
1706
+ " WHERE ftsdocs.type='e' AND NOT ftsdocs.idxed"
1707
+ );
1708
+}
16521709
16531710
/*
16541711
** Deal with all of the unindexed entries in the FTSDOCS table - that
16551712
** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the
16561713
** index.
@@ -1667,10 +1724,13 @@
16671724
search_update_ticket_index();
16681725
}
16691726
if( srchFlags & SRCH_WIKI ){
16701727
search_update_wiki_index();
16711728
}
1729
+ if( srchFlags & SRCH_TECHNOTE ){
1730
+ search_update_technote_index();
1731
+ }
16721732
}
16731733
16741734
/*
16751735
** Construct, prepopulate, and then update the full-text index.
16761736
*/
@@ -1694,14 +1754,14 @@
16941754
** reindex Rebuild the search index. This is a no-op if
16951755
** index search is disabled
16961756
**
16971757
** index (on|off) Turn the search index on or off
16981758
**
1699
-** enable cdtw Enable various kinds of search. c=Check-ins,
1700
-** d=Documents, t=Tickets, w=Wiki.
1759
+** enable cdtwe Enable various kinds of search. c=Check-ins,
1760
+** d=Documents, t=Tickets, w=Wiki, e=Tech Notes.
17011761
**
1702
-** disable cdtw Disable various kinds of search
1762
+** disable cdtwe Disable various kinds of search
17031763
**
17041764
** stemmer (on|off) Turn the Porter stemmer on or off for indexed
17051765
** search. (Unindexed search is never stemmed.)
17061766
**
17071767
** The current search settings are displayed after any changes are applied.
@@ -1714,14 +1774,15 @@
17141774
{ 3, "disable" },
17151775
{ 4, "enable" },
17161776
{ 5, "stemmer" },
17171777
};
17181778
static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = {
1719
- { "search-ckin", "check-in search:", "c" },
1720
- { "search-doc", "document search:", "d" },
1721
- { "search-tkt", "ticket search:", "t" },
1722
- { "search-wiki", "wiki search:", "w" },
1779
+ { "search-ckin", "check-in search:", "c" },
1780
+ { "search-doc", "document search:", "d" },
1781
+ { "search-tkt", "ticket search:", "t" },
1782
+ { "search-wiki", "wiki search:", "w" },
1783
+ { "search-technote", "tech note search:", "e" },
17231784
};
17241785
char *zSubCmd = 0;
17251786
int i, j, n;
17261787
int iCmd = 0;
17271788
int iAction = 0;
@@ -1779,21 +1840,21 @@
17791840
search_rebuild_index();
17801841
}
17811842
17821843
/* Always show the status before ending */
17831844
for(i=0; i<count(aSetng); i++){
1784
- fossil_print("%-16s %s\n", aSetng[i].zName,
1845
+ fossil_print("%-17s %s\n", aSetng[i].zName,
17851846
db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
17861847
}
1787
- fossil_print("%-16s %s\n", "Porter stemmer:",
1848
+ fossil_print("%-17s %s\n", "Porter stemmer:",
17881849
db_get_boolean("search-stemmer",0) ? "on" : "off");
17891850
if( search_index_exists() ){
1790
- fossil_print("%-16s enabled\n", "full-text index:");
1791
- fossil_print("%-16s %d\n", "documents:",
1851
+ fossil_print("%-17s enabled\n", "full-text index:");
1852
+ fossil_print("%-17s %d\n", "documents:",
17921853
db_int(0, "SELECT count(*) FROM ftsdocs"));
17931854
}else{
1794
- fossil_print("%-16s disabled\n", "full-text index:");
1855
+ fossil_print("%-17s disabled\n", "full-text index:");
17951856
}
17961857
db_end_transaction(0);
17971858
}
17981859
17991860
/*
18001861
--- src/search.c
+++ src/search.c
@@ -633,15 +633,16 @@
633 db_finalize(&q);
634 }
635
636 #if INTERFACE
637 /* What to search for */
638 #define SRCH_CKIN 0x0001 /* Search over check-in comments */
639 #define SRCH_DOC 0x0002 /* Search over embedded documents */
640 #define SRCH_TKT 0x0004 /* Search over tickets */
641 #define SRCH_WIKI 0x0008 /* Search over wiki */
642 #define SRCH_ALL 0x000f /* Search over everything */
 
643 #endif
644
645 /*
646 ** Remove bits from srchFlags which are disallowed by either the
647 ** current server configuration or by user permissions.
@@ -648,17 +649,18 @@
648 */
649 unsigned int search_restrict(unsigned int srchFlags){
650 static unsigned int knownGood = 0;
651 static unsigned int knownBad = 0;
652 static const struct { unsigned m; const char *zKey; } aSetng[] = {
653 { SRCH_CKIN, "search-ci" },
654 { SRCH_DOC, "search-doc" },
655 { SRCH_TKT, "search-tkt" },
656 { SRCH_WIKI, "search-wiki" },
 
657 };
658 int i;
659 if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC);
660 if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
661 if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
662 for(i=0; i<count(aSetng); i++){
663 unsigned int m = aSetng[i].m;
664 if( (srchFlags & m)==0 ) continue;
@@ -770,10 +772,30 @@
770 " datetime(tkt_mtime),"
771 " search_snippet()"
772 " FROM ticket"
773 " WHERE search_match(title('t',tkt_id,NULL),body('t',tkt_id,NULL));"
774 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
775 }
776 }
777
778 /*
779 ** Number of significant bits in a u32
@@ -886,14 +908,15 @@
886 zPattern
887 );
888 if( srchFlags!=SRCH_ALL ){
889 const char *zSep = " AND (";
890 static const struct { unsigned m; char c; } aMask[] = {
891 { SRCH_CKIN, 'c' },
892 { SRCH_DOC, 'd' },
893 { SRCH_TKT, 't' },
894 { SRCH_WIKI, 'w' },
 
895 };
896 int i;
897 for(i=0; i<count(aMask); i++){
898 if( srchFlags & aMask[i].m ){
899 blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -1037,14 +1060,15 @@
1037 const char *zDisable2;
1038 const char *zPattern;
1039 int fDebug = PB("debug");
1040 srchFlags = search_restrict(srchFlags);
1041 switch( srchFlags ){
1042 case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
1043 case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
1044 case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
1045 case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
 
1046 }
1047 if( srchFlags==0 ){
1048 zDisable1 = " disabled";
1049 zDisable2 = " disabled";
1050 zPattern = "";
@@ -1060,15 +1084,16 @@
1060 @ <div class='searchForm'>
1061 }
1062 @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)>
1063 if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){
1064 static const struct { char *z; char *zNm; unsigned m; } aY[] = {
1065 { "all", "All", SRCH_ALL },
1066 { "c", "Check-ins", SRCH_CKIN },
1067 { "d", "Docs", SRCH_DOC },
1068 { "t", "Tickets", SRCH_TKT },
1069 { "w", "Wiki", SRCH_WIKI },
 
1070 };
1071 const char *zY = PD("y","all");
1072 unsigned newFlags = srchFlags;
1073 int i;
1074 @ <select size='1' name='y'>
@@ -1116,10 +1141,11 @@
1116 ** y=TYPE What to search.
1117 ** c -> check-ins
1118 ** d -> documentation
1119 ** t -> tickets
1120 ** w -> wiki
 
1121 ** all -> everything
1122 */
1123 void search_page(void){
1124 login_check_credentials();
1125 style_header("Search");
@@ -1222,10 +1248,11 @@
1222 **
1223 ** cType: d Embedded documentation
1224 ** w Wiki page
1225 ** c Check-in comment
1226 ** t Ticket text
 
1227 **
1228 ** rid The RID of an artifact that defines the object
1229 ** being searched.
1230 **
1231 ** zName Name of the object being searched. This is used
@@ -1247,12 +1274,14 @@
1247 blob_to_utf8_no_bom(&doc, 0);
1248 get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
1249 blob_reset(&doc);
1250 break;
1251 }
 
1252 case 'w': { /* Wiki */
1253 Manifest *pWiki = manifest_get(rid, CFTYPE_WIKI,0);
 
1254 Blob wiki;
1255 if( pWiki==0 ) break;
1256 blob_init(&wiki, pWiki->zWiki, -1);
1257 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
1258 pOut);
@@ -1367,11 +1396,11 @@
1367 ** COMMAND: test-search-stext
1368 **
1369 ** Usage: fossil test-search-stext TYPE RID NAME
1370 **
1371 ** Compute the search text for document TYPE-RID whose name is NAME.
1372 ** The TYPE is one of "c", "d", "t", or "w". The RID is the document
1373 ** ID. The NAME is used to figure out a mimetype to use for formatting
1374 ** the raw document text.
1375 */
1376 void test_search_stext(void){
1377 Blob out;
@@ -1484,10 +1513,14 @@
1484 );
1485 db_multi_exec(
1486 "INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
1487 " SELECT 't', tkt_id, 0 FROM ticket;"
1488 );
 
 
 
 
1489 }
1490
1491 /*
1492 ** The document described by cType,rid,zName is about to be added or
1493 ** updated. If the document has already been indexed, then unindex it
@@ -1508,19 +1541,19 @@
1508 db_multi_exec(
1509 "REPLACE INTO ftsdocs(type,rid,name,idxed)"
1510 " VALUES(%Q,%d,%Q,0)",
1511 zType, rid, zName
1512 );
1513 if( cType=='w' ){
1514 db_multi_exec(
1515 "DELETE FROM ftsidx WHERE docid IN"
1516 " (SELECT rowid FROM ftsdocs WHERE type='w' AND name=%Q AND idxed)",
1517 zName
1518 );
1519 db_multi_exec(
1520 "DELETE FROM ftsdocs WHERE type='w' AND name=%Q AND rid!=%d",
1521 zName, rid
1522 );
1523 }
1524 }
1525 }
1526
@@ -1647,10 +1680,34 @@
1647 " tagxref.mtime"
1648 " FROM tagxref WHERE tagxref.rid=ftsdocs.rid)"
1649 " WHERE ftsdocs.type='w' AND NOT ftsdocs.idxed"
1650 );
1651 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1652
1653 /*
1654 ** Deal with all of the unindexed entries in the FTSDOCS table - that
1655 ** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the
1656 ** index.
@@ -1667,10 +1724,13 @@
1667 search_update_ticket_index();
1668 }
1669 if( srchFlags & SRCH_WIKI ){
1670 search_update_wiki_index();
1671 }
 
 
 
1672 }
1673
1674 /*
1675 ** Construct, prepopulate, and then update the full-text index.
1676 */
@@ -1694,14 +1754,14 @@
1694 ** reindex Rebuild the search index. This is a no-op if
1695 ** index search is disabled
1696 **
1697 ** index (on|off) Turn the search index on or off
1698 **
1699 ** enable cdtw Enable various kinds of search. c=Check-ins,
1700 ** d=Documents, t=Tickets, w=Wiki.
1701 **
1702 ** disable cdtw Disable various kinds of search
1703 **
1704 ** stemmer (on|off) Turn the Porter stemmer on or off for indexed
1705 ** search. (Unindexed search is never stemmed.)
1706 **
1707 ** The current search settings are displayed after any changes are applied.
@@ -1714,14 +1774,15 @@
1714 { 3, "disable" },
1715 { 4, "enable" },
1716 { 5, "stemmer" },
1717 };
1718 static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = {
1719 { "search-ckin", "check-in search:", "c" },
1720 { "search-doc", "document search:", "d" },
1721 { "search-tkt", "ticket search:", "t" },
1722 { "search-wiki", "wiki search:", "w" },
 
1723 };
1724 char *zSubCmd = 0;
1725 int i, j, n;
1726 int iCmd = 0;
1727 int iAction = 0;
@@ -1779,21 +1840,21 @@
1779 search_rebuild_index();
1780 }
1781
1782 /* Always show the status before ending */
1783 for(i=0; i<count(aSetng); i++){
1784 fossil_print("%-16s %s\n", aSetng[i].zName,
1785 db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
1786 }
1787 fossil_print("%-16s %s\n", "Porter stemmer:",
1788 db_get_boolean("search-stemmer",0) ? "on" : "off");
1789 if( search_index_exists() ){
1790 fossil_print("%-16s enabled\n", "full-text index:");
1791 fossil_print("%-16s %d\n", "documents:",
1792 db_int(0, "SELECT count(*) FROM ftsdocs"));
1793 }else{
1794 fossil_print("%-16s disabled\n", "full-text index:");
1795 }
1796 db_end_transaction(0);
1797 }
1798
1799 /*
1800
--- src/search.c
+++ src/search.c
@@ -633,15 +633,16 @@
633 db_finalize(&q);
634 }
635
636 #if INTERFACE
637 /* What to search for */
638 #define SRCH_CKIN 0x0001 /* Search over check-in comments */
639 #define SRCH_DOC 0x0002 /* Search over embedded documents */
640 #define SRCH_TKT 0x0004 /* Search over tickets */
641 #define SRCH_WIKI 0x0008 /* Search over wiki */
642 #define SRCH_TECHNOTE 0x0010 /* Search over tech notes */
643 #define SRCH_ALL 0x001f /* Search over everything */
644 #endif
645
646 /*
647 ** Remove bits from srchFlags which are disallowed by either the
648 ** current server configuration or by user permissions.
@@ -648,17 +649,18 @@
649 */
650 unsigned int search_restrict(unsigned int srchFlags){
651 static unsigned int knownGood = 0;
652 static unsigned int knownBad = 0;
653 static const struct { unsigned m; const char *zKey; } aSetng[] = {
654 { SRCH_CKIN, "search-ci" },
655 { SRCH_DOC, "search-doc" },
656 { SRCH_TKT, "search-tkt" },
657 { SRCH_WIKI, "search-wiki" },
658 { SRCH_TECHNOTE, "search-technote" },
659 };
660 int i;
661 if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_TECHNOTE);
662 if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
663 if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
664 for(i=0; i<count(aSetng); i++){
665 unsigned int m = aSetng[i].m;
666 if( (srchFlags & m)==0 ) continue;
@@ -770,10 +772,30 @@
772 " datetime(tkt_mtime),"
773 " search_snippet()"
774 " FROM ticket"
775 " WHERE search_match(title('t',tkt_id,NULL),body('t',tkt_id,NULL));"
776 );
777 }
778 if( (srchFlags & SRCH_TECHNOTE)!=0 ){
779 db_multi_exec(
780 "WITH technote(uuid,rid,mtime) AS ("
781 " SELECT substr(tagname,7), tagxref.rid, max(tagxref.mtime)"
782 " FROM tag, tagxref"
783 " WHERE tag.tagname GLOB 'event-*'"
784 " AND tagxref.tagid=tag.tagid"
785 " GROUP BY 1"
786 ")"
787 "INSERT INTO x(label,url,score,id,date,snip)"
788 " SELECT printf('Tech Note: %%s',uuid),"
789 " printf('/technote/%%s',uuid),"
790 " search_score(),"
791 " 'e'||rid,"
792 " datetime(mtime),"
793 " search_snippet()"
794 " FROM technote"
795 " WHERE search_match('',body('e',rid,NULL));"
796 );
797 }
798 }
799
800 /*
801 ** Number of significant bits in a u32
@@ -886,14 +908,15 @@
908 zPattern
909 );
910 if( srchFlags!=SRCH_ALL ){
911 const char *zSep = " AND (";
912 static const struct { unsigned m; char c; } aMask[] = {
913 { SRCH_CKIN, 'c' },
914 { SRCH_DOC, 'd' },
915 { SRCH_TKT, 't' },
916 { SRCH_WIKI, 'w' },
917 { SRCH_TECHNOTE, 'e' },
918 };
919 int i;
920 for(i=0; i<count(aMask); i++){
921 if( srchFlags & aMask[i].m ){
922 blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
@@ -1037,14 +1060,15 @@
1060 const char *zDisable2;
1061 const char *zPattern;
1062 int fDebug = PB("debug");
1063 srchFlags = search_restrict(srchFlags);
1064 switch( srchFlags ){
1065 case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
1066 case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
1067 case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
1068 case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
1069 case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break;
1070 }
1071 if( srchFlags==0 ){
1072 zDisable1 = " disabled";
1073 zDisable2 = " disabled";
1074 zPattern = "";
@@ -1060,15 +1084,16 @@
1084 @ <div class='searchForm'>
1085 }
1086 @ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)>
1087 if( useYparam && (srchFlags & (srchFlags-1))!=0 && useYparam ){
1088 static const struct { char *z; char *zNm; unsigned m; } aY[] = {
1089 { "all", "All", SRCH_ALL },
1090 { "c", "Check-ins", SRCH_CKIN },
1091 { "d", "Docs", SRCH_DOC },
1092 { "t", "Tickets", SRCH_TKT },
1093 { "w", "Wiki", SRCH_WIKI },
1094 { "e", "Tech Notes", SRCH_TECHNOTE },
1095 };
1096 const char *zY = PD("y","all");
1097 unsigned newFlags = srchFlags;
1098 int i;
1099 @ <select size='1' name='y'>
@@ -1116,10 +1141,11 @@
1141 ** y=TYPE What to search.
1142 ** c -> check-ins
1143 ** d -> documentation
1144 ** t -> tickets
1145 ** w -> wiki
1146 ** e -> tech notes
1147 ** all -> everything
1148 */
1149 void search_page(void){
1150 login_check_credentials();
1151 style_header("Search");
@@ -1222,10 +1248,11 @@
1248 **
1249 ** cType: d Embedded documentation
1250 ** w Wiki page
1251 ** c Check-in comment
1252 ** t Ticket text
1253 ** e Tech note
1254 **
1255 ** rid The RID of an artifact that defines the object
1256 ** being searched.
1257 **
1258 ** zName Name of the object being searched. This is used
@@ -1247,12 +1274,14 @@
1274 blob_to_utf8_no_bom(&doc, 0);
1275 get_stext_by_mimetype(&doc, mimetype_from_name(zName), pOut);
1276 blob_reset(&doc);
1277 break;
1278 }
1279 case 'e': /* Tech Notes */
1280 case 'w': { /* Wiki */
1281 Manifest *pWiki = manifest_get(rid,
1282 cType == 'e' ? CFTYPE_EVENT : CFTYPE_WIKI, 0);
1283 Blob wiki;
1284 if( pWiki==0 ) break;
1285 blob_init(&wiki, pWiki->zWiki, -1);
1286 get_stext_by_mimetype(&wiki, wiki_filter_mimetypes(pWiki->zMimetype),
1287 pOut);
@@ -1367,11 +1396,11 @@
1396 ** COMMAND: test-search-stext
1397 **
1398 ** Usage: fossil test-search-stext TYPE RID NAME
1399 **
1400 ** Compute the search text for document TYPE-RID whose name is NAME.
1401 ** The TYPE is one of "c", "d", "t", "w", or "e". The RID is the document
1402 ** ID. The NAME is used to figure out a mimetype to use for formatting
1403 ** the raw document text.
1404 */
1405 void test_search_stext(void){
1406 Blob out;
@@ -1484,10 +1513,14 @@
1513 );
1514 db_multi_exec(
1515 "INSERT OR IGNORE INTO ftsdocs(type,rid,idxed)"
1516 " SELECT 't', tkt_id, 0 FROM ticket;"
1517 );
1518 db_multi_exec(
1519 "INSERT OR IGNORE INTO ftsdocs(type,rid,name,idxed)"
1520 " SELECT 'e', objid, comment, 0 FROM event WHERE type='e';"
1521 );
1522 }
1523
1524 /*
1525 ** The document described by cType,rid,zName is about to be added or
1526 ** updated. If the document has already been indexed, then unindex it
@@ -1508,19 +1541,19 @@
1541 db_multi_exec(
1542 "REPLACE INTO ftsdocs(type,rid,name,idxed)"
1543 " VALUES(%Q,%d,%Q,0)",
1544 zType, rid, zName
1545 );
1546 if( cType=='w' || cType=='e' ){
1547 db_multi_exec(
1548 "DELETE FROM ftsidx WHERE docid IN"
1549 " (SELECT rowid FROM ftsdocs WHERE type='%c' AND name=%Q AND idxed)",
1550 cType, zName
1551 );
1552 db_multi_exec(
1553 "DELETE FROM ftsdocs WHERE type='%c' AND name=%Q AND rid!=%d",
1554 cType, zName, rid
1555 );
1556 }
1557 }
1558 }
1559
@@ -1647,10 +1680,34 @@
1680 " tagxref.mtime"
1681 " FROM tagxref WHERE tagxref.rid=ftsdocs.rid)"
1682 " WHERE ftsdocs.type='w' AND NOT ftsdocs.idxed"
1683 );
1684 }
1685
1686 /*
1687 ** Deal with all of the unindexed 'e' terms in FTSDOCS
1688 */
1689 static void search_update_technote_index(void){
1690 db_multi_exec(
1691 "INSERT INTO ftsidx(docid,title,body)"
1692 " SELECT rowid, title('e',rid,NULL),body('e',rid,NULL) FROM ftsdocs"
1693 " WHERE type='e' AND NOT idxed;"
1694 );
1695 if( db_changes()==0 ) return;
1696 db_multi_exec(
1697 "UPDATE ftsdocs SET idxed=1,"
1698 " (name,label,url,mtime) = "
1699 " (SELECT ftsdocs.name,"
1700 " 'Tech Note: '||ftsdocs.name,"
1701 " '/technote/'||substr(tag.tagname,7),"
1702 " tagxref.mtime"
1703 " FROM tagxref, tag USING (tagid)"
1704 " WHERE tagxref.rid=ftsdocs.rid"
1705 " AND tagname GLOB 'event-*')"
1706 " WHERE ftsdocs.type='e' AND NOT ftsdocs.idxed"
1707 );
1708 }
1709
1710 /*
1711 ** Deal with all of the unindexed entries in the FTSDOCS table - that
1712 ** is to say, all the entries with FTSDOCS.IDXED=0. Add them to the
1713 ** index.
@@ -1667,10 +1724,13 @@
1724 search_update_ticket_index();
1725 }
1726 if( srchFlags & SRCH_WIKI ){
1727 search_update_wiki_index();
1728 }
1729 if( srchFlags & SRCH_TECHNOTE ){
1730 search_update_technote_index();
1731 }
1732 }
1733
1734 /*
1735 ** Construct, prepopulate, and then update the full-text index.
1736 */
@@ -1694,14 +1754,14 @@
1754 ** reindex Rebuild the search index. This is a no-op if
1755 ** index search is disabled
1756 **
1757 ** index (on|off) Turn the search index on or off
1758 **
1759 ** enable cdtwe Enable various kinds of search. c=Check-ins,
1760 ** d=Documents, t=Tickets, w=Wiki, e=Tech Notes.
1761 **
1762 ** disable cdtwe Disable various kinds of search
1763 **
1764 ** stemmer (on|off) Turn the Porter stemmer on or off for indexed
1765 ** search. (Unindexed search is never stemmed.)
1766 **
1767 ** The current search settings are displayed after any changes are applied.
@@ -1714,14 +1774,15 @@
1774 { 3, "disable" },
1775 { 4, "enable" },
1776 { 5, "stemmer" },
1777 };
1778 static const struct { char *zSetting; char *zName; char *zSw; } aSetng[] = {
1779 { "search-ckin", "check-in search:", "c" },
1780 { "search-doc", "document search:", "d" },
1781 { "search-tkt", "ticket search:", "t" },
1782 { "search-wiki", "wiki search:", "w" },
1783 { "search-technote", "tech note search:", "e" },
1784 };
1785 char *zSubCmd = 0;
1786 int i, j, n;
1787 int iCmd = 0;
1788 int iAction = 0;
@@ -1779,21 +1840,21 @@
1840 search_rebuild_index();
1841 }
1842
1843 /* Always show the status before ending */
1844 for(i=0; i<count(aSetng); i++){
1845 fossil_print("%-17s %s\n", aSetng[i].zName,
1846 db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
1847 }
1848 fossil_print("%-17s %s\n", "Porter stemmer:",
1849 db_get_boolean("search-stemmer",0) ? "on" : "off");
1850 if( search_index_exists() ){
1851 fossil_print("%-17s enabled\n", "full-text index:");
1852 fossil_print("%-17s %d\n", "documents:",
1853 db_int(0, "SELECT count(*) FROM ftsdocs"));
1854 }else{
1855 fossil_print("%-17s disabled\n", "full-text index:");
1856 }
1857 db_end_transaction(0);
1858 }
1859
1860 /*
1861
+3 -1
--- src/setup.c
+++ src/setup.c
@@ -2281,11 +2281,13 @@
22812281
@ <br />
22822282
onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
22832283
@ <br />
22842284
onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
22852285
@ <br />
2286
- onoff_attribute("Search Wiki","search-wiki", "sw", 0, 0);
2286
+ onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
2287
+ @ <br />
2288
+ onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
22872289
@ <hr />
22882290
@ <p><input type="submit" name="submit" value="Apply Changes" /></p>
22892291
@ <hr />
22902292
if( P("fts0") ){
22912293
search_drop_index();
22922294
--- src/setup.c
+++ src/setup.c
@@ -2281,11 +2281,13 @@
2281 @ <br />
2282 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2283 @ <br />
2284 onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
2285 @ <br />
2286 onoff_attribute("Search Wiki","search-wiki", "sw", 0, 0);
 
 
2287 @ <hr />
2288 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
2289 @ <hr />
2290 if( P("fts0") ){
2291 search_drop_index();
2292
--- src/setup.c
+++ src/setup.c
@@ -2281,11 +2281,13 @@
2281 @ <br />
2282 onoff_attribute("Search Documents", "search-doc", "sd", 0, 0);
2283 @ <br />
2284 onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
2285 @ <br />
2286 onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
2287 @ <br />
2288 onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
2289 @ <hr />
2290 @ <p><input type="submit" name="submit" value="Apply Changes" /></p>
2291 @ <hr />
2292 if( P("fts0") ){
2293 search_drop_index();
2294
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,10 +1,11 @@
11
<title>Change Log</title>
22
33
<a name='v2_4'></a>
44
<h2>Changes for Version 2.4 (TBD)</h2>
55
6
+ * Add tech note search capability.
67
* Add the -r|--revision option to the annotate command.
78
* Support for URL Aliases added. URL Aliases allow an administrator
89
to define their own URLs on the web interface that are rewritten to
910
built-in URLs with specific parameters.
1011
* Provide separate on-line help screens for each setting.
1112
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,10 +1,11 @@
1 <title>Change Log</title>
2
3 <a name='v2_4'></a>
4 <h2>Changes for Version 2.4 (TBD)</h2>
5
 
6 * Add the -r|--revision option to the annotate command.
7 * Support for URL Aliases added. URL Aliases allow an administrator
8 to define their own URLs on the web interface that are rewritten to
9 built-in URLs with specific parameters.
10 * Provide separate on-line help screens for each setting.
11
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,10 +1,11 @@
1 <title>Change Log</title>
2
3 <a name='v2_4'></a>
4 <h2>Changes for Version 2.4 (TBD)</h2>
5
6 * Add tech note search capability.
7 * Add the -r|--revision option to the annotate command.
8 * Support for URL Aliases added. URL Aliases allow an administrator
9 to define their own URLs on the web interface that are rewritten to
10 built-in URLs with specific parameters.
11 * Provide separate on-line help screens for each setting.
12

Keyboard Shortcuts

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