Fossil SCM
merge trunk
Commit
9a88d1963f17a1fe1367b56ec25cc078cf3cf868
Parent
6e9e6436a6256b4…
12 files changed
+1
-1
+3
+33
-2
-2
+1
-2
+70
-8
+9
-9
+2
+104
+11
-3
+73
-16
+2
+1
-1
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -1527,11 +1527,11 @@ | ||
| 1527 | 1527 | exit(1); |
| 1528 | 1528 | } |
| 1529 | 1529 | db_end_transaction(0); |
| 1530 | 1530 | |
| 1531 | 1531 | if( !g.markPrivate ){ |
| 1532 | - autosync(SYNC_PUSH); | |
| 1532 | + autosync(SYNC_PUSH|SYNC_PULL); | |
| 1533 | 1533 | } |
| 1534 | 1534 | if( count_nonbranch_children(vid)>1 ){ |
| 1535 | 1535 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 1536 | 1536 | } |
| 1537 | 1537 | } |
| 1538 | 1538 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1527,11 +1527,11 @@ | |
| 1527 | exit(1); |
| 1528 | } |
| 1529 | db_end_transaction(0); |
| 1530 | |
| 1531 | if( !g.markPrivate ){ |
| 1532 | autosync(SYNC_PUSH); |
| 1533 | } |
| 1534 | if( count_nonbranch_children(vid)>1 ){ |
| 1535 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 1536 | } |
| 1537 | } |
| 1538 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1527,11 +1527,11 @@ | |
| 1527 | exit(1); |
| 1528 | } |
| 1529 | db_end_transaction(0); |
| 1530 | |
| 1531 | if( !g.markPrivate ){ |
| 1532 | autosync(SYNC_PUSH|SYNC_PULL); |
| 1533 | } |
| 1534 | if( count_nonbranch_children(vid)>1 ){ |
| 1535 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 1536 | } |
| 1537 | } |
| 1538 |
M
src/db.c
+3
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1222,10 +1222,13 @@ | ||
| 1222 | 1222 | void db_create_default_users(int setupUserOnly, const char *zDefaultUser){ |
| 1223 | 1223 | const char *zUser = zDefaultUser; |
| 1224 | 1224 | if( zUser==0 ){ |
| 1225 | 1225 | zUser = db_get("default-user", 0); |
| 1226 | 1226 | } |
| 1227 | + if( zUser==0 ){ | |
| 1228 | + zUser = fossil_getenv("FOSSIL_USER"); | |
| 1229 | + } | |
| 1227 | 1230 | if( zUser==0 ){ |
| 1228 | 1231 | #if defined(_WIN32) |
| 1229 | 1232 | zUser = fossil_getenv("USERNAME"); |
| 1230 | 1233 | #else |
| 1231 | 1234 | zUser = fossil_getenv("USER"); |
| 1232 | 1235 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1222,10 +1222,13 @@ | |
| 1222 | void db_create_default_users(int setupUserOnly, const char *zDefaultUser){ |
| 1223 | const char *zUser = zDefaultUser; |
| 1224 | if( zUser==0 ){ |
| 1225 | zUser = db_get("default-user", 0); |
| 1226 | } |
| 1227 | if( zUser==0 ){ |
| 1228 | #if defined(_WIN32) |
| 1229 | zUser = fossil_getenv("USERNAME"); |
| 1230 | #else |
| 1231 | zUser = fossil_getenv("USER"); |
| 1232 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1222,10 +1222,13 @@ | |
| 1222 | void db_create_default_users(int setupUserOnly, const char *zDefaultUser){ |
| 1223 | const char *zUser = zDefaultUser; |
| 1224 | if( zUser==0 ){ |
| 1225 | zUser = db_get("default-user", 0); |
| 1226 | } |
| 1227 | if( zUser==0 ){ |
| 1228 | zUser = fossil_getenv("FOSSIL_USER"); |
| 1229 | } |
| 1230 | if( zUser==0 ){ |
| 1231 | #if defined(_WIN32) |
| 1232 | zUser = fossil_getenv("USERNAME"); |
| 1233 | #else |
| 1234 | zUser = fossil_getenv("USER"); |
| 1235 |
+33
-2
| --- src/descendants.c | ||
| +++ src/descendants.c | ||
| @@ -348,10 +348,11 @@ | ||
| 348 | 348 | ** repository database to be recomputed. |
| 349 | 349 | ** |
| 350 | 350 | ** Options: |
| 351 | 351 | ** --all show ALL leaves |
| 352 | 352 | ** --closed show only closed leaves |
| 353 | +** --bybranch order output by branch name | |
| 353 | 354 | ** --recompute recompute the "leaf" table in the repository DB |
| 354 | 355 | ** |
| 355 | 356 | ** See also: descendants, finfo, info, branch |
| 356 | 357 | */ |
| 357 | 358 | void leaves_cmd(void){ |
| @@ -358,10 +359,14 @@ | ||
| 358 | 359 | Stmt q; |
| 359 | 360 | Blob sql; |
| 360 | 361 | int showAll = find_option("all", 0, 0)!=0; |
| 361 | 362 | int showClosed = find_option("closed", 0, 0)!=0; |
| 362 | 363 | int recomputeFlag = find_option("recompute",0,0)!=0; |
| 364 | + int byBranch = find_option("bybranch",0,0)!=0; | |
| 365 | + char *zLastBr = 0; | |
| 366 | + int n; | |
| 367 | + char zLineNo[10]; | |
| 363 | 368 | |
| 364 | 369 | db_find_and_open_repository(0,0); |
| 365 | 370 | if( recomputeFlag ) leaf_rebuild(); |
| 366 | 371 | blob_zero(&sql); |
| 367 | 372 | blob_append(&sql, timeline_query_for_tty(), -1); |
| @@ -369,13 +374,39 @@ | ||
| 369 | 374 | if( showClosed ){ |
| 370 | 375 | blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid")); |
| 371 | 376 | }else if( !showAll ){ |
| 372 | 377 | blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); |
| 373 | 378 | } |
| 374 | - db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql)); | |
| 379 | + if( byBranch ){ | |
| 380 | + db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase," | |
| 381 | + " event.mtime DESC", | |
| 382 | + blob_str(&sql)); | |
| 383 | + }else{ | |
| 384 | + db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql)); | |
| 385 | + } | |
| 375 | 386 | blob_reset(&sql); |
| 376 | - print_timeline(&q, 2000, 0); | |
| 387 | + n = 0; | |
| 388 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 389 | + const char *zId = db_column_text(&q, 1); | |
| 390 | + const char *zDate = db_column_text(&q, 2); | |
| 391 | + const char *zCom = db_column_text(&q, 3); | |
| 392 | + const char *zBr = db_column_text(&q, 7); | |
| 393 | + char *z; | |
| 394 | + | |
| 395 | + if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){ | |
| 396 | + fossil_print("*** %s ***\n", zBr); | |
| 397 | + fossil_free(zLastBr); | |
| 398 | + zLastBr = fossil_strdup(zBr); | |
| 399 | + } | |
| 400 | + n++; | |
| 401 | + sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n); | |
| 402 | + fossil_print("%6s ", zLineNo); | |
| 403 | + z = mprintf("%s [%.10s] %s", zDate, zId, zCom); | |
| 404 | + comment_print(z, 7, 79); | |
| 405 | + fossil_free(z); | |
| 406 | + } | |
| 407 | + fossil_free(zLastBr); | |
| 377 | 408 | db_finalize(&q); |
| 378 | 409 | } |
| 379 | 410 | |
| 380 | 411 | /* |
| 381 | 412 | ** WEBPAGE: leaves |
| 382 | 413 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -348,10 +348,11 @@ | |
| 348 | ** repository database to be recomputed. |
| 349 | ** |
| 350 | ** Options: |
| 351 | ** --all show ALL leaves |
| 352 | ** --closed show only closed leaves |
| 353 | ** --recompute recompute the "leaf" table in the repository DB |
| 354 | ** |
| 355 | ** See also: descendants, finfo, info, branch |
| 356 | */ |
| 357 | void leaves_cmd(void){ |
| @@ -358,10 +359,14 @@ | |
| 358 | Stmt q; |
| 359 | Blob sql; |
| 360 | int showAll = find_option("all", 0, 0)!=0; |
| 361 | int showClosed = find_option("closed", 0, 0)!=0; |
| 362 | int recomputeFlag = find_option("recompute",0,0)!=0; |
| 363 | |
| 364 | db_find_and_open_repository(0,0); |
| 365 | if( recomputeFlag ) leaf_rebuild(); |
| 366 | blob_zero(&sql); |
| 367 | blob_append(&sql, timeline_query_for_tty(), -1); |
| @@ -369,13 +374,39 @@ | |
| 369 | if( showClosed ){ |
| 370 | blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid")); |
| 371 | }else if( !showAll ){ |
| 372 | blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); |
| 373 | } |
| 374 | db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql)); |
| 375 | blob_reset(&sql); |
| 376 | print_timeline(&q, 2000, 0); |
| 377 | db_finalize(&q); |
| 378 | } |
| 379 | |
| 380 | /* |
| 381 | ** WEBPAGE: leaves |
| 382 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -348,10 +348,11 @@ | |
| 348 | ** repository database to be recomputed. |
| 349 | ** |
| 350 | ** Options: |
| 351 | ** --all show ALL leaves |
| 352 | ** --closed show only closed leaves |
| 353 | ** --bybranch order output by branch name |
| 354 | ** --recompute recompute the "leaf" table in the repository DB |
| 355 | ** |
| 356 | ** See also: descendants, finfo, info, branch |
| 357 | */ |
| 358 | void leaves_cmd(void){ |
| @@ -358,10 +359,14 @@ | |
| 359 | Stmt q; |
| 360 | Blob sql; |
| 361 | int showAll = find_option("all", 0, 0)!=0; |
| 362 | int showClosed = find_option("closed", 0, 0)!=0; |
| 363 | int recomputeFlag = find_option("recompute",0,0)!=0; |
| 364 | int byBranch = find_option("bybranch",0,0)!=0; |
| 365 | char *zLastBr = 0; |
| 366 | int n; |
| 367 | char zLineNo[10]; |
| 368 | |
| 369 | db_find_and_open_repository(0,0); |
| 370 | if( recomputeFlag ) leaf_rebuild(); |
| 371 | blob_zero(&sql); |
| 372 | blob_append(&sql, timeline_query_for_tty(), -1); |
| @@ -369,13 +374,39 @@ | |
| 374 | if( showClosed ){ |
| 375 | blob_appendf(&sql," AND %z", leaf_is_closed_sql("blob.rid")); |
| 376 | }else if( !showAll ){ |
| 377 | blob_appendf(&sql," AND NOT %z", leaf_is_closed_sql("blob.rid")); |
| 378 | } |
| 379 | if( byBranch ){ |
| 380 | db_prepare(&q, "%s ORDER BY nullif(branch,'trunk') COLLATE nocase," |
| 381 | " event.mtime DESC", |
| 382 | blob_str(&sql)); |
| 383 | }else{ |
| 384 | db_prepare(&q, "%s ORDER BY event.mtime DESC", blob_str(&sql)); |
| 385 | } |
| 386 | blob_reset(&sql); |
| 387 | n = 0; |
| 388 | while( db_step(&q)==SQLITE_ROW ){ |
| 389 | const char *zId = db_column_text(&q, 1); |
| 390 | const char *zDate = db_column_text(&q, 2); |
| 391 | const char *zCom = db_column_text(&q, 3); |
| 392 | const char *zBr = db_column_text(&q, 7); |
| 393 | char *z; |
| 394 | |
| 395 | if( byBranch && fossil_strcmp(zBr, zLastBr)!=0 ){ |
| 396 | fossil_print("*** %s ***\n", zBr); |
| 397 | fossil_free(zLastBr); |
| 398 | zLastBr = fossil_strdup(zBr); |
| 399 | } |
| 400 | n++; |
| 401 | sqlite3_snprintf(sizeof(zLineNo), zLineNo, "(%d)", n); |
| 402 | fossil_print("%6s ", zLineNo); |
| 403 | z = mprintf("%s [%.10s] %s", zDate, zId, zCom); |
| 404 | comment_print(z, 7, 79); |
| 405 | fossil_free(z); |
| 406 | } |
| 407 | fossil_free(zLastBr); |
| 408 | db_finalize(&q); |
| 409 | } |
| 410 | |
| 411 | /* |
| 412 | ** WEBPAGE: leaves |
| 413 |
-2
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -620,13 +620,11 @@ | ||
| 620 | 620 | |
| 621 | 621 | /* Show the differences */ |
| 622 | 622 | for(i=0; i<nr; i++){ |
| 623 | 623 | m = R[r+i*3+1]; |
| 624 | 624 | for(j=0; j<m; j++){ |
| 625 | - char cMark = '-'; | |
| 626 | 625 | if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html); |
| 627 | - if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' '; | |
| 628 | 626 | appendDiffLine(pOut, '-', &A[a+j], html, pRe); |
| 629 | 627 | } |
| 630 | 628 | a += m; |
| 631 | 629 | m = R[r+i*3+2]; |
| 632 | 630 | for(j=0; j<m; j++){ |
| 633 | 631 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -620,13 +620,11 @@ | |
| 620 | |
| 621 | /* Show the differences */ |
| 622 | for(i=0; i<nr; i++){ |
| 623 | m = R[r+i*3+1]; |
| 624 | for(j=0; j<m; j++){ |
| 625 | char cMark = '-'; |
| 626 | if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html); |
| 627 | if( pRe && re_dline_match(pRe, &A[a+j], 1)==0 ) cMark = ' '; |
| 628 | appendDiffLine(pOut, '-', &A[a+j], html, pRe); |
| 629 | } |
| 630 | a += m; |
| 631 | m = R[r+i*3+2]; |
| 632 | for(j=0; j<m; j++){ |
| 633 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -620,13 +620,11 @@ | |
| 620 | |
| 621 | /* Show the differences */ |
| 622 | for(i=0; i<nr; i++){ |
| 623 | m = R[r+i*3+1]; |
| 624 | for(j=0; j<m; j++){ |
| 625 | if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html); |
| 626 | appendDiffLine(pOut, '-', &A[a+j], html, pRe); |
| 627 | } |
| 628 | a += m; |
| 629 | m = R[r+i*3+2]; |
| 630 | for(j=0; j<m; j++){ |
| 631 |
+1
-2
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1298,11 +1298,10 @@ | ||
| 1298 | 1298 | char *zV2; |
| 1299 | 1299 | const char *zRe; |
| 1300 | 1300 | ReCompiled *pRe = 0; |
| 1301 | 1301 | u64 diffFlags; |
| 1302 | 1302 | const char *zStyle = "sbsdiff"; |
| 1303 | - const char *zReErr = 0; | |
| 1304 | 1303 | |
| 1305 | 1304 | login_check_credentials(); |
| 1306 | 1305 | if( !g.perm.Read ){ login_needed(); return; } |
| 1307 | 1306 | v1 = name_to_rid_www("v1"); |
| 1308 | 1307 | v2 = name_to_rid_www("v2"); |
| @@ -1325,11 +1324,11 @@ | ||
| 1325 | 1324 | diffFlags |= DIFF_LINENO; |
| 1326 | 1325 | zStyle = "udiff"; |
| 1327 | 1326 | } |
| 1328 | 1327 | } |
| 1329 | 1328 | zRe = P("regex"); |
| 1330 | - if( zRe ) zReErr = re_compile(&pRe, zRe, 0); | |
| 1329 | + if( zRe ) re_compile(&pRe, zRe, 0); | |
| 1331 | 1330 | content_get(v1, &c1); |
| 1332 | 1331 | content_get(v2, &c2); |
| 1333 | 1332 | text_diff(&c1, &c2, pOut, pRe, diffFlags); |
| 1334 | 1333 | blob_reset(&c1); |
| 1335 | 1334 | blob_reset(&c2); |
| 1336 | 1335 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1298,11 +1298,10 @@ | |
| 1298 | char *zV2; |
| 1299 | const char *zRe; |
| 1300 | ReCompiled *pRe = 0; |
| 1301 | u64 diffFlags; |
| 1302 | const char *zStyle = "sbsdiff"; |
| 1303 | const char *zReErr = 0; |
| 1304 | |
| 1305 | login_check_credentials(); |
| 1306 | if( !g.perm.Read ){ login_needed(); return; } |
| 1307 | v1 = name_to_rid_www("v1"); |
| 1308 | v2 = name_to_rid_www("v2"); |
| @@ -1325,11 +1324,11 @@ | |
| 1325 | diffFlags |= DIFF_LINENO; |
| 1326 | zStyle = "udiff"; |
| 1327 | } |
| 1328 | } |
| 1329 | zRe = P("regex"); |
| 1330 | if( zRe ) zReErr = re_compile(&pRe, zRe, 0); |
| 1331 | content_get(v1, &c1); |
| 1332 | content_get(v2, &c2); |
| 1333 | text_diff(&c1, &c2, pOut, pRe, diffFlags); |
| 1334 | blob_reset(&c1); |
| 1335 | blob_reset(&c2); |
| 1336 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1298,11 +1298,10 @@ | |
| 1298 | char *zV2; |
| 1299 | const char *zRe; |
| 1300 | ReCompiled *pRe = 0; |
| 1301 | u64 diffFlags; |
| 1302 | const char *zStyle = "sbsdiff"; |
| 1303 | |
| 1304 | login_check_credentials(); |
| 1305 | if( !g.perm.Read ){ login_needed(); return; } |
| 1306 | v1 = name_to_rid_www("v1"); |
| 1307 | v2 = name_to_rid_www("v2"); |
| @@ -1325,11 +1324,11 @@ | |
| 1324 | diffFlags |= DIFF_LINENO; |
| 1325 | zStyle = "udiff"; |
| 1326 | } |
| 1327 | } |
| 1328 | zRe = P("regex"); |
| 1329 | if( zRe ) re_compile(&pRe, zRe, 0); |
| 1330 | content_get(v1, &c1); |
| 1331 | content_get(v2, &c2); |
| 1332 | text_diff(&c1, &c2, pOut, pRe, diffFlags); |
| 1333 | blob_reset(&c1); |
| 1334 | blob_reset(&c2); |
| 1335 |
+70
-8
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -57,19 +57,22 @@ | ||
| 57 | 57 | |
| 58 | 58 | |
| 59 | 59 | /* |
| 60 | 60 | ** COMMAND: merge |
| 61 | 61 | ** |
| 62 | -** Usage: %fossil merge ?OPTIONS? VERSION | |
| 62 | +** Usage: %fossil merge ?OPTIONS? ?VERSION? | |
| 63 | 63 | ** |
| 64 | 64 | ** The argument VERSION is a version that should be merged into the |
| 65 | 65 | ** current checkout. All changes from VERSION back to the nearest |
| 66 | 66 | ** common ancestor are merged. Except, if either of the --cherrypick or |
| 67 | 67 | ** --backout options are used only the changes associated with the |
| 68 | 68 | ** single check-in VERSION are merged. The --backout option causes |
| 69 | 69 | ** the changes associated with VERSION to be removed from the current |
| 70 | 70 | ** checkout rather than added. |
| 71 | +** | |
| 72 | +** If the VERSION argument is omitted, then Fossil attempts to find | |
| 73 | +** a recent fork on the current branch to merge. | |
| 71 | 74 | ** |
| 72 | 75 | ** Only file content is merged. The result continues to use the |
| 73 | 76 | ** file and directory names from the current checkout even if those |
| 74 | 77 | ** names might have been changed in the branch being merged in. |
| 75 | 78 | ** |
| @@ -131,24 +134,83 @@ | ||
| 131 | 134 | zBinGlob = find_option("binary",0,1); |
| 132 | 135 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 133 | 136 | forceFlag = find_option("force","f",0)!=0; |
| 134 | 137 | zPivot = find_option("baseline",0,1); |
| 135 | 138 | capture_case_sensitive_option(); |
| 136 | - if( g.argc!=3 ){ | |
| 137 | - usage("VERSION"); | |
| 138 | - } | |
| 139 | + verify_all_options(); | |
| 139 | 140 | db_must_be_within_tree(); |
| 140 | 141 | caseSensitive = filenames_are_case_sensitive(); |
| 141 | 142 | if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
| 142 | 143 | vid = db_lget_int("checkout", 0); |
| 143 | 144 | if( vid==0 ){ |
| 144 | 145 | fossil_fatal("nothing is checked out"); |
| 145 | 146 | } |
| 146 | - mid = name_to_typed_rid(g.argv[2], "ci"); | |
| 147 | - if( mid==0 || !is_a_version(mid) ){ | |
| 148 | - fossil_fatal("not a version: %s", g.argv[2]); | |
| 147 | + | |
| 148 | + /* Find mid, the artifactID of the version to be merged into the current | |
| 149 | + ** check-out */ | |
| 150 | + if( g.argc==3 ){ | |
| 151 | + /* Mid is specified as an argument on the command-line */ | |
| 152 | + mid = name_to_typed_rid(g.argv[2], "ci"); | |
| 153 | + if( mid==0 || !is_a_version(mid) ){ | |
| 154 | + fossil_fatal("not a version: %s", g.argv[2]); | |
| 155 | + } | |
| 156 | + }else if( g.argc==2 ){ | |
| 157 | + /* No version specified on the command-line so pick the most recent | |
| 158 | + ** leaf that is (1) not the version currently checked out and (2) | |
| 159 | + ** has not already been merged into the current checkout and (3) | |
| 160 | + ** the leaf is not closed and (4) the leaf is in the same branch | |
| 161 | + ** as the current checkout. | |
| 162 | + */ | |
| 163 | + Stmt q; | |
| 164 | + if( pickFlag || backoutFlag ){ | |
| 165 | + fossil_fatal("cannot use --cherrypick or --backout with a fork merge"); | |
| 166 | + } | |
| 167 | + mid = db_int(0, | |
| 168 | + "SELECT leaf.rid" | |
| 169 | + " FROM leaf, event" | |
| 170 | + " WHERE leaf.rid=event.objid" | |
| 171 | + " AND leaf.rid!=%d" /* Constraint (1) */ | |
| 172 | + " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */ | |
| 173 | + " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */ | |
| 174 | + " WHERE rid=leaf.rid" | |
| 175 | + " AND tagid=%d" | |
| 176 | + " AND tagtype>0)" | |
| 177 | + " AND (SELECT value FROM tagxref" /* Constraint (4) */ | |
| 178 | + " WHERE tagid=%d AND rid=%d AND tagtype>0) =" | |
| 179 | + " (SELECT value FROM tagxref" | |
| 180 | + " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)" | |
| 181 | + " ORDER BY event.mtime DESC LIMIT 1", | |
| 182 | + vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH | |
| 183 | + ); | |
| 184 | + if( mid==0 ){ | |
| 185 | + fossil_fatal("no unmerged forks of branch \"%s\"", | |
| 186 | + db_text(0, "SELECT value FROM tagxref" | |
| 187 | + " WHERE tagid=%d AND rid=%d AND tagtype>0", | |
| 188 | + TAG_BRANCH, vid) | |
| 189 | + ); | |
| 190 | + } | |
| 191 | + db_prepare(&q, | |
| 192 | + "SELECT blob.uuid," | |
| 193 | + " datetime(event.mtime,'localtime')," | |
| 194 | + " coalesce(ecomment, comment)," | |
| 195 | + " coalesce(euser, user)" | |
| 196 | + " FROM event, blob" | |
| 197 | + " WHERE event.objid=%d AND blob.rid=%d", | |
| 198 | + mid, mid | |
| 199 | + ); | |
| 200 | + if( db_step(&q)==SQLITE_ROW ){ | |
| 201 | + char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", | |
| 202 | + db_column_text(&q, 0), db_column_text(&q, 1), | |
| 203 | + db_column_text(&q, 3), db_column_text(&q, 2)); | |
| 204 | + comment_print(zCom, 0, 79); | |
| 205 | + fossil_free(zCom); | |
| 206 | + } | |
| 207 | + db_finalize(&q); | |
| 208 | + }else{ | |
| 209 | + usage("?OPTIONS? ?VERSION?"); | |
| 149 | 210 | } |
| 211 | + | |
| 150 | 212 | if( zPivot ){ |
| 151 | 213 | pid = name_to_typed_rid(zPivot, "ci"); |
| 152 | 214 | if( pid==0 || !is_a_version(pid) ){ |
| 153 | 215 | fossil_fatal("not a version: %s", zPivot); |
| 154 | 216 | } |
| @@ -347,11 +409,11 @@ | ||
| 347 | 409 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 348 | 410 | ); |
| 349 | 411 | while( db_step(&q)==SQLITE_ROW ){ |
| 350 | 412 | int idm = db_column_int(&q, 0); |
| 351 | 413 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 352 | - fossil_warning("WARNING - no common ancestor: %s\n", zName); | |
| 414 | + fossil_warning("WARNING - no common ancestor: %s", zName); | |
| 353 | 415 | free(zName); |
| 354 | 416 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 355 | 417 | } |
| 356 | 418 | db_finalize(&q); |
| 357 | 419 | |
| 358 | 420 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -57,19 +57,22 @@ | |
| 57 | |
| 58 | |
| 59 | /* |
| 60 | ** COMMAND: merge |
| 61 | ** |
| 62 | ** Usage: %fossil merge ?OPTIONS? VERSION |
| 63 | ** |
| 64 | ** The argument VERSION is a version that should be merged into the |
| 65 | ** current checkout. All changes from VERSION back to the nearest |
| 66 | ** common ancestor are merged. Except, if either of the --cherrypick or |
| 67 | ** --backout options are used only the changes associated with the |
| 68 | ** single check-in VERSION are merged. The --backout option causes |
| 69 | ** the changes associated with VERSION to be removed from the current |
| 70 | ** checkout rather than added. |
| 71 | ** |
| 72 | ** Only file content is merged. The result continues to use the |
| 73 | ** file and directory names from the current checkout even if those |
| 74 | ** names might have been changed in the branch being merged in. |
| 75 | ** |
| @@ -131,24 +134,83 @@ | |
| 131 | zBinGlob = find_option("binary",0,1); |
| 132 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 133 | forceFlag = find_option("force","f",0)!=0; |
| 134 | zPivot = find_option("baseline",0,1); |
| 135 | capture_case_sensitive_option(); |
| 136 | if( g.argc!=3 ){ |
| 137 | usage("VERSION"); |
| 138 | } |
| 139 | db_must_be_within_tree(); |
| 140 | caseSensitive = filenames_are_case_sensitive(); |
| 141 | if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
| 142 | vid = db_lget_int("checkout", 0); |
| 143 | if( vid==0 ){ |
| 144 | fossil_fatal("nothing is checked out"); |
| 145 | } |
| 146 | mid = name_to_typed_rid(g.argv[2], "ci"); |
| 147 | if( mid==0 || !is_a_version(mid) ){ |
| 148 | fossil_fatal("not a version: %s", g.argv[2]); |
| 149 | } |
| 150 | if( zPivot ){ |
| 151 | pid = name_to_typed_rid(zPivot, "ci"); |
| 152 | if( pid==0 || !is_a_version(pid) ){ |
| 153 | fossil_fatal("not a version: %s", zPivot); |
| 154 | } |
| @@ -347,11 +409,11 @@ | |
| 347 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 348 | ); |
| 349 | while( db_step(&q)==SQLITE_ROW ){ |
| 350 | int idm = db_column_int(&q, 0); |
| 351 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 352 | fossil_warning("WARNING - no common ancestor: %s\n", zName); |
| 353 | free(zName); |
| 354 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 355 | } |
| 356 | db_finalize(&q); |
| 357 | |
| 358 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -57,19 +57,22 @@ | |
| 57 | |
| 58 | |
| 59 | /* |
| 60 | ** COMMAND: merge |
| 61 | ** |
| 62 | ** Usage: %fossil merge ?OPTIONS? ?VERSION? |
| 63 | ** |
| 64 | ** The argument VERSION is a version that should be merged into the |
| 65 | ** current checkout. All changes from VERSION back to the nearest |
| 66 | ** common ancestor are merged. Except, if either of the --cherrypick or |
| 67 | ** --backout options are used only the changes associated with the |
| 68 | ** single check-in VERSION are merged. The --backout option causes |
| 69 | ** the changes associated with VERSION to be removed from the current |
| 70 | ** checkout rather than added. |
| 71 | ** |
| 72 | ** If the VERSION argument is omitted, then Fossil attempts to find |
| 73 | ** a recent fork on the current branch to merge. |
| 74 | ** |
| 75 | ** Only file content is merged. The result continues to use the |
| 76 | ** file and directory names from the current checkout even if those |
| 77 | ** names might have been changed in the branch being merged in. |
| 78 | ** |
| @@ -131,24 +134,83 @@ | |
| 134 | zBinGlob = find_option("binary",0,1); |
| 135 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 136 | forceFlag = find_option("force","f",0)!=0; |
| 137 | zPivot = find_option("baseline",0,1); |
| 138 | capture_case_sensitive_option(); |
| 139 | verify_all_options(); |
| 140 | db_must_be_within_tree(); |
| 141 | caseSensitive = filenames_are_case_sensitive(); |
| 142 | if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
| 143 | vid = db_lget_int("checkout", 0); |
| 144 | if( vid==0 ){ |
| 145 | fossil_fatal("nothing is checked out"); |
| 146 | } |
| 147 | |
| 148 | /* Find mid, the artifactID of the version to be merged into the current |
| 149 | ** check-out */ |
| 150 | if( g.argc==3 ){ |
| 151 | /* Mid is specified as an argument on the command-line */ |
| 152 | mid = name_to_typed_rid(g.argv[2], "ci"); |
| 153 | if( mid==0 || !is_a_version(mid) ){ |
| 154 | fossil_fatal("not a version: %s", g.argv[2]); |
| 155 | } |
| 156 | }else if( g.argc==2 ){ |
| 157 | /* No version specified on the command-line so pick the most recent |
| 158 | ** leaf that is (1) not the version currently checked out and (2) |
| 159 | ** has not already been merged into the current checkout and (3) |
| 160 | ** the leaf is not closed and (4) the leaf is in the same branch |
| 161 | ** as the current checkout. |
| 162 | */ |
| 163 | Stmt q; |
| 164 | if( pickFlag || backoutFlag ){ |
| 165 | fossil_fatal("cannot use --cherrypick or --backout with a fork merge"); |
| 166 | } |
| 167 | mid = db_int(0, |
| 168 | "SELECT leaf.rid" |
| 169 | " FROM leaf, event" |
| 170 | " WHERE leaf.rid=event.objid" |
| 171 | " AND leaf.rid!=%d" /* Constraint (1) */ |
| 172 | " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */ |
| 173 | " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */ |
| 174 | " WHERE rid=leaf.rid" |
| 175 | " AND tagid=%d" |
| 176 | " AND tagtype>0)" |
| 177 | " AND (SELECT value FROM tagxref" /* Constraint (4) */ |
| 178 | " WHERE tagid=%d AND rid=%d AND tagtype>0) =" |
| 179 | " (SELECT value FROM tagxref" |
| 180 | " WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)" |
| 181 | " ORDER BY event.mtime DESC LIMIT 1", |
| 182 | vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH |
| 183 | ); |
| 184 | if( mid==0 ){ |
| 185 | fossil_fatal("no unmerged forks of branch \"%s\"", |
| 186 | db_text(0, "SELECT value FROM tagxref" |
| 187 | " WHERE tagid=%d AND rid=%d AND tagtype>0", |
| 188 | TAG_BRANCH, vid) |
| 189 | ); |
| 190 | } |
| 191 | db_prepare(&q, |
| 192 | "SELECT blob.uuid," |
| 193 | " datetime(event.mtime,'localtime')," |
| 194 | " coalesce(ecomment, comment)," |
| 195 | " coalesce(euser, user)" |
| 196 | " FROM event, blob" |
| 197 | " WHERE event.objid=%d AND blob.rid=%d", |
| 198 | mid, mid |
| 199 | ); |
| 200 | if( db_step(&q)==SQLITE_ROW ){ |
| 201 | char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", |
| 202 | db_column_text(&q, 0), db_column_text(&q, 1), |
| 203 | db_column_text(&q, 3), db_column_text(&q, 2)); |
| 204 | comment_print(zCom, 0, 79); |
| 205 | fossil_free(zCom); |
| 206 | } |
| 207 | db_finalize(&q); |
| 208 | }else{ |
| 209 | usage("?OPTIONS? ?VERSION?"); |
| 210 | } |
| 211 | |
| 212 | if( zPivot ){ |
| 213 | pid = name_to_typed_rid(zPivot, "ci"); |
| 214 | if( pid==0 || !is_a_version(pid) ){ |
| 215 | fossil_fatal("not a version: %s", zPivot); |
| 216 | } |
| @@ -347,11 +409,11 @@ | |
| 409 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 410 | ); |
| 411 | while( db_step(&q)==SQLITE_ROW ){ |
| 412 | int idm = db_column_int(&q, 0); |
| 413 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 414 | fossil_warning("WARNING - no common ancestor: %s", zName); |
| 415 | free(zName); |
| 416 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 417 | } |
| 418 | db_finalize(&q); |
| 419 | |
| 420 |
+9
-9
| --- src/regexp.c | ||
| +++ src/regexp.c | ||
| @@ -32,11 +32,11 @@ | ||
| 32 | 32 | ** X$ X occurring at the end of the string |
| 33 | 33 | ** . Match any single character |
| 34 | 34 | ** \c Character c where c is one of \{}()[]|*+?. |
| 35 | 35 | ** \c C-language escapes for c in afnrtv. ex: \t or \n |
| 36 | 36 | ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX |
| 37 | -** \xXXX Where XXX is any number of hex digits, unicode value XXX | |
| 37 | +** \xXX Where XX is exactly 2 hex digits, unicode value XX | |
| 38 | 38 | ** [abc] Any single character from the set abc |
| 39 | 39 | ** [^abc] Any single character not in the set abc |
| 40 | 40 | ** [a-z] Any single character in the range a-z |
| 41 | 41 | ** [^a-z] Any single character not in the range a-z |
| 42 | 42 | ** \b Word boundary |
| @@ -381,22 +381,21 @@ | ||
| 381 | 381 | *pV = (*pV)*16 + (c & 0xff); |
| 382 | 382 | return 1; |
| 383 | 383 | } |
| 384 | 384 | |
| 385 | 385 | /* A backslash character has been seen, read the next character and |
| 386 | -** return its intepretation. | |
| 386 | +** return its interpretation. | |
| 387 | 387 | */ |
| 388 | 388 | static unsigned re_esc_char(ReCompiled *p){ |
| 389 | 389 | static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; |
| 390 | 390 | static const char zTrans[] = "\a\f\n\r\t\v"; |
| 391 | 391 | int i, v = 0; |
| 392 | 392 | char c; |
| 393 | 393 | if( p->sIn.i>=p->sIn.mx ) return 0; |
| 394 | 394 | c = p->sIn.z[p->sIn.i]; |
| 395 | - if( c=='u' && p->sIn.i+5<p->sIn.mx ){ | |
| 395 | + if( c=='u' && p->sIn.i+4<p->sIn.mx ){ | |
| 396 | 396 | const unsigned char *zIn = p->sIn.z + p->sIn.i; |
| 397 | - v = 0; | |
| 398 | 397 | if( re_hex(zIn[1],&v) |
| 399 | 398 | && re_hex(zIn[2],&v) |
| 400 | 399 | && re_hex(zIn[3],&v) |
| 401 | 400 | && re_hex(zIn[4],&v) |
| 402 | 401 | ){ |
| @@ -403,15 +402,16 @@ | ||
| 403 | 402 | p->sIn.i += 5; |
| 404 | 403 | return v; |
| 405 | 404 | } |
| 406 | 405 | } |
| 407 | 406 | if( c=='x' ){ |
| 408 | - v = 0; | |
| 409 | - for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){} | |
| 410 | - if( i>1 ){ | |
| 411 | - p->sIn.i += i; | |
| 412 | - return v; | |
| 407 | + const unsigned char *zIn = p->sIn.z + p->sIn.i; | |
| 408 | + if( p->sIn.i+2<p->sIn.mx ){ | |
| 409 | + if( re_hex(zIn[1],&v) && re_hex(zIn[2],&v) ){ | |
| 410 | + p->sIn.i += 3; | |
| 411 | + return v; | |
| 412 | + } | |
| 413 | 413 | } |
| 414 | 414 | } |
| 415 | 415 | for(i=0; zEsc[i] && zEsc[i]!=c; i++){} |
| 416 | 416 | if( zEsc[i] ){ |
| 417 | 417 | if( i<6 ) c = zTrans[i]; |
| 418 | 418 |
| --- src/regexp.c | |
| +++ src/regexp.c | |
| @@ -32,11 +32,11 @@ | |
| 32 | ** X$ X occurring at the end of the string |
| 33 | ** . Match any single character |
| 34 | ** \c Character c where c is one of \{}()[]|*+?. |
| 35 | ** \c C-language escapes for c in afnrtv. ex: \t or \n |
| 36 | ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX |
| 37 | ** \xXXX Where XXX is any number of hex digits, unicode value XXX |
| 38 | ** [abc] Any single character from the set abc |
| 39 | ** [^abc] Any single character not in the set abc |
| 40 | ** [a-z] Any single character in the range a-z |
| 41 | ** [^a-z] Any single character not in the range a-z |
| 42 | ** \b Word boundary |
| @@ -381,22 +381,21 @@ | |
| 381 | *pV = (*pV)*16 + (c & 0xff); |
| 382 | return 1; |
| 383 | } |
| 384 | |
| 385 | /* A backslash character has been seen, read the next character and |
| 386 | ** return its intepretation. |
| 387 | */ |
| 388 | static unsigned re_esc_char(ReCompiled *p){ |
| 389 | static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; |
| 390 | static const char zTrans[] = "\a\f\n\r\t\v"; |
| 391 | int i, v = 0; |
| 392 | char c; |
| 393 | if( p->sIn.i>=p->sIn.mx ) return 0; |
| 394 | c = p->sIn.z[p->sIn.i]; |
| 395 | if( c=='u' && p->sIn.i+5<p->sIn.mx ){ |
| 396 | const unsigned char *zIn = p->sIn.z + p->sIn.i; |
| 397 | v = 0; |
| 398 | if( re_hex(zIn[1],&v) |
| 399 | && re_hex(zIn[2],&v) |
| 400 | && re_hex(zIn[3],&v) |
| 401 | && re_hex(zIn[4],&v) |
| 402 | ){ |
| @@ -403,15 +402,16 @@ | |
| 403 | p->sIn.i += 5; |
| 404 | return v; |
| 405 | } |
| 406 | } |
| 407 | if( c=='x' ){ |
| 408 | v = 0; |
| 409 | for(i=1; p->sIn.i<p->sIn.mx && re_hex(p->sIn.z[p->sIn.i+i], &v); i++){} |
| 410 | if( i>1 ){ |
| 411 | p->sIn.i += i; |
| 412 | return v; |
| 413 | } |
| 414 | } |
| 415 | for(i=0; zEsc[i] && zEsc[i]!=c; i++){} |
| 416 | if( zEsc[i] ){ |
| 417 | if( i<6 ) c = zTrans[i]; |
| 418 |
| --- src/regexp.c | |
| +++ src/regexp.c | |
| @@ -32,11 +32,11 @@ | |
| 32 | ** X$ X occurring at the end of the string |
| 33 | ** . Match any single character |
| 34 | ** \c Character c where c is one of \{}()[]|*+?. |
| 35 | ** \c C-language escapes for c in afnrtv. ex: \t or \n |
| 36 | ** \uXXXX Where XXXX is exactly 4 hex digits, unicode value XXXX |
| 37 | ** \xXX Where XX is exactly 2 hex digits, unicode value XX |
| 38 | ** [abc] Any single character from the set abc |
| 39 | ** [^abc] Any single character not in the set abc |
| 40 | ** [a-z] Any single character in the range a-z |
| 41 | ** [^a-z] Any single character not in the range a-z |
| 42 | ** \b Word boundary |
| @@ -381,22 +381,21 @@ | |
| 381 | *pV = (*pV)*16 + (c & 0xff); |
| 382 | return 1; |
| 383 | } |
| 384 | |
| 385 | /* A backslash character has been seen, read the next character and |
| 386 | ** return its interpretation. |
| 387 | */ |
| 388 | static unsigned re_esc_char(ReCompiled *p){ |
| 389 | static const char zEsc[] = "afnrtv\\()*.+?[$^{|}]"; |
| 390 | static const char zTrans[] = "\a\f\n\r\t\v"; |
| 391 | int i, v = 0; |
| 392 | char c; |
| 393 | if( p->sIn.i>=p->sIn.mx ) return 0; |
| 394 | c = p->sIn.z[p->sIn.i]; |
| 395 | if( c=='u' && p->sIn.i+4<p->sIn.mx ){ |
| 396 | const unsigned char *zIn = p->sIn.z + p->sIn.i; |
| 397 | if( re_hex(zIn[1],&v) |
| 398 | && re_hex(zIn[2],&v) |
| 399 | && re_hex(zIn[3],&v) |
| 400 | && re_hex(zIn[4],&v) |
| 401 | ){ |
| @@ -403,15 +402,16 @@ | |
| 402 | p->sIn.i += 5; |
| 403 | return v; |
| 404 | } |
| 405 | } |
| 406 | if( c=='x' ){ |
| 407 | const unsigned char *zIn = p->sIn.z + p->sIn.i; |
| 408 | if( p->sIn.i+2<p->sIn.mx ){ |
| 409 | if( re_hex(zIn[1],&v) && re_hex(zIn[2],&v) ){ |
| 410 | p->sIn.i += 3; |
| 411 | return v; |
| 412 | } |
| 413 | } |
| 414 | } |
| 415 | for(i=0; zEsc[i] && zEsc[i]!=c; i++){} |
| 416 | if( zEsc[i] ){ |
| 417 | if( i<6 ) c = zTrans[i]; |
| 418 |
+2
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -385,10 +385,11 @@ | ||
| 385 | 385 | @ CREATE TABLE ticket( |
| 386 | 386 | @ -- Do not change any column that begins with tkt_ |
| 387 | 387 | @ tkt_id INTEGER PRIMARY KEY, |
| 388 | 388 | @ tkt_uuid TEXT UNIQUE, |
| 389 | 389 | @ tkt_mtime DATE, |
| 390 | +@ tkt_ctime DATE, | |
| 390 | 391 | @ -- Add as many field as required below this line |
| 391 | 392 | @ type TEXT, |
| 392 | 393 | @ status TEXT, |
| 393 | 394 | @ subsystem TEXT, |
| 394 | 395 | @ priority TEXT, |
| @@ -400,10 +401,11 @@ | ||
| 400 | 401 | @ comment TEXT |
| 401 | 402 | @ ); |
| 402 | 403 | @ CREATE TABLE ticketchng( |
| 403 | 404 | @ -- Do not change any column that begins with tkt_ |
| 404 | 405 | @ tkt_id INTEGER REFERENCES ticket, |
| 406 | +@ tkt_rid INTEGER REFERENCES blob, | |
| 405 | 407 | @ tkt_mtime DATE, |
| 406 | 408 | @ -- Add as many fields as required below this line |
| 407 | 409 | @ login TEXT, |
| 408 | 410 | @ username TEXT, |
| 409 | 411 | @ mimetype TEXT, |
| 410 | 412 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -385,10 +385,11 @@ | |
| 385 | @ CREATE TABLE ticket( |
| 386 | @ -- Do not change any column that begins with tkt_ |
| 387 | @ tkt_id INTEGER PRIMARY KEY, |
| 388 | @ tkt_uuid TEXT UNIQUE, |
| 389 | @ tkt_mtime DATE, |
| 390 | @ -- Add as many field as required below this line |
| 391 | @ type TEXT, |
| 392 | @ status TEXT, |
| 393 | @ subsystem TEXT, |
| 394 | @ priority TEXT, |
| @@ -400,10 +401,11 @@ | |
| 400 | @ comment TEXT |
| 401 | @ ); |
| 402 | @ CREATE TABLE ticketchng( |
| 403 | @ -- Do not change any column that begins with tkt_ |
| 404 | @ tkt_id INTEGER REFERENCES ticket, |
| 405 | @ tkt_mtime DATE, |
| 406 | @ -- Add as many fields as required below this line |
| 407 | @ login TEXT, |
| 408 | @ username TEXT, |
| 409 | @ mimetype TEXT, |
| 410 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -385,10 +385,11 @@ | |
| 385 | @ CREATE TABLE ticket( |
| 386 | @ -- Do not change any column that begins with tkt_ |
| 387 | @ tkt_id INTEGER PRIMARY KEY, |
| 388 | @ tkt_uuid TEXT UNIQUE, |
| 389 | @ tkt_mtime DATE, |
| 390 | @ tkt_ctime DATE, |
| 391 | @ -- Add as many field as required below this line |
| 392 | @ type TEXT, |
| 393 | @ status TEXT, |
| 394 | @ subsystem TEXT, |
| 395 | @ priority TEXT, |
| @@ -400,10 +401,11 @@ | |
| 401 | @ comment TEXT |
| 402 | @ ); |
| 403 | @ CREATE TABLE ticketchng( |
| 404 | @ -- Do not change any column that begins with tkt_ |
| 405 | @ tkt_id INTEGER REFERENCES ticket, |
| 406 | @ tkt_rid INTEGER REFERENCES blob, |
| 407 | @ tkt_mtime DATE, |
| 408 | @ -- Add as many fields as required below this line |
| 409 | @ login TEXT, |
| 410 | @ username TEXT, |
| 411 | @ mimetype TEXT, |
| 412 |
+104
| --- src/stat.c | ||
| +++ src/stat.c | ||
| @@ -137,10 +137,114 @@ | ||
| 137 | 137 | @ </td></tr> |
| 138 | 138 | |
| 139 | 139 | @ </table> |
| 140 | 140 | style_footer(); |
| 141 | 141 | } |
| 142 | + | |
| 143 | +/* | |
| 144 | +** COMMAND: dbstat | |
| 145 | +** | |
| 146 | +** Show statistics and global information about the repository. | |
| 147 | +*/ | |
| 148 | +void dbstat_cmd(void){ | |
| 149 | + i64 t, fsize; | |
| 150 | + int n, m; | |
| 151 | + int szMax, szAvg; | |
| 152 | + const char *zDb; | |
| 153 | + int brief; | |
| 154 | + char zBuf[100]; | |
| 155 | + const int colWidth = -20 /* printf alignment/width for left column */; | |
| 156 | + brief = find_option("brief", "b",0)!=0; | |
| 157 | + db_find_and_open_repository(0,0); | |
| 158 | + fsize = file_size(g.zRepositoryName); | |
| 159 | + bigSizeName(sizeof(zBuf), zBuf, fsize); | |
| 160 | + fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf ); | |
| 161 | + if( !brief ){ | |
| 162 | + n = db_int(0, "SELECT count(*) FROM blob"); | |
| 163 | + m = db_int(0, "SELECT count(*) FROM delta"); | |
| 164 | + fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n", | |
| 165 | + colWidth, "artifact-count:", | |
| 166 | + n, n-m, m); | |
| 167 | + if( n>0 ){ | |
| 168 | + int a, b; | |
| 169 | + Stmt q; | |
| 170 | + db_prepare(&q, "SELECT total(size), avg(size), max(size)" | |
| 171 | + " FROM blob WHERE size>0"); | |
| 172 | + db_step(&q); | |
| 173 | + t = db_column_int64(&q, 0); | |
| 174 | + szAvg = db_column_int(&q, 1); | |
| 175 | + szMax = db_column_int(&q, 2); | |
| 176 | + db_finalize(&q); | |
| 177 | + bigSizeName(sizeof(zBuf), zBuf, t); | |
| 178 | + fossil_print( "%*s%d bytes average, " | |
| 179 | + "%d bytes max, %s total\n", | |
| 180 | + colWidth, "artifact-sizes:", | |
| 181 | + szAvg, szMax, zBuf); | |
| 182 | + if( t/fsize < 5 ){ | |
| 183 | + b = 10; | |
| 184 | + fsize /= 10; | |
| 185 | + }else{ | |
| 186 | + b = 1; | |
| 187 | + } | |
| 188 | + a = t/fsize; | |
| 189 | + fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b); | |
| 190 | + } | |
| 191 | + n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'"); | |
| 192 | + fossil_print("%*s%d\n", colWidth, "checkin-count:", n); | |
| 193 | + n = db_int(0, "SELECT count(*) FROM filename /*scan*/"); | |
| 194 | + /* FIXME/TODO: add the change-count-per-type to each event type, | |
| 195 | + ** plus add 'Event' count | |
| 196 | + */ | |
| 197 | +#if 0 | |
| 198 | + m = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/"); | |
| 199 | +#endif | |
| 200 | + fossil_print("%*s%d"/* (%d changes) */"\n", colWidth, "file-count:", | |
| 201 | + n/*, m */); | |
| 202 | + n = db_int(0, "SELECT count(*) FROM tag /*scan*/" | |
| 203 | + " WHERE tagname GLOB 'wiki-*'"); | |
| 204 | +#if 0 | |
| 205 | + m = db_int(0, "SELECT COUNT(*) FROM blob b JOIN event e WHERE " | |
| 206 | + "b.rid=e.objid AND e.type='w'"); | |
| 207 | +#endif | |
| 208 | + fossil_print("%*s%d"/* (%d changes) */"\n", colWidth, "wikipage-count:", | |
| 209 | + n/*, m */); | |
| 210 | + n = db_int(0, "SELECT count(*) FROM tag /*scan*/" | |
| 211 | + " WHERE tagname GLOB 'tkt-*'"); | |
| 212 | +#if 0 | |
| 213 | + m = db_int(0, "SELECT COUNT(*) FROM blob b JOIN event e WHERE " | |
| 214 | + "b.rid=e.objid AND e.type='t'"); | |
| 215 | +#endif | |
| 216 | + fossil_print("%*s%d"/* (%d changes)*/"\n", colWidth, "ticket-count:", | |
| 217 | + n/* , m */); | |
| 218 | + } | |
| 219 | + n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" | |
| 220 | + " + 0.99"); | |
| 221 | + fossil_print("%*s%d days or approximately %.2f years.\n", | |
| 222 | + colWidth, "project-age:", n, n/365.24); | |
| 223 | + fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code","")); | |
| 224 | + fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code","")); | |
| 225 | + fossil_print("%*s%s %s %s (%s)\n", | |
| 226 | + colWidth, "fossil-version:", | |
| 227 | + RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION, | |
| 228 | + COMPILER_NAME); | |
| 229 | + fossil_print("%*s%.19s [%.10s] (%s)\n", | |
| 230 | + colWidth, "sqlite-version:", | |
| 231 | + SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20], | |
| 232 | + SQLITE_VERSION); | |
| 233 | + zDb = db_name("repository"); | |
| 234 | + fossil_print("%*s%d pages, %d bytes/page, %d free pages, " | |
| 235 | + "%s, %s mode\n", | |
| 236 | + colWidth, "database-stats:", | |
| 237 | + db_int(0, "PRAGMA %s.page_count", zDb), | |
| 238 | + db_int(0, "PRAGMA %s.page_size", zDb), | |
| 239 | + db_int(0, "PRAGMA %s.freelist_count", zDb), | |
| 240 | + db_text(0, "PRAGMA %s.encoding", zDb), | |
| 241 | + db_text(0, "PRAGMA %s.journal_mode", zDb)); | |
| 242 | + | |
| 243 | +} | |
| 244 | + | |
| 245 | + | |
| 142 | 246 | |
| 143 | 247 | /* |
| 144 | 248 | ** WEBPAGE: urllist |
| 145 | 249 | ** |
| 146 | 250 | ** Show ways in which this repository has been accessed |
| 147 | 251 |
| --- src/stat.c | |
| +++ src/stat.c | |
| @@ -137,10 +137,114 @@ | |
| 137 | @ </td></tr> |
| 138 | |
| 139 | @ </table> |
| 140 | style_footer(); |
| 141 | } |
| 142 | |
| 143 | /* |
| 144 | ** WEBPAGE: urllist |
| 145 | ** |
| 146 | ** Show ways in which this repository has been accessed |
| 147 |
| --- src/stat.c | |
| +++ src/stat.c | |
| @@ -137,10 +137,114 @@ | |
| 137 | @ </td></tr> |
| 138 | |
| 139 | @ </table> |
| 140 | style_footer(); |
| 141 | } |
| 142 | |
| 143 | /* |
| 144 | ** COMMAND: dbstat |
| 145 | ** |
| 146 | ** Show statistics and global information about the repository. |
| 147 | */ |
| 148 | void dbstat_cmd(void){ |
| 149 | i64 t, fsize; |
| 150 | int n, m; |
| 151 | int szMax, szAvg; |
| 152 | const char *zDb; |
| 153 | int brief; |
| 154 | char zBuf[100]; |
| 155 | const int colWidth = -20 /* printf alignment/width for left column */; |
| 156 | brief = find_option("brief", "b",0)!=0; |
| 157 | db_find_and_open_repository(0,0); |
| 158 | fsize = file_size(g.zRepositoryName); |
| 159 | bigSizeName(sizeof(zBuf), zBuf, fsize); |
| 160 | fossil_print( "%*s%s\n", colWidth, "repository-size:", zBuf ); |
| 161 | if( !brief ){ |
| 162 | n = db_int(0, "SELECT count(*) FROM blob"); |
| 163 | m = db_int(0, "SELECT count(*) FROM delta"); |
| 164 | fossil_print("%*s%d (stored as %d full text and %d delta blobs)\n", |
| 165 | colWidth, "artifact-count:", |
| 166 | n, n-m, m); |
| 167 | if( n>0 ){ |
| 168 | int a, b; |
| 169 | Stmt q; |
| 170 | db_prepare(&q, "SELECT total(size), avg(size), max(size)" |
| 171 | " FROM blob WHERE size>0"); |
| 172 | db_step(&q); |
| 173 | t = db_column_int64(&q, 0); |
| 174 | szAvg = db_column_int(&q, 1); |
| 175 | szMax = db_column_int(&q, 2); |
| 176 | db_finalize(&q); |
| 177 | bigSizeName(sizeof(zBuf), zBuf, t); |
| 178 | fossil_print( "%*s%d bytes average, " |
| 179 | "%d bytes max, %s total\n", |
| 180 | colWidth, "artifact-sizes:", |
| 181 | szAvg, szMax, zBuf); |
| 182 | if( t/fsize < 5 ){ |
| 183 | b = 10; |
| 184 | fsize /= 10; |
| 185 | }else{ |
| 186 | b = 1; |
| 187 | } |
| 188 | a = t/fsize; |
| 189 | fossil_print("%*s%d:%d\n", colWidth, "compression-ratio:", a, b); |
| 190 | } |
| 191 | n = db_int(0, "SELECT COUNT(*) FROM event e WHERE e.type='ci'"); |
| 192 | fossil_print("%*s%d\n", colWidth, "checkin-count:", n); |
| 193 | n = db_int(0, "SELECT count(*) FROM filename /*scan*/"); |
| 194 | /* FIXME/TODO: add the change-count-per-type to each event type, |
| 195 | ** plus add 'Event' count |
| 196 | */ |
| 197 | #if 0 |
| 198 | m = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/"); |
| 199 | #endif |
| 200 | fossil_print("%*s%d"/* (%d changes) */"\n", colWidth, "file-count:", |
| 201 | n/*, m */); |
| 202 | n = db_int(0, "SELECT count(*) FROM tag /*scan*/" |
| 203 | " WHERE tagname GLOB 'wiki-*'"); |
| 204 | #if 0 |
| 205 | m = db_int(0, "SELECT COUNT(*) FROM blob b JOIN event e WHERE " |
| 206 | "b.rid=e.objid AND e.type='w'"); |
| 207 | #endif |
| 208 | fossil_print("%*s%d"/* (%d changes) */"\n", colWidth, "wikipage-count:", |
| 209 | n/*, m */); |
| 210 | n = db_int(0, "SELECT count(*) FROM tag /*scan*/" |
| 211 | " WHERE tagname GLOB 'tkt-*'"); |
| 212 | #if 0 |
| 213 | m = db_int(0, "SELECT COUNT(*) FROM blob b JOIN event e WHERE " |
| 214 | "b.rid=e.objid AND e.type='t'"); |
| 215 | #endif |
| 216 | fossil_print("%*s%d"/* (%d changes)*/"\n", colWidth, "ticket-count:", |
| 217 | n/* , m */); |
| 218 | } |
| 219 | n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)" |
| 220 | " + 0.99"); |
| 221 | fossil_print("%*s%d days or approximately %.2f years.\n", |
| 222 | colWidth, "project-age:", n, n/365.24); |
| 223 | fossil_print("%*s%s\n", colWidth, "project-id:", db_get("project-code","")); |
| 224 | fossil_print("%*s%s\n", colWidth, "server-id:", db_get("server-code","")); |
| 225 | fossil_print("%*s%s %s %s (%s)\n", |
| 226 | colWidth, "fossil-version:", |
| 227 | RELEASE_VERSION, MANIFEST_DATE, MANIFEST_VERSION, |
| 228 | COMPILER_NAME); |
| 229 | fossil_print("%*s%.19s [%.10s] (%s)\n", |
| 230 | colWidth, "sqlite-version:", |
| 231 | SQLITE_SOURCE_ID, &SQLITE_SOURCE_ID[20], |
| 232 | SQLITE_VERSION); |
| 233 | zDb = db_name("repository"); |
| 234 | fossil_print("%*s%d pages, %d bytes/page, %d free pages, " |
| 235 | "%s, %s mode\n", |
| 236 | colWidth, "database-stats:", |
| 237 | db_int(0, "PRAGMA %s.page_count", zDb), |
| 238 | db_int(0, "PRAGMA %s.page_size", zDb), |
| 239 | db_int(0, "PRAGMA %s.freelist_count", zDb), |
| 240 | db_text(0, "PRAGMA %s.encoding", zDb), |
| 241 | db_text(0, "PRAGMA %s.journal_mode", zDb)); |
| 242 | |
| 243 | } |
| 244 | |
| 245 | |
| 246 | |
| 247 | /* |
| 248 | ** WEBPAGE: urllist |
| 249 | ** |
| 250 | ** Show ways in which this repository has been accessed |
| 251 |
+11
-3
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1392,10 +1392,12 @@ | ||
| 1392 | 1392 | ** 1. uuid |
| 1393 | 1393 | ** 2. Date/Time |
| 1394 | 1394 | ** 3. Comment string and user |
| 1395 | 1395 | ** 4. Number of non-merge children |
| 1396 | 1396 | ** 5. Number of parents |
| 1397 | +** 6. mtime | |
| 1398 | +** 7. branch | |
| 1397 | 1399 | */ |
| 1398 | 1400 | void print_timeline(Stmt *q, int mxLine, int showfiles){ |
| 1399 | 1401 | int nLine = 0; |
| 1400 | 1402 | char zPrevDate[20]; |
| 1401 | 1403 | const char *zCurrentUuid=0; |
| @@ -1500,15 +1502,21 @@ | ||
| 1500 | 1502 | @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x |
| 1501 | 1503 | @ FROM tag, tagxref |
| 1502 | 1504 | @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid |
| 1503 | 1505 | @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) |
| 1504 | 1506 | @ || ')' as comment, |
| 1505 | - @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount, | |
| 1507 | + @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) | |
| 1508 | + @ AS primPlinkCount, | |
| 1506 | 1509 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, |
| 1507 | - @ event.mtime AS mtime | |
| 1508 | - @ FROM event, blob | |
| 1510 | + @ event.mtime AS mtime, | |
| 1511 | + @ tagxref.value AS branch | |
| 1512 | + @ FROM tag CROSS JOIN event CROSS JOIN blob CROSS JOIN tagxref | |
| 1509 | 1513 | @ WHERE blob.rid=event.objid |
| 1514 | + @ AND tag.tagname='branch' | |
| 1515 | + @ AND tagxref.tagid=tag.tagid | |
| 1516 | + @ AND tagxref.tagtype>0 | |
| 1517 | + @ AND tagxref.rid=blob.rid | |
| 1510 | 1518 | ; |
| 1511 | 1519 | return zBaseSql; |
| 1512 | 1520 | } |
| 1513 | 1521 | |
| 1514 | 1522 | /* |
| 1515 | 1523 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1392,10 +1392,12 @@ | |
| 1392 | ** 1. uuid |
| 1393 | ** 2. Date/Time |
| 1394 | ** 3. Comment string and user |
| 1395 | ** 4. Number of non-merge children |
| 1396 | ** 5. Number of parents |
| 1397 | */ |
| 1398 | void print_timeline(Stmt *q, int mxLine, int showfiles){ |
| 1399 | int nLine = 0; |
| 1400 | char zPrevDate[20]; |
| 1401 | const char *zCurrentUuid=0; |
| @@ -1500,15 +1502,21 @@ | |
| 1500 | @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x |
| 1501 | @ FROM tag, tagxref |
| 1502 | @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid |
| 1503 | @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) |
| 1504 | @ || ')' as comment, |
| 1505 | @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) AS primPlinkCount, |
| 1506 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, |
| 1507 | @ event.mtime AS mtime |
| 1508 | @ FROM event, blob |
| 1509 | @ WHERE blob.rid=event.objid |
| 1510 | ; |
| 1511 | return zBaseSql; |
| 1512 | } |
| 1513 | |
| 1514 | /* |
| 1515 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1392,10 +1392,12 @@ | |
| 1392 | ** 1. uuid |
| 1393 | ** 2. Date/Time |
| 1394 | ** 3. Comment string and user |
| 1395 | ** 4. Number of non-merge children |
| 1396 | ** 5. Number of parents |
| 1397 | ** 6. mtime |
| 1398 | ** 7. branch |
| 1399 | */ |
| 1400 | void print_timeline(Stmt *q, int mxLine, int showfiles){ |
| 1401 | int nLine = 0; |
| 1402 | char zPrevDate[20]; |
| 1403 | const char *zCurrentUuid=0; |
| @@ -1500,15 +1502,21 @@ | |
| 1502 | @ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x |
| 1503 | @ FROM tag, tagxref |
| 1504 | @ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid |
| 1505 | @ AND tagxref.rid=blob.rid AND tagxref.tagtype>0)) |
| 1506 | @ || ')' as comment, |
| 1507 | @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim) |
| 1508 | @ AS primPlinkCount, |
| 1509 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, |
| 1510 | @ event.mtime AS mtime, |
| 1511 | @ tagxref.value AS branch |
| 1512 | @ FROM tag CROSS JOIN event CROSS JOIN blob CROSS JOIN tagxref |
| 1513 | @ WHERE blob.rid=event.objid |
| 1514 | @ AND tag.tagname='branch' |
| 1515 | @ AND tagxref.tagid=tag.tagid |
| 1516 | @ AND tagxref.tagtype>0 |
| 1517 | @ AND tagxref.rid=blob.rid |
| 1518 | ; |
| 1519 | return zBaseSql; |
| 1520 | } |
| 1521 | |
| 1522 | /* |
| 1523 |
+73
-16
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -34,12 +34,15 @@ | ||
| 34 | 34 | char *zAppend; /* Value to append */ |
| 35 | 35 | unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */ |
| 36 | 36 | } *aField; |
| 37 | 37 | #define USEDBY_TICKET 01 |
| 38 | 38 | #define USEDBY_TICKETCHNG 02 |
| 39 | -static int haveTicket = 0; /* True if the TICKET table exists */ | |
| 40 | -static int haveTicketChng = 0; /* True if the TICKETCHNG table exists */ | |
| 39 | +#define USEDBY_BOTH 03 | |
| 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 */ | |
| 41 | 44 | |
| 42 | 45 | /* |
| 43 | 46 | ** Compare two entries in aField[] for sorting purposes |
| 44 | 47 | */ |
| 45 | 48 | static int nameCmpr(const void *a, const void *b){ |
| @@ -74,11 +77,14 @@ | ||
| 74 | 77 | once = 1; |
| 75 | 78 | db_prepare(&q, "PRAGMA table_info(ticket)"); |
| 76 | 79 | while( db_step(&q)==SQLITE_ROW ){ |
| 77 | 80 | const char *zFieldName = db_column_text(&q, 1); |
| 78 | 81 | haveTicket = 1; |
| 79 | - if( memcmp(zFieldName,"tkt_",4)==0 ) continue; | |
| 82 | + if( memcmp(zFieldName,"tkt_",4)==0 ){ | |
| 83 | + if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1; | |
| 84 | + continue; | |
| 85 | + } | |
| 80 | 86 | if( nField%10==0 ){ |
| 81 | 87 | aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) ); |
| 82 | 88 | } |
| 83 | 89 | aField[nField].zName = mprintf("%s", zFieldName); |
| 84 | 90 | aField[nField].mUsed = USEDBY_TICKET; |
| @@ -87,11 +93,14 @@ | ||
| 87 | 93 | db_finalize(&q); |
| 88 | 94 | db_prepare(&q, "PRAGMA table_info(ticketchng)"); |
| 89 | 95 | while( db_step(&q)==SQLITE_ROW ){ |
| 90 | 96 | const char *zFieldName = db_column_text(&q, 1); |
| 91 | 97 | haveTicketChng = 1; |
| 92 | - if( memcmp(zFieldName,"tkt_",4)==0 ) continue; | |
| 98 | + if( memcmp(zFieldName,"tkt_",4)==0 ){ | |
| 99 | + if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1; | |
| 100 | + continue; | |
| 101 | + } | |
| 93 | 102 | if( (i = fieldId(zFieldName))>=0 ){ |
| 94 | 103 | aField[i].mUsed |= USEDBY_TICKETCHNG; |
| 95 | 104 | continue; |
| 96 | 105 | } |
| 97 | 106 | if( nField%10==0 ){ |
| @@ -183,10 +192,11 @@ | ||
| 183 | 192 | */ |
| 184 | 193 | static int ticket_insert(const Manifest *p, int rid, int tktid){ |
| 185 | 194 | Blob sql1, sql2, sql3; |
| 186 | 195 | Stmt q; |
| 187 | 196 | int i, j; |
| 197 | + char *aUsed; | |
| 188 | 198 | |
| 189 | 199 | if( tktid==0 ){ |
| 190 | 200 | db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) " |
| 191 | 201 | "VALUES(%Q, 0)", p->zTicketUuid); |
| 192 | 202 | tktid = db_last_insert_rowid(); |
| @@ -193,22 +203,25 @@ | ||
| 193 | 203 | } |
| 194 | 204 | blob_zero(&sql1); |
| 195 | 205 | blob_zero(&sql2); |
| 196 | 206 | blob_zero(&sql3); |
| 197 | 207 | blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); |
| 208 | + if( haveTicketCTime ){ | |
| 209 | + blob_appendf(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)"); | |
| 210 | + } | |
| 211 | + aUsed = fossil_malloc( nField ); | |
| 212 | + memset(aUsed, 0, nField); | |
| 198 | 213 | for(i=0; i<p->nField; i++){ |
| 199 | 214 | const char *zName = p->aField[i].zName; |
| 200 | - if( zName[0]=='+' ){ | |
| 201 | - zName++; | |
| 202 | - if( (j = fieldId(zName))<0 ) continue; | |
| 203 | - if( aField[j].mUsed & USEDBY_TICKET ){ | |
| 215 | + if( (j = fieldId(zName))<0 ) continue; | |
| 216 | + aUsed[j] = 1; | |
| 217 | + if( aField[j].mUsed & USEDBY_TICKET ){ | |
| 218 | + if( zName[0]=='+' ){ | |
| 219 | + zName++; | |
| 204 | 220 | blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q", |
| 205 | 221 | zName, zName, p->aField[i].zValue); |
| 206 | - } | |
| 207 | - }else{ | |
| 208 | - if( (j = fieldId(zName))<0 ) continue; | |
| 209 | - if( aField[j].mUsed & USEDBY_TICKET ){ | |
| 222 | + }else{ | |
| 210 | 223 | blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue); |
| 211 | 224 | } |
| 212 | 225 | } |
| 213 | 226 | if( aField[j].mUsed & USEDBY_TICKETCHNG ){ |
| 214 | 227 | blob_appendf(&sql2, ",%s", zName); |
| @@ -222,20 +235,41 @@ | ||
| 222 | 235 | db_prepare(&q, "%s", blob_str(&sql1)); |
| 223 | 236 | db_bind_double(&q, ":mtime", p->rDate); |
| 224 | 237 | db_step(&q); |
| 225 | 238 | db_finalize(&q); |
| 226 | 239 | blob_reset(&sql1); |
| 227 | - if( blob_size(&sql2)>0 ){ | |
| 228 | - db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" | |
| 229 | - "VALUES(%d,:mtime%s)", | |
| 230 | - blob_str(&sql2), tktid, blob_str(&sql3)); | |
| 240 | + if( blob_size(&sql2)>0 || haveTicketChngRid ){ | |
| 241 | + int fromTkt = 0; | |
| 242 | + if( haveTicketChngRid ){ | |
| 243 | + blob_append(&sql2, ",tkt_rid", -1); | |
| 244 | + blob_appendf(&sql3, ",%d", rid); | |
| 245 | + } | |
| 246 | + for(i=0; i<nField; i++){ | |
| 247 | + if( aUsed[i]==0 | |
| 248 | + && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH | |
| 249 | + ){ | |
| 250 | + fromTkt = 1; | |
| 251 | + blob_appendf(&sql2, ",%s", aField[i].zName); | |
| 252 | + blob_appendf(&sql3, ",%s", aField[i].zName); | |
| 253 | + } | |
| 254 | + } | |
| 255 | + if( fromTkt ){ | |
| 256 | + db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" | |
| 257 | + "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d", | |
| 258 | + blob_str(&sql2), tktid, blob_str(&sql3), tktid); | |
| 259 | + }else{ | |
| 260 | + db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" | |
| 261 | + "VALUES(%d,:mtime%s)", | |
| 262 | + blob_str(&sql2), tktid, blob_str(&sql3)); | |
| 263 | + } | |
| 231 | 264 | db_bind_double(&q, ":mtime", p->rDate); |
| 232 | 265 | db_step(&q); |
| 233 | 266 | db_finalize(&q); |
| 234 | 267 | } |
| 235 | 268 | blob_reset(&sql2); |
| 236 | 269 | blob_reset(&sql3); |
| 270 | + fossil_free(aUsed); | |
| 237 | 271 | return tktid; |
| 238 | 272 | } |
| 239 | 273 | |
| 240 | 274 | /* |
| 241 | 275 | ** Rebuild an entire entry in the TICKET table |
| @@ -268,10 +302,11 @@ | ||
| 268 | 302 | } |
| 269 | 303 | createFlag = 0; |
| 270 | 304 | } |
| 271 | 305 | db_finalize(&q); |
| 272 | 306 | } |
| 307 | + | |
| 273 | 308 | |
| 274 | 309 | /* |
| 275 | 310 | ** Create the TH1 interpreter and load the "common" code. |
| 276 | 311 | */ |
| 277 | 312 | void ticket_init(void){ |
| @@ -328,10 +363,32 @@ | ||
| 328 | 363 | ticket_rebuild_entry(zName); |
| 329 | 364 | } |
| 330 | 365 | db_finalize(&q); |
| 331 | 366 | db_end_transaction(0); |
| 332 | 367 | } |
| 368 | + | |
| 369 | +/* | |
| 370 | +** COMMAND: test-ticket-rebuild | |
| 371 | +** | |
| 372 | +** Usage: %fossil test-ticket-rebuild TICKETID|all | |
| 373 | +** | |
| 374 | +** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID | |
| 375 | +** or for ALL. | |
| 376 | +*/ | |
| 377 | +void test_ticket_rebuild(void){ | |
| 378 | + db_find_and_open_repository(0, 0); | |
| 379 | + if( g.argc!=3 ) usage("TICKETID|all"); | |
| 380 | + if( fossil_strcmp(g.argv[2], "all")==0 ){ | |
| 381 | + ticket_rebuild(); | |
| 382 | + }else{ | |
| 383 | + const char *zUuid; | |
| 384 | + zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag" | |
| 385 | + " WHERE tagname GLOB 'tkt-%q*'", g.argv[2]); | |
| 386 | + if( zUuid==0 ) fossil_fatal("no such ticket: %s", g.argv[2]); | |
| 387 | + ticket_rebuild_entry(zUuid); | |
| 388 | + } | |
| 389 | +} | |
| 333 | 390 | |
| 334 | 391 | /* |
| 335 | 392 | ** For trouble-shooting purposes, render a dump of the aField[] table to |
| 336 | 393 | ** the webpage currently under construction. |
| 337 | 394 | */ |
| 338 | 395 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -34,12 +34,15 @@ | |
| 34 | char *zAppend; /* Value to append */ |
| 35 | unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */ |
| 36 | } *aField; |
| 37 | #define USEDBY_TICKET 01 |
| 38 | #define USEDBY_TICKETCHNG 02 |
| 39 | static int haveTicket = 0; /* True if the TICKET table exists */ |
| 40 | static int haveTicketChng = 0; /* True if the TICKETCHNG table exists */ |
| 41 | |
| 42 | /* |
| 43 | ** Compare two entries in aField[] for sorting purposes |
| 44 | */ |
| 45 | static int nameCmpr(const void *a, const void *b){ |
| @@ -74,11 +77,14 @@ | |
| 74 | once = 1; |
| 75 | db_prepare(&q, "PRAGMA table_info(ticket)"); |
| 76 | while( db_step(&q)==SQLITE_ROW ){ |
| 77 | const char *zFieldName = db_column_text(&q, 1); |
| 78 | haveTicket = 1; |
| 79 | if( memcmp(zFieldName,"tkt_",4)==0 ) continue; |
| 80 | if( nField%10==0 ){ |
| 81 | aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) ); |
| 82 | } |
| 83 | aField[nField].zName = mprintf("%s", zFieldName); |
| 84 | aField[nField].mUsed = USEDBY_TICKET; |
| @@ -87,11 +93,14 @@ | |
| 87 | db_finalize(&q); |
| 88 | db_prepare(&q, "PRAGMA table_info(ticketchng)"); |
| 89 | while( db_step(&q)==SQLITE_ROW ){ |
| 90 | const char *zFieldName = db_column_text(&q, 1); |
| 91 | haveTicketChng = 1; |
| 92 | if( memcmp(zFieldName,"tkt_",4)==0 ) continue; |
| 93 | if( (i = fieldId(zFieldName))>=0 ){ |
| 94 | aField[i].mUsed |= USEDBY_TICKETCHNG; |
| 95 | continue; |
| 96 | } |
| 97 | if( nField%10==0 ){ |
| @@ -183,10 +192,11 @@ | |
| 183 | */ |
| 184 | static int ticket_insert(const Manifest *p, int rid, int tktid){ |
| 185 | Blob sql1, sql2, sql3; |
| 186 | Stmt q; |
| 187 | int i, j; |
| 188 | |
| 189 | if( tktid==0 ){ |
| 190 | db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) " |
| 191 | "VALUES(%Q, 0)", p->zTicketUuid); |
| 192 | tktid = db_last_insert_rowid(); |
| @@ -193,22 +203,25 @@ | |
| 193 | } |
| 194 | blob_zero(&sql1); |
| 195 | blob_zero(&sql2); |
| 196 | blob_zero(&sql3); |
| 197 | blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); |
| 198 | for(i=0; i<p->nField; i++){ |
| 199 | const char *zName = p->aField[i].zName; |
| 200 | if( zName[0]=='+' ){ |
| 201 | zName++; |
| 202 | if( (j = fieldId(zName))<0 ) continue; |
| 203 | if( aField[j].mUsed & USEDBY_TICKET ){ |
| 204 | blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q", |
| 205 | zName, zName, p->aField[i].zValue); |
| 206 | } |
| 207 | }else{ |
| 208 | if( (j = fieldId(zName))<0 ) continue; |
| 209 | if( aField[j].mUsed & USEDBY_TICKET ){ |
| 210 | blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue); |
| 211 | } |
| 212 | } |
| 213 | if( aField[j].mUsed & USEDBY_TICKETCHNG ){ |
| 214 | blob_appendf(&sql2, ",%s", zName); |
| @@ -222,20 +235,41 @@ | |
| 222 | db_prepare(&q, "%s", blob_str(&sql1)); |
| 223 | db_bind_double(&q, ":mtime", p->rDate); |
| 224 | db_step(&q); |
| 225 | db_finalize(&q); |
| 226 | blob_reset(&sql1); |
| 227 | if( blob_size(&sql2)>0 ){ |
| 228 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 229 | "VALUES(%d,:mtime%s)", |
| 230 | blob_str(&sql2), tktid, blob_str(&sql3)); |
| 231 | db_bind_double(&q, ":mtime", p->rDate); |
| 232 | db_step(&q); |
| 233 | db_finalize(&q); |
| 234 | } |
| 235 | blob_reset(&sql2); |
| 236 | blob_reset(&sql3); |
| 237 | return tktid; |
| 238 | } |
| 239 | |
| 240 | /* |
| 241 | ** Rebuild an entire entry in the TICKET table |
| @@ -268,10 +302,11 @@ | |
| 268 | } |
| 269 | createFlag = 0; |
| 270 | } |
| 271 | db_finalize(&q); |
| 272 | } |
| 273 | |
| 274 | /* |
| 275 | ** Create the TH1 interpreter and load the "common" code. |
| 276 | */ |
| 277 | void ticket_init(void){ |
| @@ -328,10 +363,32 @@ | |
| 328 | ticket_rebuild_entry(zName); |
| 329 | } |
| 330 | db_finalize(&q); |
| 331 | db_end_transaction(0); |
| 332 | } |
| 333 | |
| 334 | /* |
| 335 | ** For trouble-shooting purposes, render a dump of the aField[] table to |
| 336 | ** the webpage currently under construction. |
| 337 | */ |
| 338 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -34,12 +34,15 @@ | |
| 34 | char *zAppend; /* Value to append */ |
| 35 | unsigned mUsed; /* 01: TICKET 02: TICKETCHNG */ |
| 36 | } *aField; |
| 37 | #define USEDBY_TICKET 01 |
| 38 | #define USEDBY_TICKETCHNG 02 |
| 39 | #define USEDBY_BOTH 03 |
| 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 | |
| 45 | /* |
| 46 | ** Compare two entries in aField[] for sorting purposes |
| 47 | */ |
| 48 | static int nameCmpr(const void *a, const void *b){ |
| @@ -74,11 +77,14 @@ | |
| 77 | once = 1; |
| 78 | db_prepare(&q, "PRAGMA table_info(ticket)"); |
| 79 | while( db_step(&q)==SQLITE_ROW ){ |
| 80 | const char *zFieldName = db_column_text(&q, 1); |
| 81 | haveTicket = 1; |
| 82 | if( memcmp(zFieldName,"tkt_",4)==0 ){ |
| 83 | if( strcmp(zFieldName, "tkt_ctime")==0 ) haveTicketCTime = 1; |
| 84 | continue; |
| 85 | } |
| 86 | if( nField%10==0 ){ |
| 87 | aField = fossil_realloc(aField, sizeof(aField[0])*(nField+10) ); |
| 88 | } |
| 89 | aField[nField].zName = mprintf("%s", zFieldName); |
| 90 | aField[nField].mUsed = USEDBY_TICKET; |
| @@ -87,11 +93,14 @@ | |
| 93 | db_finalize(&q); |
| 94 | db_prepare(&q, "PRAGMA table_info(ticketchng)"); |
| 95 | while( db_step(&q)==SQLITE_ROW ){ |
| 96 | const char *zFieldName = db_column_text(&q, 1); |
| 97 | haveTicketChng = 1; |
| 98 | if( memcmp(zFieldName,"tkt_",4)==0 ){ |
| 99 | if( strcmp(zFieldName,"tkt_rid")==0 ) haveTicketChngRid = 1; |
| 100 | continue; |
| 101 | } |
| 102 | if( (i = fieldId(zFieldName))>=0 ){ |
| 103 | aField[i].mUsed |= USEDBY_TICKETCHNG; |
| 104 | continue; |
| 105 | } |
| 106 | if( nField%10==0 ){ |
| @@ -183,10 +192,11 @@ | |
| 192 | */ |
| 193 | static int ticket_insert(const Manifest *p, int rid, int tktid){ |
| 194 | Blob sql1, sql2, sql3; |
| 195 | Stmt q; |
| 196 | int i, j; |
| 197 | char *aUsed; |
| 198 | |
| 199 | if( tktid==0 ){ |
| 200 | db_multi_exec("INSERT INTO ticket(tkt_uuid, tkt_mtime) " |
| 201 | "VALUES(%Q, 0)", p->zTicketUuid); |
| 202 | tktid = db_last_insert_rowid(); |
| @@ -193,22 +203,25 @@ | |
| 203 | } |
| 204 | blob_zero(&sql1); |
| 205 | blob_zero(&sql2); |
| 206 | blob_zero(&sql3); |
| 207 | blob_appendf(&sql1, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); |
| 208 | if( haveTicketCTime ){ |
| 209 | blob_appendf(&sql1, ", tkt_ctime=coalesce(tkt_ctime,:mtime)"); |
| 210 | } |
| 211 | aUsed = fossil_malloc( nField ); |
| 212 | memset(aUsed, 0, nField); |
| 213 | for(i=0; i<p->nField; i++){ |
| 214 | const char *zName = p->aField[i].zName; |
| 215 | if( (j = fieldId(zName))<0 ) continue; |
| 216 | aUsed[j] = 1; |
| 217 | if( aField[j].mUsed & USEDBY_TICKET ){ |
| 218 | if( zName[0]=='+' ){ |
| 219 | zName++; |
| 220 | blob_appendf(&sql1,", %s=coalesce(%s,'') || %Q", |
| 221 | zName, zName, p->aField[i].zValue); |
| 222 | }else{ |
| 223 | blob_appendf(&sql1,", %s=%Q", zName, p->aField[i].zValue); |
| 224 | } |
| 225 | } |
| 226 | if( aField[j].mUsed & USEDBY_TICKETCHNG ){ |
| 227 | blob_appendf(&sql2, ",%s", zName); |
| @@ -222,20 +235,41 @@ | |
| 235 | db_prepare(&q, "%s", blob_str(&sql1)); |
| 236 | db_bind_double(&q, ":mtime", p->rDate); |
| 237 | db_step(&q); |
| 238 | db_finalize(&q); |
| 239 | blob_reset(&sql1); |
| 240 | if( blob_size(&sql2)>0 || haveTicketChngRid ){ |
| 241 | int fromTkt = 0; |
| 242 | if( haveTicketChngRid ){ |
| 243 | blob_append(&sql2, ",tkt_rid", -1); |
| 244 | blob_appendf(&sql3, ",%d", rid); |
| 245 | } |
| 246 | for(i=0; i<nField; i++){ |
| 247 | if( aUsed[i]==0 |
| 248 | && (aField[i].mUsed & USEDBY_BOTH)==USEDBY_BOTH |
| 249 | ){ |
| 250 | fromTkt = 1; |
| 251 | blob_appendf(&sql2, ",%s", aField[i].zName); |
| 252 | blob_appendf(&sql3, ",%s", aField[i].zName); |
| 253 | } |
| 254 | } |
| 255 | if( fromTkt ){ |
| 256 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 257 | "SELECT %d,:mtime%s FROM ticket WHERE tkt_id=%d", |
| 258 | blob_str(&sql2), tktid, blob_str(&sql3), tktid); |
| 259 | }else{ |
| 260 | db_prepare(&q, "INSERT INTO ticketchng(tkt_id,tkt_mtime%s)" |
| 261 | "VALUES(%d,:mtime%s)", |
| 262 | blob_str(&sql2), tktid, blob_str(&sql3)); |
| 263 | } |
| 264 | db_bind_double(&q, ":mtime", p->rDate); |
| 265 | db_step(&q); |
| 266 | db_finalize(&q); |
| 267 | } |
| 268 | blob_reset(&sql2); |
| 269 | blob_reset(&sql3); |
| 270 | fossil_free(aUsed); |
| 271 | return tktid; |
| 272 | } |
| 273 | |
| 274 | /* |
| 275 | ** Rebuild an entire entry in the TICKET table |
| @@ -268,10 +302,11 @@ | |
| 302 | } |
| 303 | createFlag = 0; |
| 304 | } |
| 305 | db_finalize(&q); |
| 306 | } |
| 307 | |
| 308 | |
| 309 | /* |
| 310 | ** Create the TH1 interpreter and load the "common" code. |
| 311 | */ |
| 312 | void ticket_init(void){ |
| @@ -328,10 +363,32 @@ | |
| 363 | ticket_rebuild_entry(zName); |
| 364 | } |
| 365 | db_finalize(&q); |
| 366 | db_end_transaction(0); |
| 367 | } |
| 368 | |
| 369 | /* |
| 370 | ** COMMAND: test-ticket-rebuild |
| 371 | ** |
| 372 | ** Usage: %fossil test-ticket-rebuild TICKETID|all |
| 373 | ** |
| 374 | ** Rebuild the TICKET and TICKETCHNG tables for the given ticket ID |
| 375 | ** or for ALL. |
| 376 | */ |
| 377 | void test_ticket_rebuild(void){ |
| 378 | db_find_and_open_repository(0, 0); |
| 379 | if( g.argc!=3 ) usage("TICKETID|all"); |
| 380 | if( fossil_strcmp(g.argv[2], "all")==0 ){ |
| 381 | ticket_rebuild(); |
| 382 | }else{ |
| 383 | const char *zUuid; |
| 384 | zUuid = db_text(0, "SELECT substr(tagname,5) FROM tag" |
| 385 | " WHERE tagname GLOB 'tkt-%q*'", g.argv[2]); |
| 386 | if( zUuid==0 ) fossil_fatal("no such ticket: %s", g.argv[2]); |
| 387 | ticket_rebuild_entry(zUuid); |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | /* |
| 392 | ** For trouble-shooting purposes, render a dump of the aField[] table to |
| 393 | ** the webpage currently under construction. |
| 394 | */ |
| 395 |
+2
| --- src/tktsetup.c | ||
| +++ src/tktsetup.c | ||
| @@ -67,10 +67,11 @@ | ||
| 67 | 67 | @ CREATE TABLE ticket( |
| 68 | 68 | @ -- Do not change any column that begins with tkt_ |
| 69 | 69 | @ tkt_id INTEGER PRIMARY KEY, |
| 70 | 70 | @ tkt_uuid TEXT UNIQUE, |
| 71 | 71 | @ tkt_mtime DATE, |
| 72 | +@ tkt_ctime DATE, | |
| 72 | 73 | @ -- Add as many fields as required below this line |
| 73 | 74 | @ type TEXT, |
| 74 | 75 | @ status TEXT, |
| 75 | 76 | @ subsystem TEXT, |
| 76 | 77 | @ priority TEXT, |
| @@ -82,10 +83,11 @@ | ||
| 82 | 83 | @ comment TEXT |
| 83 | 84 | @ ); |
| 84 | 85 | @ CREATE TABLE ticketchng( |
| 85 | 86 | @ -- Do not change any column that begins with tkt_ |
| 86 | 87 | @ tkt_id INTEGER REFERENCES ticket, |
| 88 | +@ tkt_rid INTEGER REFERENCES blob, | |
| 87 | 89 | @ tkt_mtime DATE, |
| 88 | 90 | @ -- Add as many fields as required below this line |
| 89 | 91 | @ login TEXT, |
| 90 | 92 | @ username TEXT, |
| 91 | 93 | @ mimetype TEXT, |
| 92 | 94 |
| --- src/tktsetup.c | |
| +++ src/tktsetup.c | |
| @@ -67,10 +67,11 @@ | |
| 67 | @ CREATE TABLE ticket( |
| 68 | @ -- Do not change any column that begins with tkt_ |
| 69 | @ tkt_id INTEGER PRIMARY KEY, |
| 70 | @ tkt_uuid TEXT UNIQUE, |
| 71 | @ tkt_mtime DATE, |
| 72 | @ -- Add as many fields as required below this line |
| 73 | @ type TEXT, |
| 74 | @ status TEXT, |
| 75 | @ subsystem TEXT, |
| 76 | @ priority TEXT, |
| @@ -82,10 +83,11 @@ | |
| 82 | @ comment TEXT |
| 83 | @ ); |
| 84 | @ CREATE TABLE ticketchng( |
| 85 | @ -- Do not change any column that begins with tkt_ |
| 86 | @ tkt_id INTEGER REFERENCES ticket, |
| 87 | @ tkt_mtime DATE, |
| 88 | @ -- Add as many fields as required below this line |
| 89 | @ login TEXT, |
| 90 | @ username TEXT, |
| 91 | @ mimetype TEXT, |
| 92 |
| --- src/tktsetup.c | |
| +++ src/tktsetup.c | |
| @@ -67,10 +67,11 @@ | |
| 67 | @ CREATE TABLE ticket( |
| 68 | @ -- Do not change any column that begins with tkt_ |
| 69 | @ tkt_id INTEGER PRIMARY KEY, |
| 70 | @ tkt_uuid TEXT UNIQUE, |
| 71 | @ tkt_mtime DATE, |
| 72 | @ tkt_ctime DATE, |
| 73 | @ -- Add as many fields as required below this line |
| 74 | @ type TEXT, |
| 75 | @ status TEXT, |
| 76 | @ subsystem TEXT, |
| 77 | @ priority TEXT, |
| @@ -82,10 +83,11 @@ | |
| 83 | @ comment TEXT |
| 84 | @ ); |
| 85 | @ CREATE TABLE ticketchng( |
| 86 | @ -- Do not change any column that begins with tkt_ |
| 87 | @ tkt_id INTEGER REFERENCES ticket, |
| 88 | @ tkt_rid INTEGER REFERENCES blob, |
| 89 | @ tkt_mtime DATE, |
| 90 | @ -- Add as many fields as required below this line |
| 91 | @ login TEXT, |
| 92 | @ username TEXT, |
| 93 | @ mimetype TEXT, |
| 94 |