Fossil

Changes On Branch generated-tkt-mimetype
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch generated-tkt-mimetype Excluding Merge-Ins

This is equivalent to a diff from 07d739b4ba to 33c67c2851

2022-05-24
20:32
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. ... (check-in: 6fb642c02b user: george tags: trunk)
2022-05-18
22:52
Fix a couple of invokations of <code>backlink_extract()</code> that were overlooked in the previous check-in. ... (Closed-Leaf check-in: 33c67c2851 user: george tags: generated-tkt-mimetype)
20:21
Add support for generated "mimetype" column in the <var>TICKET</var> table. Introduce integer mimetype codes and refactor <code>backlink_extract()</code> accordingly. Make the overall handling of the generated "mimetype" columns a bit more clear. ... (check-in: e39f77906e user: george tags: generated-tkt-mimetype)
2022-05-16
11:55
Bring in the latest SQLite 3.39.0 enhancements for testing. ... (check-in: 8683664a45 user: drh tags: trunk)
2022-05-14
17:42
Fix a subtle bug in <code>ticket_insert()</code> which may lead to redundant rows in the BACKLINK table. The bug appeared in [7c13a57358ae]. ... (check-in: 3b42738e36 user: george tags: generated-tkt-mimetype)
14:38
Adds minor output to stash command to alert users when a stash is successful. See [forum:fd2405eff30f4c73 | forum post fd2405eff30f4c73] for discussion. ... (check-in: 07d739b4ba user: andybradford tags: trunk)
14:23
Bring branch up to date with trunk. ... (Closed-Leaf check-in: 393e73cf3e user: andybradford tags: stash-success)
06:37
Typo fix in email-renew-interval setting docs, per forum report. ... (check-in: 7ae1f31994 user: stephan tags: trunk)

Changes to src/backlink.c.
177
178
179
180
181
182
183

184

185
186
187
188
189
190
191
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192







+
-
+







  Manifest *pWiki;
  if( tagid==0 ) return;
  rid = db_int(0, "SELECT rid FROM tagxref WHERE tagid=%d"
                  " ORDER BY mtime DESC LIMIT 1", tagid);
  if( rid==0 ) return;
  pWiki = manifest_get(rid, CFTYPE_WIKI, 0);
  if( pWiki ){
    int mimetype = parse_mimetype( pWiki->zMimetype );
    backlink_extract(pWiki->zWiki, pWiki->zMimetype, tagid, BKLNK_WIKI,
    backlink_extract(pWiki->zWiki, mimetype, tagid, BKLNK_WIKI,
                     pWiki->rDate, 1);
    manifest_destroy(pWiki);
  }
}

/*
** Structure used to pass down state information through the
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
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







+
+
+
+
+
+
+
+
+
+
+






-
+












+


-
+

-
+







  blob_init(&out, 0, 0);
  blob_init(&in, zInputText, -1);
  markdown(&out, &in, &html_renderer);
  blob_reset(&out);
  blob_reset(&in);
}

/*
** Transform mimetype string into an integer code.
** NOTE: In the sake of compatability empty string is parsed as MT_UNKNOWN;
**       it is yet unclear whether it can safely be changed to MT_NONE.
*/
int parse_mimetype(const char* zMimetype){
  if( zMimetype==0 ) return MT_NONE;
  if( strstr(zMimetype,"wiki")!=0 )     return MT_WIKI;
  if( strstr(zMimetype,"markdown")!=0 ) return MT_MARKDOWN;
  return MT_UNKNOWN;
}
/*
** Parse text looking for hyperlinks.  Insert references into the
** BACKLINK table.
*/
void backlink_extract(
  char *zSrc,            /* Input text from which links are extracted */
  const char *zMimetype, /* Mimetype of input.  NULL means fossil-wiki */
  int mimetype,          /* Mimetype of input. MT_NONE works as MT_WIKI */
  int srcid,             /* srcid for the source document */
  int srctype,           /* One of BKLNK_*.  0=comment 1=ticket 2=wiki */
  double mtime,          /* mtime field for new BACKLINK table entries */
  int replaceFlag        /* True to overwrite prior BACKLINK entries */
){
  Backlink bklnk;
  if( replaceFlag ){
    db_multi_exec("DELETE FROM backlink WHERE srctype=%d AND srcid=%d",
                  srctype, srcid);
  }
  bklnk.srcid = srcid;
  assert( ValidBklnk(srctype) );
  assert( ValidMTC(mimetype) );
  bklnk.srctype = srctype;
  bklnk.mtime = mtime;
  if( zMimetype==0 || strstr(zMimetype,"wiki")!=0 ){
  if( mimetype==MT_NONE || mimetype==MT_WIKI ){
    wiki_extract_links(zSrc, &bklnk, srctype==BKLNK_COMMENT ? WIKI_INLINE : 0);
  }else if( strstr(zMimetype,"markdown")!=0 ){
  }else if( mimetype==MT_MARKDOWN ){
    markdown_extract_links(zSrc, &bklnk);
  }
}

/*
** COMMAND: test-backlinks
**
338
339
340
341
342
343
344

345
346
347
348
349
350
351
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365







+







**    --mtime DATETIME        Use an alternative date/time.  Defaults to the
**                            current date/time.
**    --mimetype TYPE         Use an alternative mimetype.
*/
void test_backlinks_cmd(void){
  const char *zMTime = find_option("mtime",0,1);
  const char *zMimetype = find_option("mimetype",0,1);
  const int mimetype = parse_mimetype(zMimetype);
  Blob in;
  int srcid;
  int srctype;
  double mtime;

  verify_all_options();
  if( g.argc!=5 ){
369
370
371
372
373
374
375
376

377
378
379
380
381
382
383
383
384
385
386
387
388
389

390
391
392
393
394
395
396
397







-
+







    " 'target='||quote(new.target)||"
    " ' srctype='||quote(new.srctype)||"
    " ' srcid='||quote(new.srcid)||"
    " ' mtime='||datetime(new.mtime));\n"
    "  SELECT raise(ignore);\n"
    "END;"
  );
  backlink_extract(blob_str(&in),zMimetype,srcid,srctype,mtime,0);
  backlink_extract(blob_str(&in),mimetype,srcid,srctype,mtime,0);
  blob_reset(&in);
}


/*
** COMMAND: test-wiki-relink
**
Changes to src/manifest.c.
2393
2394
2395
2396
2397
2398
2399
2400

2401
2402
2403
2404
2405
2406
2407
2393
2394
2395
2396
2397
2398
2399

2400
2401
2402
2403
2404
2405
2406
2407







-
+







        "RETURNING coalesce(ecomment,comment);",
        TAG_DATE, rid, p->rDate,
        rid, p->zUser, p->zComment,
        TAG_BGCOLOR, rid,
        TAG_USER, rid,
        TAG_COMMENT, rid, p->rDate
      );
      backlink_extract(zCom, 0, rid, BKLNK_COMMENT, p->rDate, 1);
      backlink_extract(zCom, MT_NONE, rid, BKLNK_COMMENT, p->rDate, 1);
      fossil_free(zCom);

      /* If this is a delta-manifest, record the fact that this repository
      ** contains delta manifests, to free the "commit" logic to generate
      ** new delta manifests.
      */
      if( p->zBaseline!=0 ){
2851
2852
2853
2854
2855
2856
2857

2858

2859
2860
2861
2862
2863
2864
2865
2851
2852
2853
2854
2855
2856
2857
2858

2859
2860
2861
2862
2863
2864
2865
2866







+
-
+







        "REPLACE INTO event(type,mtime,objid,user,comment)"
        "VALUES('f',%.17g,%d,%Q,'%q: %q')",
        p->rDate, rid, p->zUser, zFType, zTitle
      );
      fossil_free(zTitle);
    }
    if( p->zWiki[0] ){
      int mimetype = parse_mimetype(p->zMimetype);
      backlink_extract(p->zWiki, p->zMimetype, rid, BKLNK_FORUM, p->rDate, 1);
      backlink_extract(p->zWiki, mimetype, rid, BKLNK_FORUM, p->rDate, 1);
    }
  }

  db_end_transaction(0);
  if( permitHooks ){
    rc = xfer_run_common_script();
    if( rc==TH_OK ){
Changes to src/schema.c.
487
488
489
490
491
492
493











494
495
496
497
498
499
500
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511







+
+
+
+
+
+
+
+
+
+
+







# define BKLNK_TICKET     1   /* Ticket body or title */
# define BKLNK_WIKI       2   /* Wiki */
# define BKLNK_EVENT      3   /* Technote */
# define BKLNK_FORUM      4   /* Forum post */
# define ValidBklnk(X)   (X>=0 && X<=4)  /* True if backlink.srctype is valid */
#endif

/*
** Allowed values for MIMEtype codes
*/
#if INTERFACE
# define MT_NONE       0   /* unspecified */
# define MT_WIKI       1   /* Wiki */
# define MT_MARKDOWN   2   /* Markdonw */
# define MT_UNKNOWN    3   /* unknown  */
# define ValidMTC(X)  ((X)>=0 && (X)<=3)  /* True if MIMEtype code is valid */
#endif

/*
** Predefined tagid values
*/
#if INTERFACE
# define TAG_BGCOLOR    1     /* Set the background color for display */
# define TAG_COMMENT    2     /* The check-in comment */
# define TAG_USER       3     /* User who made a checking */
Changes to src/tag.c.
218
219
220
221
222
223
224
225

226
227
228
229
230
231
232
218
219
220
221
222
223
224

225
226
227
228
229
230
231
232







-
+







    }
  }
  if( zCol ){
    db_multi_exec("UPDATE event SET \"%w\"=%Q WHERE objid=%d",
                  zCol, zValue, rid);
    if( tagid==TAG_COMMENT ){
      char *zCopy = mprintf("%s", zValue);
      backlink_extract(zCopy, 0, rid, BKLNK_COMMENT, mtime, 1);
      backlink_extract(zCopy, MT_NONE, rid, BKLNK_COMMENT, mtime, 1);
      free(zCopy);
    }
  }
  if( tagid==TAG_DATE ){
    db_multi_exec("UPDATE event "
                  "   SET mtime=julianday(%Q),"
                  "       omtime=coalesce(omtime,mtime)"
Changes to src/tkt.c.
38
39
40
41
42
43
44



45
46
47
48
49
50
51
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54







+
+
+







#define USEDBY_TICKETCHNG  02
#define USEDBY_BOTH        03
static u8 haveTicket = 0;        /* True if the TICKET table exists */
static u8 haveTicketCTime = 0;   /* True if TICKET.TKT_CTIME exists */
static u8 haveTicketChng = 0;    /* True if the TICKETCHNG table exists */
static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */
static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */
static u8 useTicketGenMt = 0;    /* use generated TICKET.MIMETYPE */
static u8 useTicketChngGenMt = 0;/* use generated TICKETCHNG.MIMETYPE */


/*
** Compare two entries in aField[] for sorting purposes
*/
static int nameCmpr(const void *a, const void *b){
  return fossil_strcmp(((const struct tktFieldInfo*)a)->zName,
                       ((const struct tktFieldInfo*)b)->zName);
68
69
70
71
72
73
74
75

76
77
78
79
80
81
82
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85







-
+







** in sorted order in aField[].
**
** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and
** TICKETCHANGE tables exist, respectively.
*/
static void getAllTicketFields(void){
  Stmt q;
  int i;
  int i, noRegularMimetype;
  static int once = 0;
  if( once ) return;
  once = 1;
  db_prepare(&q, "PRAGMA table_info(ticket)");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zFieldName = db_column_text(&q, 1);
    haveTicket = 1;
113
114
115
116
117
118
119

120
121
122











123
124
125
126
127
128
129
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144







+



+
+
+
+
+
+
+
+
+
+
+







    }
    aField[nField].zName = mprintf("%s", zFieldName);
    aField[nField].mUsed = USEDBY_TICKETCHNG;
    nField++;
  }
  db_finalize(&q);
  qsort(aField, nField, sizeof(aField[0]), nameCmpr);
  noRegularMimetype = 1;
  for(i=0; i<nField; i++){
    aField[i].zValue = "";
    aField[i].zAppend = 0;
    if( strcmp(aField[i].zName,"mimetype")==0 ){
      noRegularMimetype = 0;
    }
  }
  if( noRegularMimetype ){ /* check for generated "mimetype" columns */
    useTicketGenMt = db_exists(
      "SELECT 1 FROM pragma_table_xinfo('ticket') "
      "WHERE name = 'mimetype'");
    useTicketChngGenMt = db_exists(
      "SELECT 1 FROM pragma_table_xinfo('ticketchng') "
      "WHERE name = 'mimetype'");
  }
}

/*
** Query the database for all TICKET fields for the specific
** ticket whose name is given by the "name" CGI parameter.
** Load the values for all fields into the interpreter.
192
193
194
195
196
197
198
199

200
201
202
203
204
205
206

207
208
209
210
211
212
213
207
208
209
210
211
212
213

214
215
216
217
218
219
220

221
222
223
224
225
226
227
228







-
+






-
+







** the appropriate TICKET table entry if tktid is zero.  If tktid is nonzero
** then it will be the ROWID of an existing TICKET entry.
**
** Parameter rid is the recordID for the ticket artifact in the BLOB table.
**
** Return the new rowid of the TICKET table entry.
*/
static int ticket_insert(const Manifest *p, int rid, int tktid){
static int ticket_insert(const Manifest *p, const int rid, int tktid){
  Blob sql1; /* update or replace TICKET ... */
  Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */
  Blob sql3; /* list of values which correspond to the previous list */
  Stmt q;
  int i, j;
  char *aUsed;
  const char *zMimetype = 0;
  int mimetype_tkt = MT_NONE, mimetype_tktchng = MT_NONE;

  if( tktid==0 ){
    db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) "
                  "VALUES(%Q, 0)", p->zTicketUuid);
    tktid = db_last_insert_rowid();
  }
  blob_zero(&sql1);
234
235
236
237
238
239
240
241

242
243
244



245
246
247
248
249
250

251
252
253
254



255
256
257






258
259
260
261
262
263
264
249
250
251
252
253
254
255

256



257
258
259






260

261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282







-
+
-
-
-
+
+
+
-
-
-
-
-
-
+
-



+
+
+



+
+
+
+
+
+







      }
    }
    if( aField[j].mUsed & USEDBY_TICKETCHNG ){
      blob_append_sql(&sql2, ",\"%w\"", zBaseName);
      blob_append_sql(&sql3, ",%Q", p->aField[i].zValue);
    }
    if( strcmp(zBaseName,"mimetype")==0 ){
      zMimetype = p->aField[i].zValue;
      const char *zMimetype = p->aField[i].zValue;
    }
  }
  if( rid>0 ){
      /* "mimetype" is a regular column => these two flags must be 0 */
      assert(!useTicketGenMt);
      assert(!useTicketChngGenMt);
    for(i=0; i<p->nField; i++){
      const char *zName = p->aField[i].zName;
      const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
      j = fieldId(zBaseName);
      if( j<0 ) continue;
      backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET,
      mimetype_tkt = mimetype_tktchng = parse_mimetype( zMimetype );
                       p->rDate, i==0);
    }
  }
  blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid);
  if( useTicketGenMt ){
    blob_append_literal(&sql1, " RETURNING mimetype");
  }
  db_prepare(&q, "%s", blob_sql_text(&sql1));
  db_bind_double(&q, ":mtime", p->rDate);
  db_step(&q);
  if( useTicketGenMt ){
    mimetype_tkt = parse_mimetype( db_column_text(&q,0) );
    if( !useTicketChngGenMt ){
      mimetype_tktchng = mimetype_tkt;
    }
  }
  db_finalize(&q);
  blob_reset(&sql1);
  if( blob_size(&sql2)>0 || haveTicketChngRid || haveTicketChngUser ){
    int fromTkt = 0;
    if( haveTicketChngRid ){
      blob_append_literal(&sql2, ",tkt_rid");
      blob_append_sql(&sql3, ",%d", rid);
276
277
278
279
280
281
282
283

284
285


286
287
288
289



290
291
292











293
294
295
296
297

















298
299
300
301
302
303
304
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
346
347
348
349
350
351
352







-
+

-
+
+


-
-
+
+
+



+
+
+
+
+
+
+
+
+
+
+





+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







        fromTkt = 1;
        blob_append_sql(&sql2, ",\"%w\"", z);
        blob_append_sql(&sql3, ",\"%w\"", z);
      }
    }
    if( fromTkt ){
      db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
                     "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d",
                     "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d%s",
                     blob_sql_text(&sql2), tktid,
                     blob_sql_text(&sql3), tktid);
                     blob_sql_text(&sql3), tktid,
                     useTicketChngGenMt ? " RETURNING mimetype" : "");
    }else{
      db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)"
                     "VALUES(%d,:mtime%s)",
                     blob_sql_text(&sql2), tktid, blob_sql_text(&sql3));
                     "VALUES(%d,:mtime%s)%s",
                     blob_sql_text(&sql2), tktid, blob_sql_text(&sql3),
                     useTicketChngGenMt ? " RETURNING mimetype" : "");
    }
    db_bind_double(&q, ":mtime", p->rDate);
    db_step(&q);
    if( useTicketChngGenMt ){
      mimetype_tktchng = parse_mimetype( db_column_text(&q, 0) );
      /* substitute NULL with a value generated within another table */
      if( !useTicketGenMt ){
        mimetype_tkt = mimetype_tktchng;
      }else if( mimetype_tktchng==MT_NONE ){
        mimetype_tktchng = mimetype_tkt;
      }else if( mimetype_tkt==MT_NONE ){
        mimetype_tkt = mimetype_tktchng;
      }
    }
    db_finalize(&q);
  }
  blob_reset(&sql2);
  blob_reset(&sql3);
  fossil_free(aUsed);
  if( rid>0 ){                   /* extract backlinks */
    int bReplace = 1, mimetype;
    for(i=0; i<p->nField; i++){
      const char *zName = p->aField[i].zName;
      const char *zBaseName = zName[0]=='+' ? zName+1 : zName;
      j = fieldId(zBaseName);
      if( j<0 ) continue;
      if( aField[j].mUsed & USEDBY_TICKETCHNG ){
        mimetype = mimetype_tktchng;
      }else{
        mimetype = mimetype_tkt;
      }
      backlink_extract(p->aField[i].zValue, mimetype, rid, BKLNK_TICKET,
                       p->rDate, bReplace);
      bReplace = 0;
    }
  }
  return tktid;
}

/*
** Returns non-zero if moderation is required for ticket changes and ticket
** attachments.
*/