Fossil SCM
If "<var>mimetype</var>" column of the <var>TICKETCHNG</var> table is a [https://www.sqlite.org/gencol.html|generated column], than use these generated values for extraction of backlinks from the ticket-changes.
Commit
5ab73ab8c7be3a0c6eba55843e95d68f4c72d219e1b31beb03b49de1e16a2ce8
Parent
3b42738e365e742…
1 file changed
+36
-18
+36
-18
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -40,10 +40,11 @@ | ||
| 40 | 40 | static u8 haveTicket = 0; /* True if the TICKET table exists */ |
| 41 | 41 | static u8 haveTicketCTime = 0; /* True if TICKET.TKT_CTIME exists */ |
| 42 | 42 | static u8 haveTicketChng = 0; /* True if the TICKETCHNG table exists */ |
| 43 | 43 | static u8 haveTicketChngRid = 0; /* True if TICKETCHNG.TKT_RID exists */ |
| 44 | 44 | static u8 haveTicketChngUser = 0;/* True if TICKETCHNG.TKT_USER exists */ |
| 45 | +static u8 haveTicketChngGenMt= 0;/* True if TICKETCHNG.MIMETYPE is generated */ | |
| 45 | 46 | |
| 46 | 47 | /* |
| 47 | 48 | ** Compare two entries in aField[] for sorting purposes |
| 48 | 49 | */ |
| 49 | 50 | static int nameCmpr(const void *a, const void *b){ |
| @@ -70,11 +71,11 @@ | ||
| 70 | 71 | ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and |
| 71 | 72 | ** TICKETCHANGE tables exist, respectively. |
| 72 | 73 | */ |
| 73 | 74 | static void getAllTicketFields(void){ |
| 74 | 75 | Stmt q; |
| 75 | - int i; | |
| 76 | + int i, bRegularMimetype = 0; | |
| 76 | 77 | static int once = 0; |
| 77 | 78 | if( once ) return; |
| 78 | 79 | once = 1; |
| 79 | 80 | db_prepare(&q, "PRAGMA table_info(ticket)"); |
| 80 | 81 | while( db_step(&q)==SQLITE_ROW ){ |
| @@ -101,10 +102,13 @@ | ||
| 101 | 102 | haveTicketChngRid = 1; /* tkt_rid */ |
| 102 | 103 | }else if( strcmp(zFieldName+4,"user")==0 ){ |
| 103 | 104 | haveTicketChngUser = 1; /* tkt_user */ |
| 104 | 105 | } |
| 105 | 106 | continue; |
| 107 | + } | |
| 108 | + if( strcmp(zFieldName,"mimetype")==0 ){ | |
| 109 | + bRegularMimetype = 1; | |
| 106 | 110 | } |
| 107 | 111 | if( (i = fieldId(zFieldName))>=0 ){ |
| 108 | 112 | aField[i].mUsed |= USEDBY_TICKETCHNG; |
| 109 | 113 | continue; |
| 110 | 114 | } |
| @@ -119,10 +123,15 @@ | ||
| 119 | 123 | qsort(aField, nField, sizeof(aField[0]), nameCmpr); |
| 120 | 124 | for(i=0; i<nField; i++){ |
| 121 | 125 | aField[i].zValue = ""; |
| 122 | 126 | aField[i].zAppend = 0; |
| 123 | 127 | } |
| 128 | + if( !bRegularMimetype && | |
| 129 | + db_exists("SELECT 1 FROM pragma_table_xinfo('ticketchng') " | |
| 130 | + "WHERE name = 'mimetype'") ){ | |
| 131 | + haveTicketChngGenMt = 1; | |
| 132 | + } | |
| 124 | 133 | } |
| 125 | 134 | |
| 126 | 135 | /* |
| 127 | 136 | ** Query the database for all TICKET fields for the specific |
| 128 | 137 | ** ticket whose name is given by the "name" CGI parameter. |
| @@ -194,11 +203,11 @@ | ||
| 194 | 203 | ** |
| 195 | 204 | ** Parameter rid is the recordID for the ticket artifact in the BLOB table. |
| 196 | 205 | ** |
| 197 | 206 | ** Return the new rowid of the TICKET table entry. |
| 198 | 207 | */ |
| 199 | -static int ticket_insert(const Manifest *p, int rid, int tktid){ | |
| 208 | +static int ticket_insert(const Manifest *p, const int rid, int tktid){ | |
| 200 | 209 | Blob sql1; /* update or replace TICKET ... */ |
| 201 | 210 | Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */ |
| 202 | 211 | Blob sql3; /* list of values which correspond to the previous list */ |
| 203 | 212 | Stmt q; |
| 204 | 213 | int i, j; |
| @@ -236,25 +245,14 @@ | ||
| 236 | 245 | if( aField[j].mUsed & USEDBY_TICKETCHNG ){ |
| 237 | 246 | blob_append_sql(&sql2, ",\"%w\"", zBaseName); |
| 238 | 247 | blob_append_sql(&sql3, ",%Q", p->aField[i].zValue); |
| 239 | 248 | } |
| 240 | 249 | if( strcmp(zBaseName,"mimetype")==0 ){ |
| 250 | + assert(!haveTicketChngGenMt); /* aField is for regular columns */ | |
| 241 | 251 | zMimetype = p->aField[i].zValue; |
| 242 | 252 | } |
| 243 | 253 | } |
| 244 | - if( rid>0 ){ | |
| 245 | - int bReplace = 1; | |
| 246 | - for(i=0; i<p->nField; i++){ | |
| 247 | - const char *zName = p->aField[i].zName; | |
| 248 | - const char *zBaseName = zName[0]=='+' ? zName+1 : zName; | |
| 249 | - j = fieldId(zBaseName); | |
| 250 | - if( j<0 ) continue; | |
| 251 | - backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET, | |
| 252 | - p->rDate, bReplace); | |
| 253 | - bReplace = 0; | |
| 254 | - } | |
| 255 | - } | |
| 256 | 254 | blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid); |
| 257 | 255 | db_prepare(&q, "%s", blob_sql_text(&sql1)); |
| 258 | 256 | db_bind_double(&q, ":mtime", p->rDate); |
| 259 | 257 | db_step(&q); |
| 260 | 258 | db_finalize(&q); |
| @@ -280,25 +278,45 @@ | ||
| 280 | 278 | blob_append_sql(&sql3, ",\"%w\"", z); |
| 281 | 279 | } |
| 282 | 280 | } |
| 283 | 281 | if( fromTkt ){ |
| 284 | 282 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 285 | - "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d", | |
| 283 | + "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d%s", | |
| 286 | 284 | blob_sql_text(&sql2), tktid, |
| 287 | - blob_sql_text(&sql3), tktid); | |
| 285 | + blob_sql_text(&sql3), tktid, | |
| 286 | + haveTicketChngGenMt ? " RETURNING mimetype" : ""); | |
| 288 | 287 | }else{ |
| 289 | 288 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 290 | - "VALUES(%d,:mtime%s)", | |
| 291 | - blob_sql_text(&sql2), tktid, blob_sql_text(&sql3)); | |
| 289 | + "VALUES(%d,:mtime%s)%s", | |
| 290 | + blob_sql_text(&sql2), tktid, blob_sql_text(&sql3), | |
| 291 | + haveTicketChngGenMt ? " RETURNING mimetype" : ""); | |
| 292 | 292 | } |
| 293 | 293 | db_bind_double(&q, ":mtime", p->rDate); |
| 294 | 294 | db_step(&q); |
| 295 | + if( haveTicketChngGenMt ){ | |
| 296 | + zMimetype = db_column_malloc(&q, 0); | |
| 297 | + } | |
| 295 | 298 | db_finalize(&q); |
| 296 | 299 | } |
| 297 | 300 | blob_reset(&sql2); |
| 298 | 301 | blob_reset(&sql3); |
| 302 | + if( rid>0 ){ | |
| 303 | + int bReplace = 1; | |
| 304 | + for(i=0; i<p->nField; i++){ | |
| 305 | + const char *zName = p->aField[i].zName; | |
| 306 | + const char *zBaseName = zName[0]=='+' ? zName+1 : zName; | |
| 307 | + j = fieldId(zBaseName); | |
| 308 | + if( j<0 /*|| strcmp(zBaseName,"mimetype")==0*/ ) continue; | |
| 309 | + backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET, | |
| 310 | + p->rDate, bReplace); | |
| 311 | + bReplace = 0; | |
| 312 | + } | |
| 313 | + } | |
| 299 | 314 | fossil_free(aUsed); |
| 315 | + if( haveTicketChngGenMt && zMimetype ){ | |
| 316 | + fossil_free((char*)zMimetype); | |
| 317 | + } | |
| 300 | 318 | return tktid; |
| 301 | 319 | } |
| 302 | 320 | |
| 303 | 321 | /* |
| 304 | 322 | ** Returns non-zero if moderation is required for ticket changes and ticket |
| 305 | 323 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -40,10 +40,11 @@ | |
| 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 +71,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 ){ |
| @@ -101,10 +102,13 @@ | |
| 101 | haveTicketChngRid = 1; /* tkt_rid */ |
| 102 | }else if( strcmp(zFieldName+4,"user")==0 ){ |
| 103 | haveTicketChngUser = 1; /* tkt_user */ |
| 104 | } |
| 105 | continue; |
| 106 | } |
| 107 | if( (i = fieldId(zFieldName))>=0 ){ |
| 108 | aField[i].mUsed |= USEDBY_TICKETCHNG; |
| 109 | continue; |
| 110 | } |
| @@ -119,10 +123,15 @@ | |
| 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 |
| 128 | ** ticket whose name is given by the "name" CGI parameter. |
| @@ -194,11 +203,11 @@ | |
| 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; |
| @@ -236,25 +245,14 @@ | |
| 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 | int bReplace = 1; |
| 246 | for(i=0; i<p->nField; i++){ |
| 247 | const char *zName = p->aField[i].zName; |
| 248 | const char *zBaseName = zName[0]=='+' ? zName+1 : zName; |
| 249 | j = fieldId(zBaseName); |
| 250 | if( j<0 ) continue; |
| 251 | backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET, |
| 252 | p->rDate, bReplace); |
| 253 | bReplace = 0; |
| 254 | } |
| 255 | } |
| 256 | blob_append_sql(&sql1, " WHERE tkt_id=%d", tktid); |
| 257 | db_prepare(&q, "%s", blob_sql_text(&sql1)); |
| 258 | db_bind_double(&q, ":mtime", p->rDate); |
| 259 | db_step(&q); |
| 260 | db_finalize(&q); |
| @@ -280,25 +278,45 @@ | |
| 280 | blob_append_sql(&sql3, ",\"%w\"", z); |
| 281 | } |
| 282 | } |
| 283 | if( fromTkt ){ |
| 284 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 285 | "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d", |
| 286 | blob_sql_text(&sql2), tktid, |
| 287 | blob_sql_text(&sql3), tktid); |
| 288 | }else{ |
| 289 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 290 | "VALUES(%d,:mtime%s)", |
| 291 | blob_sql_text(&sql2), tktid, blob_sql_text(&sql3)); |
| 292 | } |
| 293 | db_bind_double(&q, ":mtime", p->rDate); |
| 294 | db_step(&q); |
| 295 | db_finalize(&q); |
| 296 | } |
| 297 | blob_reset(&sql2); |
| 298 | blob_reset(&sql3); |
| 299 | fossil_free(aUsed); |
| 300 | return tktid; |
| 301 | } |
| 302 | |
| 303 | /* |
| 304 | ** Returns non-zero if moderation is required for ticket changes and ticket |
| 305 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -40,10 +40,11 @@ | |
| 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 haveTicketChngGenMt= 0;/* True if TICKETCHNG.MIMETYPE is generated */ |
| 46 | |
| 47 | /* |
| 48 | ** Compare two entries in aField[] for sorting purposes |
| 49 | */ |
| 50 | static int nameCmpr(const void *a, const void *b){ |
| @@ -70,11 +71,11 @@ | |
| 71 | ** The haveTicket and haveTicketChng variables are set to 1 if the TICKET and |
| 72 | ** TICKETCHANGE tables exist, respectively. |
| 73 | */ |
| 74 | static void getAllTicketFields(void){ |
| 75 | Stmt q; |
| 76 | int i, bRegularMimetype = 0; |
| 77 | static int once = 0; |
| 78 | if( once ) return; |
| 79 | once = 1; |
| 80 | db_prepare(&q, "PRAGMA table_info(ticket)"); |
| 81 | while( db_step(&q)==SQLITE_ROW ){ |
| @@ -101,10 +102,13 @@ | |
| 102 | haveTicketChngRid = 1; /* tkt_rid */ |
| 103 | }else if( strcmp(zFieldName+4,"user")==0 ){ |
| 104 | haveTicketChngUser = 1; /* tkt_user */ |
| 105 | } |
| 106 | continue; |
| 107 | } |
| 108 | if( strcmp(zFieldName,"mimetype")==0 ){ |
| 109 | bRegularMimetype = 1; |
| 110 | } |
| 111 | if( (i = fieldId(zFieldName))>=0 ){ |
| 112 | aField[i].mUsed |= USEDBY_TICKETCHNG; |
| 113 | continue; |
| 114 | } |
| @@ -119,10 +123,15 @@ | |
| 123 | qsort(aField, nField, sizeof(aField[0]), nameCmpr); |
| 124 | for(i=0; i<nField; i++){ |
| 125 | aField[i].zValue = ""; |
| 126 | aField[i].zAppend = 0; |
| 127 | } |
| 128 | if( !bRegularMimetype && |
| 129 | db_exists("SELECT 1 FROM pragma_table_xinfo('ticketchng') " |
| 130 | "WHERE name = 'mimetype'") ){ |
| 131 | haveTicketChngGenMt = 1; |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | /* |
| 136 | ** Query the database for all TICKET fields for the specific |
| 137 | ** ticket whose name is given by the "name" CGI parameter. |
| @@ -194,11 +203,11 @@ | |
| 203 | ** |
| 204 | ** Parameter rid is the recordID for the ticket artifact in the BLOB table. |
| 205 | ** |
| 206 | ** Return the new rowid of the TICKET table entry. |
| 207 | */ |
| 208 | static int ticket_insert(const Manifest *p, const int rid, int tktid){ |
| 209 | Blob sql1; /* update or replace TICKET ... */ |
| 210 | Blob sql2; /* list of TICKETCHNG's fields that are in the manifest */ |
| 211 | Blob sql3; /* list of values which correspond to the previous list */ |
| 212 | Stmt q; |
| 213 | int i, j; |
| @@ -236,25 +245,14 @@ | |
| 245 | if( aField[j].mUsed & USEDBY_TICKETCHNG ){ |
| 246 | blob_append_sql(&sql2, ",\"%w\"", zBaseName); |
| 247 | blob_append_sql(&sql3, ",%Q", p->aField[i].zValue); |
| 248 | } |
| 249 | if( strcmp(zBaseName,"mimetype")==0 ){ |
| 250 | assert(!haveTicketChngGenMt); /* aField is for regular columns */ |
| 251 | zMimetype = p->aField[i].zValue; |
| 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); |
| @@ -280,25 +278,45 @@ | |
| 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%s", |
| 284 | blob_sql_text(&sql2), tktid, |
| 285 | blob_sql_text(&sql3), tktid, |
| 286 | haveTicketChngGenMt ? " RETURNING mimetype" : ""); |
| 287 | }else{ |
| 288 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 289 | "VALUES(%d,:mtime%s)%s", |
| 290 | blob_sql_text(&sql2), tktid, blob_sql_text(&sql3), |
| 291 | haveTicketChngGenMt ? " RETURNING mimetype" : ""); |
| 292 | } |
| 293 | db_bind_double(&q, ":mtime", p->rDate); |
| 294 | db_step(&q); |
| 295 | if( haveTicketChngGenMt ){ |
| 296 | zMimetype = db_column_malloc(&q, 0); |
| 297 | } |
| 298 | db_finalize(&q); |
| 299 | } |
| 300 | blob_reset(&sql2); |
| 301 | blob_reset(&sql3); |
| 302 | if( rid>0 ){ |
| 303 | int bReplace = 1; |
| 304 | for(i=0; i<p->nField; i++){ |
| 305 | const char *zName = p->aField[i].zName; |
| 306 | const char *zBaseName = zName[0]=='+' ? zName+1 : zName; |
| 307 | j = fieldId(zBaseName); |
| 308 | if( j<0 /*|| strcmp(zBaseName,"mimetype")==0*/ ) continue; |
| 309 | backlink_extract(p->aField[i].zValue, zMimetype, rid, BKLNK_TICKET, |
| 310 | p->rDate, bReplace); |
| 311 | bReplace = 0; |
| 312 | } |
| 313 | } |
| 314 | fossil_free(aUsed); |
| 315 | if( haveTicketChngGenMt && zMimetype ){ |
| 316 | fossil_free((char*)zMimetype); |
| 317 | } |
| 318 | return tktid; |
| 319 | } |
| 320 | |
| 321 | /* |
| 322 | ** Returns non-zero if moderation is required for ticket changes and ticket |
| 323 |