Fossil SCM

If neither <var>TICKET</var> nor <var>TICKETCHNG</var> table has regular "mimetype" column then generated "mimetype" columns of these two tables are queried and used during the extraction of backlinks from ticket change artifacts. See [forum:/forumpost/40c1208a0f84fabe|forum post 40c1208a0f84] for rationale.

george 2022-05-24 20:32 trunk merge
Commit 6fb642c02b48ca7db95149e30836f654e2eec84f396b7b6f1a95b8eb9f7c7b28
+19 -5
--- src/backlink.c
+++ src/backlink.c
@@ -179,11 +179,12 @@
179179
rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
180180
" ORDER BY mtime DESC LIMIT 1", tagid);
181181
if( rid==0 ) return;
182182
pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
183183
if( pWiki ){
184
- backlink_extract(pWiki->zWiki, pWiki->zMimetype, tagid, BKLNK_WIKI,
184
+ int mimetype = parse_mimetype( pWiki->zMimetype );
185
+ backlink_extract(pWiki->zWiki, mimetype, tagid, BKLNK_WIKI,
185186
pWiki->rDate, 1);
186187
manifest_destroy(pWiki);
187188
}
188189
}
189190
@@ -295,17 +296,28 @@
295296
markdown(&out, &in, &html_renderer);
296297
blob_reset(&out);
297298
blob_reset(&in);
298299
}
299300
301
+/*
302
+** Transform mimetype string into an integer code.
303
+** NOTE: In the sake of compatability empty string is parsed as MT_UNKNOWN;
304
+** it is yet unclear whether it can safely be changed to MT_NONE.
305
+*/
306
+int parse_mimetype(const char* zMimetype){
307
+ if( zMimetype==0 ) return MT_NONE;
308
+ if( strstr(zMimetype,"wiki")!=0 ) return MT_WIKI;
309
+ if( strstr(zMimetype,"markdown")!=0 ) return MT_MARKDOWN;
310
+ return MT_UNKNOWN;
311
+}
300312
/*
301313
** Parse text looking for hyperlinks. Insert references into the
302314
** BACKLINK table.
303315
*/
304316
void backlink_extract(
305317
char *zSrc, /* Input text from which links are extracted */
306
- const char *zMimetype, /* Mimetype of input. NULL means fossil-wiki */
318
+ int mimetype, /* Mimetype of input. MT_NONE works as MT_WIKI */
307319
int srcid, /* srcid for the source document */
308320
int srctype, /* One of BKLNK_*. 0=comment 1=ticket 2=wiki */
309321
double mtime, /* mtime field for new BACKLINK table entries */
310322
int replaceFlag /* True to overwrite prior BACKLINK entries */
311323
){
@@ -314,15 +326,16 @@
314326
db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
315327
srctype, srcid);
316328
}
317329
bklnk.srcid = srcid;
318330
assert( ValidBklnk(srctype) );
331
+ assert( ValidMTC(mimetype) );
319332
bklnk.srctype = srctype;
320333
bklnk.mtime = mtime;
321
- if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
334
+ if( mimetype==MT_NONE || mimetype==MT_WIKI ){
322335
wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
323
- }else if( strstr(zMimetype,"markdown")!=0 ){
336
+ }else if( mimetype==MT_MARKDOWN ){
324337
markdown_extract_links(zSrc, &bklnk);
325338
}
326339
}
327340
328341
/*
@@ -340,10 +353,11 @@
340353
** --mimetype TYPE Use an alternative mimetype.
341354
*/
342355
void test_backlinks_cmd(void){
343356
const char *zMTime = find_option("mtime",0,1);
344357
const char *zMimetype = find_option("mimetype",0,1);
358
+ const int mimetype = parse_mimetype(zMimetype);
345359
Blob in;
346360
int srcid;
347361
int srctype;
348362
double mtime;
349363
@@ -371,11 +385,11 @@
371385
" ' srcid='||quote(new.srcid)||"
372386
" ' mtime='||datetime(new.mtime));\n"
373387
" SELECT raise(ignore);\n"
374388
"END;"
375389
);
376
- backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
390
+ backlink_extract(blob_str(&in),mimetype,srcid,srctype,mtime,0);
377391
blob_reset(&in);
378392
}
379393
380394
381395
/*
382396
--- src/backlink.c
+++ src/backlink.c
@@ -179,11 +179,12 @@
179 rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
180 " ORDER BY mtime DESC LIMIT 1", tagid);
181 if( rid==0 ) return;
182 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
183 if( pWiki ){
184 backlink_extract(pWiki->zWiki, pWiki->zMimetype, tagid, BKLNK_WIKI,
 
185 pWiki->rDate, 1);
186 manifest_destroy(pWiki);
187 }
188 }
189
@@ -295,17 +296,28 @@
295 markdown(&out, &in, &html_renderer);
296 blob_reset(&out);
297 blob_reset(&in);
298 }
299
 
 
 
 
 
 
 
 
 
 
 
300 /*
301 ** Parse text looking for hyperlinks. Insert references into the
302 ** BACKLINK table.
303 */
304 void backlink_extract(
305 char *zSrc, /* Input text from which links are extracted */
306 const char *zMimetype, /* Mimetype of input. NULL means fossil-wiki */
307 int srcid, /* srcid for the source document */
308 int srctype, /* One of BKLNK_*. 0=comment 1=ticket 2=wiki */
309 double mtime, /* mtime field for new BACKLINK table entries */
310 int replaceFlag /* True to overwrite prior BACKLINK entries */
311 ){
@@ -314,15 +326,16 @@
314 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
315 srctype, srcid);
316 }
317 bklnk.srcid = srcid;
318 assert( ValidBklnk(srctype) );
 
319 bklnk.srctype = srctype;
320 bklnk.mtime = mtime;
321 if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
322 wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
323 }else if( strstr(zMimetype,"markdown")!=0 ){
324 markdown_extract_links(zSrc, &bklnk);
325 }
326 }
327
328 /*
@@ -340,10 +353,11 @@
340 ** --mimetype TYPE Use an alternative mimetype.
341 */
342 void test_backlinks_cmd(void){
343 const char *zMTime = find_option("mtime",0,1);
344 const char *zMimetype = find_option("mimetype",0,1);
 
345 Blob in;
346 int srcid;
347 int srctype;
348 double mtime;
349
@@ -371,11 +385,11 @@
371 " ' srcid='||quote(new.srcid)||"
372 " ' mtime='||datetime(new.mtime));\n"
373 " SELECT raise(ignore);\n"
374 "END;"
375 );
376 backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
377 blob_reset(&in);
378 }
379
380
381 /*
382
--- src/backlink.c
+++ src/backlink.c
@@ -179,11 +179,12 @@
179 rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
180 " ORDER BY mtime DESC LIMIT 1", tagid);
181 if( rid==0 ) return;
182 pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
183 if( pWiki ){
184 int mimetype = parse_mimetype( pWiki->zMimetype );
185 backlink_extract(pWiki->zWiki, mimetype, tagid, BKLNK_WIKI,
186 pWiki->rDate, 1);
187 manifest_destroy(pWiki);
188 }
189 }
190
@@ -295,17 +296,28 @@
296 markdown(&out, &in, &html_renderer);
297 blob_reset(&out);
298 blob_reset(&in);
299 }
300
301 /*
302 ** Transform mimetype string into an integer code.
303 ** NOTE: In the sake of compatability empty string is parsed as MT_UNKNOWN;
304 ** it is yet unclear whether it can safely be changed to MT_NONE.
305 */
306 int parse_mimetype(const char* zMimetype){
307 if( zMimetype==0 ) return MT_NONE;
308 if( strstr(zMimetype,"wiki")!=0 ) return MT_WIKI;
309 if( strstr(zMimetype,"markdown")!=0 ) return MT_MARKDOWN;
310 return MT_UNKNOWN;
311 }
312 /*
313 ** Parse text looking for hyperlinks. Insert references into the
314 ** BACKLINK table.
315 */
316 void backlink_extract(
317 char *zSrc, /* Input text from which links are extracted */
318 int mimetype, /* Mimetype of input. MT_NONE works as MT_WIKI */
319 int srcid, /* srcid for the source document */
320 int srctype, /* One of BKLNK_*. 0=comment 1=ticket 2=wiki */
321 double mtime, /* mtime field for new BACKLINK table entries */
322 int replaceFlag /* True to overwrite prior BACKLINK entries */
323 ){
@@ -314,15 +326,16 @@
326 db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
327 srctype, srcid);
328 }
329 bklnk.srcid = srcid;
330 assert( ValidBklnk(srctype) );
331 assert( ValidMTC(mimetype) );
332 bklnk.srctype = srctype;
333 bklnk.mtime = mtime;
334 if( mimetype==MT_NONE || mimetype==MT_WIKI ){
335 wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
336 }else if( mimetype==MT_MARKDOWN ){
337 markdown_extract_links(zSrc, &bklnk);
338 }
339 }
340
341 /*
@@ -340,10 +353,11 @@
353 ** --mimetype TYPE Use an alternative mimetype.
354 */
355 void test_backlinks_cmd(void){
356 const char *zMTime = find_option("mtime",0,1);
357 const char *zMimetype = find_option("mimetype",0,1);
358 const int mimetype = parse_mimetype(zMimetype);
359 Blob in;
360 int srcid;
361 int srctype;
362 double mtime;
363
@@ -371,11 +385,11 @@
385 " ' srcid='||quote(new.srcid)||"
386 " ' mtime='||datetime(new.mtime));\n"
387 " SELECT raise(ignore);\n"
388 "END;"
389 );
390 backlink_extract(blob_str(&in),mimetype,srcid,srctype,mtime,0);
391 blob_reset(&in);
392 }
393
394
395 /*
396
+3 -2
--- src/manifest.c
+++ src/manifest.c
@@ -2395,11 +2395,11 @@
23952395
rid, p->zUser, p->zComment,
23962396
TAG_BGCOLOR, rid,
23972397
TAG_USER, rid,
23982398
TAG_COMMENT, rid, p->rDate
23992399
);
2400
- backlink_extract(zCom, 0, rid, BKLNK_COMMENT, p->rDate, 1);
2400
+ backlink_extract(zCom, MT_NONE, rid, BKLNK_COMMENT, p->rDate, 1);
24012401
fossil_free(zCom);
24022402
24032403
/* If this is a delta-manifest, record the fact that this repository
24042404
** contains delta manifests, to free the "commit" logic to generate
24052405
** new delta manifests.
@@ -2853,11 +2853,12 @@
28532853
p->rDate, rid, p->zUser, zFType, zTitle
28542854
);
28552855
fossil_free(zTitle);
28562856
}
28572857
if( p->zWiki[0] ){
2858
- backlink_extract(p->zWiki, p->zMimetype, rid, BKLNK_FORUM, p->rDate, 1);
2858
+ int mimetype = parse_mimetype(p->zMimetype);
2859
+ backlink_extract(p->zWiki, mimetype, rid, BKLNK_FORUM, p->rDate, 1);
28592860
}
28602861
}
28612862
28622863
db_end_transaction(0);
28632864
if( permitHooks ){
28642865
--- src/manifest.c
+++ src/manifest.c
@@ -2395,11 +2395,11 @@
2395 rid, p->zUser, p->zComment,
2396 TAG_BGCOLOR, rid,
2397 TAG_USER, rid,
2398 TAG_COMMENT, rid, p->rDate
2399 );
2400 backlink_extract(zCom, 0, rid, BKLNK_COMMENT, p->rDate, 1);
2401 fossil_free(zCom);
2402
2403 /* If this is a delta-manifest, record the fact that this repository
2404 ** contains delta manifests, to free the "commit" logic to generate
2405 ** new delta manifests.
@@ -2853,11 +2853,12 @@
2853 p->rDate, rid, p->zUser, zFType, zTitle
2854 );
2855 fossil_free(zTitle);
2856 }
2857 if( p->zWiki[0] ){
2858 backlink_extract(p->zWiki, p->zMimetype, rid, BKLNK_FORUM, p->rDate, 1);
 
2859 }
2860 }
2861
2862 db_end_transaction(0);
2863 if( permitHooks ){
2864
--- src/manifest.c
+++ src/manifest.c
@@ -2395,11 +2395,11 @@
2395 rid, p->zUser, p->zComment,
2396 TAG_BGCOLOR, rid,
2397 TAG_USER, rid,
2398 TAG_COMMENT, rid, p->rDate
2399 );
2400 backlink_extract(zCom, MT_NONE, rid, BKLNK_COMMENT, p->rDate, 1);
2401 fossil_free(zCom);
2402
2403 /* If this is a delta-manifest, record the fact that this repository
2404 ** contains delta manifests, to free the "commit" logic to generate
2405 ** new delta manifests.
@@ -2853,11 +2853,12 @@
2853 p->rDate, rid, p->zUser, zFType, zTitle
2854 );
2855 fossil_free(zTitle);
2856 }
2857 if( p->zWiki[0] ){
2858 int mimetype = parse_mimetype(p->zMimetype);
2859 backlink_extract(p->zWiki, mimetype, rid, BKLNK_FORUM, p->rDate, 1);
2860 }
2861 }
2862
2863 db_end_transaction(0);
2864 if( permitHooks ){
2865
+11
--- src/schema.c
+++ src/schema.c
@@ -489,10 +489,21 @@
489489
# define BKLNK_EVENT 3 /* Technote */
490490
# define BKLNK_FORUM 4 /* Forum post */
491491
# define ValidBklnk(X) (X>=0 && X<=4) /* True if backlink.srctype is valid */
492492
#endif
493493
494
+/*
495
+** Allowed values for MIMEtype codes
496
+*/
497
+#if INTERFACE
498
+# define MT_NONE 0 /* unspecified */
499
+# define MT_WIKI 1 /* Wiki */
500
+# define MT_MARKDOWN 2 /* Markdonw */
501
+# define MT_UNKNOWN 3 /* unknown */
502
+# define ValidMTC(X) ((X)>=0 && (X)<=3) /* True if MIMEtype code is valid */
503
+#endif
504
+
494505
/*
495506
** Predefined tagid values
496507
*/
497508
#if INTERFACE
498509
# define TAG_BGCOLOR 1 /* Set the background color for display */
499510
--- src/schema.c
+++ src/schema.c
@@ -489,10 +489,21 @@
489 # define BKLNK_EVENT 3 /* Technote */
490 # define BKLNK_FORUM 4 /* Forum post */
491 # define ValidBklnk(X) (X>=0 && X<=4) /* True if backlink.srctype is valid */
492 #endif
493
 
 
 
 
 
 
 
 
 
 
 
494 /*
495 ** Predefined tagid values
496 */
497 #if INTERFACE
498 # define TAG_BGCOLOR 1 /* Set the background color for display */
499
--- src/schema.c
+++ src/schema.c
@@ -489,10 +489,21 @@
489 # define BKLNK_EVENT 3 /* Technote */
490 # define BKLNK_FORUM 4 /* Forum post */
491 # define ValidBklnk(X) (X>=0 && X<=4) /* True if backlink.srctype is valid */
492 #endif
493
494 /*
495 ** Allowed values for MIMEtype codes
496 */
497 #if INTERFACE
498 # define MT_NONE 0 /* unspecified */
499 # define MT_WIKI 1 /* Wiki */
500 # define MT_MARKDOWN 2 /* Markdonw */
501 # define MT_UNKNOWN 3 /* unknown */
502 # define ValidMTC(X) ((X)>=0 && (X)<=3) /* True if MIMEtype code is valid */
503 #endif
504
505 /*
506 ** Predefined tagid values
507 */
508 #if INTERFACE
509 # define TAG_BGCOLOR 1 /* Set the background color for display */
510
+1 -1
--- src/tag.c
+++ src/tag.c
@@ -220,11 +220,11 @@
220220
if( zCol ){
221221
db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
222222
zCol, zValue, rid);
223223
if( tagid==TAG_COMMENT ){
224224
char *zCopy = mprintf("%s", zValue);
225
- backlink_extract(zCopy, 0, rid, BKLNK_COMMENT, mtime, 1);
225
+ backlink_extract(zCopy, MT_NONE, rid, BKLNK_COMMENT, mtime, 1);
226226
free(zCopy);
227227
}
228228
}
229229
if( tagid==TAG_DATE ){
230230
db_multi_exec("UPDATE event "
231231
--- src/tag.c
+++ src/tag.c
@@ -220,11 +220,11 @@
220 if( zCol ){
221 db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
222 zCol, zValue, rid);
223 if( tagid==TAG_COMMENT ){
224 char *zCopy = mprintf("%s", zValue);
225 backlink_extract(zCopy, 0, rid, BKLNK_COMMENT, mtime, 1);
226 free(zCopy);
227 }
228 }
229 if( tagid==TAG_DATE ){
230 db_multi_exec("UPDATE event "
231
--- src/tag.c
+++ src/tag.c
@@ -220,11 +220,11 @@
220 if( zCol ){
221 db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
222 zCol, zValue, rid);
223 if( tagid==TAG_COMMENT ){
224 char *zCopy = mprintf("%s", zValue);
225 backlink_extract(zCopy, MT_NONE, rid, BKLNK_COMMENT, mtime, 1);
226 free(zCopy);
227 }
228 }
229 if( tagid==TAG_DATE ){
230 db_multi_exec("UPDATE event "
231
+66 -18
--- src/tkt.c
+++ src/tkt.c
@@ -40,10 +40,13 @@
4040
static u8 haveTicket = 0; /* True if the TICKET table exists */
4141
static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
4242
static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
4343
static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
4444
static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */
45
+static u8 useTicketGenMt = 0; /* use generated TICKET.MIMETYPE */
46
+static u8 useTicketChngGenMt = 0;/* use generated TICKETCHNG.MIMETYPE */
47
+
4548
4649
/*
4750
** Compare two entries in aField[] for sorting purposes
4851
*/
4952
static int nameCmpr(const void *a, const void *b){
@@ -70,11 +73,11 @@
7073
** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and
7174
** TICKETCHANGE tables exist, respectively.
7275
*/
7376
static void getAllTicketFields(void){
7477
Stmt q;
75
- int i;
78
+ int i, noRegularMimetype;
7679
static int once = 0;
7780
if( once ) return;
7881
once = 1;
7982
db_prepare(&q, "PRAGMA table_info(ticket)");
8083
while( db_step(&q)==SQLITE_ROW ){
@@ -115,13 +118,25 @@
115118
aField[nField].mUsed = USEDBY_TICKETCHNG;
116119
nField++;
117120
}
118121
db_finalize(&q);
119122
qsort(aField, nField, sizeof(aField[0]), nameCmpr);
123
+ noRegularMimetype = 1;
120124
for(i=0; i<nField; i++){
121125
aField[i].zValue = "";
122126
aField[i].zAppend = 0;
127
+ if( strcmp(aField[i].zName,"mimetype")==0 ){
128
+ noRegularMimetype = 0;
129
+ }
130
+ }
131
+ if( noRegularMimetype ){ /* check for generated "mimetype" columns */
132
+ useTicketGenMt = db_exists(
133
+ "SELECT 1 FROM pragma_table_xinfo('ticket') "
134
+ "WHERE name = 'mimetype'");
135
+ useTicketChngGenMt = db_exists(
136
+ "SELECT 1 FROM pragma_table_xinfo('ticketchng') "
137
+ "WHERE name = 'mimetype'");
123138
}
124139
}
125140
126141
/*
127142
** Query the database for all TICKET fields for the specific
@@ -194,18 +209,18 @@
194209
**
195210
** Parameter rid is the recordID for the ticket artifact in the BLOB table.
196211
**
197212
** Return the new rowid of the TICKET table entry.
198213
*/
199
-static int ticket_insert(const Manifest *p, int rid, int tktid){
214
+static int ticket_insert(const Manifest *p, const int rid, int tktid){
200215
Blob sql1; /* update or replace TICKET ... */
201216
Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */
202217
Blob sql3; /* list of values which correspond to the previous list */
203218
Stmt q;
204219
int i, j;
205220
char *aUsed;
206
- const char *zMimetype = 0;
221
+ int mimetype_tkt = MT_NONE, mimetype_tktchng = MT_NONE;
207222
208223
if( tktid==0 ){
209224
db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
210225
"VALUES(%Q, 0)", p->zTicketUuid);
211226
tktid = db_last_insert_rowid();
@@ -236,27 +251,30 @@
236251
if( aField[j].mUsed & USEDBY_TICKETCHNG ){
237252
blob_append_sql(&sql2, ",\"%w\"", zBaseName);
238253
blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
239254
}
240255
if( strcmp(zBaseName,"mimetype")==0 ){
241
- zMimetype = p->aField[i].zValue;
242
- }
243
- }
244
- if( rid>0 ){
245
- for(i=0; i<p->nField; i++){
246
- const char *zName = p->aField[i].zName;
247
- const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
248
- j = fieldId(zBaseName);
249
- if( j<0 ) continue;
250
- backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET,
251
- p->rDate, i==0);
256
+ const char *zMimetype = p->aField[i].zValue;
257
+ /* "mimetype" is a regular column => these two flags must be 0 */
258
+ assert(!useTicketGenMt);
259
+ assert(!useTicketChngGenMt);
260
+ mimetype_tkt = mimetype_tktchng = parse_mimetype( zMimetype );
252261
}
253262
}
254263
blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid);
264
+ if( useTicketGenMt ){
265
+ blob_append_literal(&sql1, " RETURNING mimetype");
266
+ }
255267
db_prepare(&q, "%s", blob_sql_text(&sql1));
256268
db_bind_double(&q, ":mtime", p->rDate);
257269
db_step(&q);
270
+ if( useTicketGenMt ){
271
+ mimetype_tkt = parse_mimetype( db_column_text(&q,0) );
272
+ if( !useTicketChngGenMt ){
273
+ mimetype_tktchng = mimetype_tkt;
274
+ }
275
+ }
258276
db_finalize(&q);
259277
blob_reset(&sql1);
260278
if( blob_size(&sql2)>0 || haveTicketChngRid || haveTicketChngUser ){
261279
int fromTkt = 0;
262280
if( haveTicketChngRid ){
@@ -278,25 +296,55 @@
278296
blob_append_sql(&sql3, ",\"%w\"", z);
279297
}
280298
}
281299
if( fromTkt ){
282300
db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
283
- "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
301
+ "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d%s",
284302
blob_sql_text(&sql2), tktid,
285
- blob_sql_text(&sql3), tktid);
303
+ blob_sql_text(&sql3), tktid,
304
+ useTicketChngGenMt ? " RETURNING mimetype" : "");
286305
}else{
287306
db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
288
- "VALUES(%d,:mtime%s)",
289
- blob_sql_text(&sql2), tktid, blob_sql_text(&sql3));
307
+ "VALUES(%d,:mtime%s)%s",
308
+ blob_sql_text(&sql2), tktid, blob_sql_text(&sql3),
309
+ useTicketChngGenMt ? " RETURNING mimetype" : "");
290310
}
291311
db_bind_double(&q, ":mtime", p->rDate);
292312
db_step(&q);
313
+ if( useTicketChngGenMt ){
314
+ mimetype_tktchng = parse_mimetype( db_column_text(&q, 0) );
315
+ /* substitute NULL with a value generated within another table */
316
+ if( !useTicketGenMt ){
317
+ mimetype_tkt = mimetype_tktchng;
318
+ }else if( mimetype_tktchng==MT_NONE ){
319
+ mimetype_tktchng = mimetype_tkt;
320
+ }else if( mimetype_tkt==MT_NONE ){
321
+ mimetype_tkt = mimetype_tktchng;
322
+ }
323
+ }
293324
db_finalize(&q);
294325
}
295326
blob_reset(&sql2);
296327
blob_reset(&sql3);
297328
fossil_free(aUsed);
329
+ if( rid>0 ){ /* extract backlinks */
330
+ int bReplace = 1, mimetype;
331
+ for(i=0; i<p->nField; i++){
332
+ const char *zName = p->aField[i].zName;
333
+ const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
334
+ j = fieldId(zBaseName);
335
+ if( j<0 ) continue;
336
+ if( aField[j].mUsed & USEDBY_TICKETCHNG ){
337
+ mimetype = mimetype_tktchng;
338
+ }else{
339
+ mimetype = mimetype_tkt;
340
+ }
341
+ backlink_extract(p->aField[i].zValue, mimetype, rid, BKLNK_TICKET,
342
+ p->rDate, bReplace);
343
+ bReplace = 0;
344
+ }
345
+ }
298346
return tktid;
299347
}
300348
301349
/*
302350
** Returns non-zero if moderation is required for ticket changes and ticket
303351
--- src/tkt.c
+++ src/tkt.c
@@ -40,10 +40,13 @@
40 static u8 haveTicket = 0; /* True if the TICKET table exists */
41 static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
42 static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
43 static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
44 static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */
 
 
 
45
46 /*
47 ** Compare two entries in aField[] for sorting purposes
48 */
49 static int nameCmpr(const void *a, const void *b){
@@ -70,11 +73,11 @@
70 ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and
71 ** TICKETCHANGE tables exist, respectively.
72 */
73 static void getAllTicketFields(void){
74 Stmt q;
75 int i;
76 static int once = 0;
77 if( once ) return;
78 once = 1;
79 db_prepare(&q, "PRAGMA table_info(ticket)");
80 while( db_step(&q)==SQLITE_ROW ){
@@ -115,13 +118,25 @@
115 aField[nField].mUsed = USEDBY_TICKETCHNG;
116 nField++;
117 }
118 db_finalize(&q);
119 qsort(aField, nField, sizeof(aField[0]), nameCmpr);
 
120 for(i=0; i<nField; i++){
121 aField[i].zValue = "";
122 aField[i].zAppend = 0;
 
 
 
 
 
 
 
 
 
 
 
123 }
124 }
125
126 /*
127 ** Query the database for all TICKET fields for the specific
@@ -194,18 +209,18 @@
194 **
195 ** Parameter rid is the recordID for the ticket artifact in the BLOB table.
196 **
197 ** Return the new rowid of the TICKET table entry.
198 */
199 static int ticket_insert(const Manifest *p, int rid, int tktid){
200 Blob sql1; /* update or replace TICKET ... */
201 Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */
202 Blob sql3; /* list of values which correspond to the previous list */
203 Stmt q;
204 int i, j;
205 char *aUsed;
206 const char *zMimetype = 0;
207
208 if( tktid==0 ){
209 db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
210 "VALUES(%Q, 0)", p->zTicketUuid);
211 tktid = db_last_insert_rowid();
@@ -236,27 +251,30 @@
236 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
237 blob_append_sql(&sql2, ",\"%w\"", zBaseName);
238 blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
239 }
240 if( strcmp(zBaseName,"mimetype")==0 ){
241 zMimetype = p->aField[i].zValue;
242 }
243 }
244 if( rid>0 ){
245 for(i=0; i<p->nField; i++){
246 const char *zName = p->aField[i].zName;
247 const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
248 j = fieldId(zBaseName);
249 if( j<0 ) continue;
250 backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET,
251 p->rDate, i==0);
252 }
253 }
254 blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid);
 
 
 
255 db_prepare(&q, "%s", blob_sql_text(&sql1));
256 db_bind_double(&q, ":mtime", p->rDate);
257 db_step(&q);
 
 
 
 
 
 
258 db_finalize(&q);
259 blob_reset(&sql1);
260 if( blob_size(&sql2)>0 || haveTicketChngRid || haveTicketChngUser ){
261 int fromTkt = 0;
262 if( haveTicketChngRid ){
@@ -278,25 +296,55 @@
278 blob_append_sql(&sql3, ",\"%w\"", z);
279 }
280 }
281 if( fromTkt ){
282 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
283 "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
284 blob_sql_text(&sql2), tktid,
285 blob_sql_text(&sql3), tktid);
 
286 }else{
287 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
288 "VALUES(%d,:mtime%s)",
289 blob_sql_text(&sql2), tktid, blob_sql_text(&sql3));
 
290 }
291 db_bind_double(&q, ":mtime", p->rDate);
292 db_step(&q);
 
 
 
 
 
 
 
 
 
 
 
293 db_finalize(&q);
294 }
295 blob_reset(&sql2);
296 blob_reset(&sql3);
297 fossil_free(aUsed);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298 return tktid;
299 }
300
301 /*
302 ** Returns non-zero if moderation is required for ticket changes and ticket
303
--- src/tkt.c
+++ src/tkt.c
@@ -40,10 +40,13 @@
40 static u8 haveTicket = 0; /* True if the TICKET table exists */
41 static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */
42 static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */
43 static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
44 static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */
45 static u8 useTicketGenMt = 0; /* use generated TICKET.MIMETYPE */
46 static u8 useTicketChngGenMt = 0;/* use generated TICKETCHNG.MIMETYPE */
47
48
49 /*
50 ** Compare two entries in aField[] for sorting purposes
51 */
52 static int nameCmpr(const void *a, const void *b){
@@ -70,11 +73,11 @@
73 ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and
74 ** TICKETCHANGE tables exist, respectively.
75 */
76 static void getAllTicketFields(void){
77 Stmt q;
78 int i, noRegularMimetype;
79 static int once = 0;
80 if( once ) return;
81 once = 1;
82 db_prepare(&q, "PRAGMA table_info(ticket)");
83 while( db_step(&q)==SQLITE_ROW ){
@@ -115,13 +118,25 @@
118 aField[nField].mUsed = USEDBY_TICKETCHNG;
119 nField++;
120 }
121 db_finalize(&q);
122 qsort(aField, nField, sizeof(aField[0]), nameCmpr);
123 noRegularMimetype = 1;
124 for(i=0; i<nField; i++){
125 aField[i].zValue = "";
126 aField[i].zAppend = 0;
127 if( strcmp(aField[i].zName,"mimetype")==0 ){
128 noRegularMimetype = 0;
129 }
130 }
131 if( noRegularMimetype ){ /* check for generated "mimetype" columns */
132 useTicketGenMt = db_exists(
133 "SELECT 1 FROM pragma_table_xinfo('ticket') "
134 "WHERE name = 'mimetype'");
135 useTicketChngGenMt = db_exists(
136 "SELECT 1 FROM pragma_table_xinfo('ticketchng') "
137 "WHERE name = 'mimetype'");
138 }
139 }
140
141 /*
142 ** Query the database for all TICKET fields for the specific
@@ -194,18 +209,18 @@
209 **
210 ** Parameter rid is the recordID for the ticket artifact in the BLOB table.
211 **
212 ** Return the new rowid of the TICKET table entry.
213 */
214 static int ticket_insert(const Manifest *p, const int rid, int tktid){
215 Blob sql1; /* update or replace TICKET ... */
216 Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */
217 Blob sql3; /* list of values which correspond to the previous list */
218 Stmt q;
219 int i, j;
220 char *aUsed;
221 int mimetype_tkt = MT_NONE, mimetype_tktchng = MT_NONE;
222
223 if( tktid==0 ){
224 db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
225 "VALUES(%Q, 0)", p->zTicketUuid);
226 tktid = db_last_insert_rowid();
@@ -236,27 +251,30 @@
251 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
252 blob_append_sql(&sql2, ",\"%w\"", zBaseName);
253 blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
254 }
255 if( strcmp(zBaseName,"mimetype")==0 ){
256 const char *zMimetype = p->aField[i].zValue;
257 /* "mimetype" is a regular column => these two flags must be 0 */
258 assert(!useTicketGenMt);
259 assert(!useTicketChngGenMt);
260 mimetype_tkt = mimetype_tktchng = parse_mimetype( zMimetype );
 
 
 
 
 
 
261 }
262 }
263 blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid);
264 if( useTicketGenMt ){
265 blob_append_literal(&sql1, " RETURNING mimetype");
266 }
267 db_prepare(&q, "%s", blob_sql_text(&sql1));
268 db_bind_double(&q, ":mtime", p->rDate);
269 db_step(&q);
270 if( useTicketGenMt ){
271 mimetype_tkt = parse_mimetype( db_column_text(&q,0) );
272 if( !useTicketChngGenMt ){
273 mimetype_tktchng = mimetype_tkt;
274 }
275 }
276 db_finalize(&q);
277 blob_reset(&sql1);
278 if( blob_size(&sql2)>0 || haveTicketChngRid || haveTicketChngUser ){
279 int fromTkt = 0;
280 if( haveTicketChngRid ){
@@ -278,25 +296,55 @@
296 blob_append_sql(&sql3, ",\"%w\"", z);
297 }
298 }
299 if( fromTkt ){
300 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
301 "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d%s",
302 blob_sql_text(&sql2), tktid,
303 blob_sql_text(&sql3), tktid,
304 useTicketChngGenMt ? " RETURNING mimetype" : "");
305 }else{
306 db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
307 "VALUES(%d,:mtime%s)%s",
308 blob_sql_text(&sql2), tktid, blob_sql_text(&sql3),
309 useTicketChngGenMt ? " RETURNING mimetype" : "");
310 }
311 db_bind_double(&q, ":mtime", p->rDate);
312 db_step(&q);
313 if( useTicketChngGenMt ){
314 mimetype_tktchng = parse_mimetype( db_column_text(&q, 0) );
315 /* substitute NULL with a value generated within another table */
316 if( !useTicketGenMt ){
317 mimetype_tkt = mimetype_tktchng;
318 }else if( mimetype_tktchng==MT_NONE ){
319 mimetype_tktchng = mimetype_tkt;
320 }else if( mimetype_tkt==MT_NONE ){
321 mimetype_tkt = mimetype_tktchng;
322 }
323 }
324 db_finalize(&q);
325 }
326 blob_reset(&sql2);
327 blob_reset(&sql3);
328 fossil_free(aUsed);
329 if( rid>0 ){ /* extract backlinks */
330 int bReplace = 1, mimetype;
331 for(i=0; i<p->nField; i++){
332 const char *zName = p->aField[i].zName;
333 const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
334 j = fieldId(zBaseName);
335 if( j<0 ) continue;
336 if( aField[j].mUsed & USEDBY_TICKETCHNG ){
337 mimetype = mimetype_tktchng;
338 }else{
339 mimetype = mimetype_tkt;
340 }
341 backlink_extract(p->aField[i].zValue, mimetype, rid, BKLNK_TICKET,
342 p->rDate, bReplace);
343 bReplace = 0;
344 }
345 }
346 return tktid;
347 }
348
349 /*
350 ** Returns non-zero if moderation is required for ticket changes and ticket
351
--- www/changes.wiki
+++ www/changes.wiki
@@ -16,10 +16,12 @@
1616
See corresponding [../test/markdown-test3.md|test cases],
1717
[/wiki?name=branch/markdown-footnotes#il|known limitations] and
1818
[forum:/forumthread/ee1f1597e46ec07a|discussion].
1919
* Add the new special name "start:BRANCH" to refer to the first check-in of
2020
the branch.
21
+ * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"]
22
+ columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables.
2123
2224
<h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2>
2325
* Added support for [./ssl-server.md|SSL/TLS server mode] for commands
2426
like "[/help?cmd=server|fossil server]" and "[/help?cmd=http|fossil http]"
2527
* The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
2628
--- www/changes.wiki
+++ www/changes.wiki
@@ -16,10 +16,12 @@
16 See corresponding [../test/markdown-test3.md|test cases],
17 [/wiki?name=branch/markdown-footnotes#il|known limitations] and
18 [forum:/forumthread/ee1f1597e46ec07a|discussion].
19 * Add the new special name "start:BRANCH" to refer to the first check-in of
20 the branch.
 
 
21
22 <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2>
23 * Added support for [./ssl-server.md|SSL/TLS server mode] for commands
24 like "[/help?cmd=server|fossil server]" and "[/help?cmd=http|fossil http]"
25 * The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
26
--- www/changes.wiki
+++ www/changes.wiki
@@ -16,10 +16,12 @@
16 See corresponding [../test/markdown-test3.md|test cases],
17 [/wiki?name=branch/markdown-footnotes#il|known limitations] and
18 [forum:/forumthread/ee1f1597e46ec07a|discussion].
19 * Add the new special name "start:BRANCH" to refer to the first check-in of
20 the branch.
21 * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"]
22 columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables.
23
24 <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2>
25 * Added support for [./ssl-server.md|SSL/TLS server mode] for commands
26 like "[/help?cmd=server|fossil server]" and "[/help?cmd=http|fossil http]"
27 * The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
28
--- www/changes.wiki
+++ www/changes.wiki
@@ -16,10 +16,12 @@
1616
See corresponding [../test/markdown-test3.md|test cases],
1717
[/wiki?name=branch/markdown-footnotes#il|known limitations] and
1818
[forum:/forumthread/ee1f1597e46ec07a|discussion].
1919
* Add the new special name "start:BRANCH" to refer to the first check-in of
2020
the branch.
21
+ * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"]
22
+ columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables.
2123
2224
<h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2>
2325
* Added support for [./ssl-server.md|SSL/TLS server mode] for commands
2426
like "[/help?cmd=server|fossil server]" and "[/help?cmd=http|fossil http]"
2527
* The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
2628
--- www/changes.wiki
+++ www/changes.wiki
@@ -16,10 +16,12 @@
16 See corresponding [../test/markdown-test3.md|test cases],
17 [/wiki?name=branch/markdown-footnotes#il|known limitations] and
18 [forum:/forumthread/ee1f1597e46ec07a|discussion].
19 * Add the new special name "start:BRANCH" to refer to the first check-in of
20 the branch.
 
 
21
22 <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2>
23 * Added support for [./ssl-server.md|SSL/TLS server mode] for commands
24 like "[/help?cmd=server|fossil server]" and "[/help?cmd=http|fossil http]"
25 * The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
26
--- www/changes.wiki
+++ www/changes.wiki
@@ -16,10 +16,12 @@
16 See corresponding [../test/markdown-test3.md|test cases],
17 [/wiki?name=branch/markdown-footnotes#il|known limitations] and
18 [forum:/forumthread/ee1f1597e46ec07a|discussion].
19 * Add the new special name "start:BRANCH" to refer to the first check-in of
20 the branch.
21 * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"]
22 columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables.
23
24 <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2>
25 * Added support for [./ssl-server.md|SSL/TLS server mode] for commands
26 like "[/help?cmd=server|fossil server]" and "[/help?cmd=http|fossil http]"
27 * The new [/help?cmd=cherry-pick|cherry-pick command] is an alias for
28

Keyboard Shortcuts

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