Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Add the ft=TAG query parameter to /timeline which, in combination with d=Y shows all descendants of Y up to TAG. Implementation of enhancement request [eadfb8c2ffa9fe03]. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
64f141fce02f83497f54d12da457969b |
| User & Date: | drh 2023-03-27 13:41:25.164 |
Context
|
2023-03-28
| ||
| 00:02 | Post-sleep edit pass on the new material in §3.2 of the containers doc. check-in: d21fb2678a user: wyoung tags: trunk | |
|
2023-03-27
| ||
| 13:41 | Add the ft=TAG query parameter to /timeline which, in combination with d=Y shows all descendants of Y up to TAG. Implementation of enhancement request [eadfb8c2ffa9fe03]. check-in: 64f141fce0 user: drh tags: trunk | |
| 07:24 | Refined the Tcl and Python examples in the new §3.2 of the container doc. check-in: 9baa4423f6 user: wyoung tags: trunk | |
Changes
Changes to src/name.c.
| ︙ | ︙ | |||
249 250 251 252 253 254 255 | /* ** Find the RID for a check-in that is the most recent check-in with ** tag zTag that occurs on or prior to rDate. ** ** See also the performance note on most_recent_event_with_tag() which ** applies to this routine too. */ | | | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
/*
** Find the RID for a check-in that is the most recent check-in with
** tag zTag that occurs on or prior to rDate.
**
** See also the performance note on most_recent_event_with_tag() which
** applies to this routine too.
*/
int last_checkin_with_tag_before_date(const char *zTag, double rLimit){
Stmt s;
int rid = 0;
if( strncmp(zTag, "tag:", 4)==0 ) zTag += 4;
db_prepare(&s,
"SELECT objid FROM ("
/* Q1: Begin by looking for the tag in the 30 most recent events */
"SELECT objid"
|
| ︙ | ︙ | |||
285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
") LIMIT 1;",
zTag, zTag
);
db_bind_double(&s, ":datelimit", rLimit);
if( db_step(&s)==SQLITE_ROW ){
rid = db_column_int(&s,0);
}
db_finalize(&s);
return rid;
}
/*
** Return true if character "c" is a character that might have been
** accidentally appended to the end of a URL.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
") LIMIT 1;",
zTag, zTag
);
db_bind_double(&s, ":datelimit", rLimit);
if( db_step(&s)==SQLITE_ROW ){
rid = db_column_int(&s,0);
}
db_finalize(&s);
return rid;
}
/*
** Find the RID of the first check-in (chronologically) after rStart that
** has tag zTag.
**
** See also the performance note on most_recent_event_with_tag() which
** applies to this routine too.
*/
int first_checkin_with_tag_after_date(const char *zTag, double rStart){
Stmt s;
int rid = 0;
if( strncmp(zTag, "tag:", 4)==0 ) zTag += 4;
db_prepare(&s,
"SELECT objid FROM ("
/* Q1: Begin by looking for the tag in the 30 most recent events */
"SELECT objid"
" FROM (SELECT * FROM event WHERE mtime>=:startdate"
" ORDER BY mtime LIMIT 30) AS ex"
" WHERE type='ci'"
" AND EXISTS(SELECT 1 FROM tagxref, tag"
" WHERE tag.tagname='sym-%q'"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND tagxref.rid=ex.objid)"
" ORDER BY mtime LIMIT 1"
") UNION ALL SELECT * FROM ("
/* Q2: If the tag is not found in the 30 most recent events, then using
** the tagxref table to index for the tag */
"SELECT event.objid"
" FROM tag, tagxref, event"
" WHERE tag.tagname='sym-%q'"
" AND tagxref.tagid=tag.tagid"
" AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid"
" AND event.type='ci'"
" AND event.mtime>=:startdate"
" ORDER BY event.mtime LIMIT 1"
") LIMIT 1;",
zTag, zTag
);
db_bind_double(&s, ":startdate", rStart);
if( db_step(&s)==SQLITE_ROW ){
rid = db_column_int(&s,0);
}
db_finalize(&s);
return rid;
}
/*
** Return true if character "c" is a character that might have been
** accidentally appended to the end of a URL.
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 | ** sel2=TIMEORTAG Like sel1= but use the secondary highlight. ** n=COUNT Maximum number of events. "all" for no limit ** n1=COUNT Same as "n" but doesn't set the display-preference cookie ** Use "n1=COUNT" for a one-time display change ** p=CHECKIN Parents and ancestors of CHECKIN ** bt=PRIOR ... going back to PRIOR ** d=CHECKIN Children and descendants of CHECKIN ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" ** bt=CHECKIN In conjunction with p=CX, this means show all ** ancestors of CX going back to the time of CHECKIN. ** All qualifying check-ins are shown unless there ** is also an n= or n1= query parameter. ** t=TAG Show only check-ins with the given TAG | > | 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 | ** sel2=TIMEORTAG Like sel1= but use the secondary highlight. ** n=COUNT Maximum number of events. "all" for no limit ** n1=COUNT Same as "n" but doesn't set the display-preference cookie ** Use "n1=COUNT" for a one-time display change ** p=CHECKIN Parents and ancestors of CHECKIN ** bt=PRIOR ... going back to PRIOR ** d=CHECKIN Children and descendants of CHECKIN ** ft=DESCENDANT ... going forward to DESCENDANT ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" ** bt=CHECKIN In conjunction with p=CX, this means show all ** ancestors of CX going back to the time of CHECKIN. ** All qualifying check-ins are shown unless there ** is also an n= or n1= query parameter. ** t=TAG Show only check-ins with the given TAG |
| ︙ | ︙ | |||
2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 |
addFileGlobDescription(zChng, &desc);
}else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){
/* If p= or d= is present, ignore all other parameters other than n= */
char *zUuid;
const char *zCiName;
int np = 0, nd;
const char *zBackTo = 0;
int ridBackTo = 0;
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
if( p_rid && d_rid ){
if( p_rid!=d_rid ) p_rid = d_rid;
if( !haveParameterN ) nEntry = 10;
}
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
);
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
p_rid ? p_rid : d_rid);
zCiName = pd_rid ? P("pd") : p_rid ? P("p") : P("d");
if( zCiName==0 ) zCiName = zUuid;
blob_append_sql(&sql, " AND event.objid IN ok");
nd = 0;
if( d_rid ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < | < | > | 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 |
addFileGlobDescription(zChng, &desc);
}else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){
/* If p= or d= is present, ignore all other parameters other than n= */
char *zUuid;
const char *zCiName;
int np = 0, nd;
const char *zBackTo = 0;
const char *zFwdTo = 0;
int ridBackTo = 0;
int ridFwdTo = 0;
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
if( p_rid && d_rid ){
if( p_rid!=d_rid ) p_rid = d_rid;
if( !haveParameterN ) nEntry = 10;
}
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
);
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d",
p_rid ? p_rid : d_rid);
zCiName = pd_rid ? P("pd") : p_rid ? P("p") : P("d");
if( zCiName==0 ) zCiName = zUuid;
blob_append_sql(&sql, " AND event.objid IN ok");
nd = 0;
if( d_rid ){
Stmt s;
double rStopTime = 9e99;
zFwdTo = P("ft");
if( zFwdTo ){
double rStartDate = db_double(0.0,
"SELECT mtime FROM event WHERE objid=%d", d_rid);
ridFwdTo = first_checkin_with_tag_after_date(zFwdTo, rStartDate);
if( ridFwdTo==0 ){
ridFwdTo = name_to_typed_rid(zBackTo,"ci");
}
if( ridFwdTo ){
if( !haveParameterN ) nEntry = 0;
rStopTime = db_double(9e99,
"SELECT mtime FROM event WHERE objid=%d", ridFwdTo);
}
}
db_prepare(&s,
"WITH RECURSIVE"
" dx(rid,mtime) AS ("
" SELECT %d, 0"
" UNION"
" SELECT plink.cid, plink.mtime FROM dx, plink"
" WHERE plink.pid=dx.rid"
" AND (:stop>=8e99 OR plink.mtime<=:stop)"
" ORDER BY 2"
" )"
"INSERT OR IGNORE INTO ok SELECT rid FROM dx LIMIT %d",
d_rid, nEntry<=0 ? -1 : nEntry+1
);
db_bind_double(&s, ":stop", rStopTime);
db_step(&s);
db_finalize(&s);
/* compute_descendants(d_rid, nEntry==0 ? 0 : nEntry+1); */
nd = db_int(0, "SELECT count(*)-1 FROM ok");
if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql));
if( nd>0 || p_rid==0 ){
blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
}
if( useDividers && !selectedRid ) selectedRid = d_rid;
db_multi_exec("DELETE FROM ok");
}
if( p_rid ){
zBackTo = P("bt");
if( zBackTo ){
double rDateLimit = db_double(0.0,
"SELECT mtime FROM event WHERE objid=%d", p_rid);
ridBackTo = last_checkin_with_tag_before_date(zBackTo, rDateLimit);
if( ridBackTo==0 ){
ridBackTo = name_to_typed_rid(zBackTo,"ci");
}
if( ridBackTo && !haveParameterN ) nEntry = 0;
}
compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo);
np = db_int(0, "SELECT count(*)-1 FROM ok");
if( np>0 || nd==0 ){
if( nd>0 ) blob_appendf(&desc, " and ");
blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s");
db_multi_exec("%s", blob_sql_text(&sql));
}
|
| ︙ | ︙ | |||
2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 |
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> is not an ancestor)",
href("%R/info?name=%h",zCiName), zCiName,
href("%R/info?name=%h",zBackTo), zBackTo);
}else{
blob_appendf(&desc, " back to %z%h</a>",
href("%R/info?name=%h",zBackTo), zBackTo);
}
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
| > > > > > > > > > > > > > > > | 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 |
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> is not an ancestor)",
href("%R/info?name=%h",zCiName), zCiName,
href("%R/info?name=%h",zBackTo), zBackTo);
}else{
blob_appendf(&desc, " back to %z%h</a>",
href("%R/info?name=%h",zBackTo), zBackTo);
if( ridFwdTo && zFwdTo ){
blob_appendf(&desc, " and up to %z%h</a>",
href("%R/info?name=%h",zFwdTo), zFwdTo);
}
}
}else if( ridFwdTo ){
if( nd==0 ){
blob_reset(&desc);
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> is not an descendant)",
href("%R/info?name=%h",zCiName), zCiName,
href("%R/info?name=%h",zFwdTo), zFwdTo);
}else{
blob_appendf(&desc, " up to %z%h</a>",
href("%R/info?name=%h",zFwdTo), zFwdTo);
}
}
if( d_rid ){
if( p_rid ){
/* If both p= and d= are set, we don't have the uuid of d yet. */
zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", d_rid);
}
|
| ︙ | ︙ |