Fossil SCM
Attempt N at filtering /forum on the status tag. This still requires a separate query to get the status label for each entry and it's not yet proven to be performant enough for real use, but it essentially works. Bug: when browsing to page 2+ of a filtered list then changing the filter via the dropdown selection list, the x= param (starting offset) is retained but we need it to be removed.
Commit
45a8de423b9af62470f24e9cf035347dd736071a41c6bf6415040f38c1581db2
Parent
d01961c346476c5…
1 file changed
+68
-10
+68
-10
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -2470,32 +2470,90 @@ | ||
| 2470 | 2470 | if( zStatusFilter && |
| 2471 | 2471 | (!*zStatusFilter || 0==fossil_strcmp("*",zStatusFilter)) ){ |
| 2472 | 2472 | zStatusFilter = 0; |
| 2473 | 2473 | } |
| 2474 | 2474 | if( db_table_exists("repository","forumpost") ){ |
| 2475 | - Stmt qStat; | |
| 2475 | + const ForumStatusList * pFstat = forum_statuses(); | |
| 2476 | + const int iStatusTagId = bHasStatus | |
| 2477 | + ? db_int(0, "SELECT tagid FROM TAG WHERE tagname='status'") | |
| 2478 | + : 0; | |
| 2479 | + Stmt qStat = empty_Stmt; | |
| 2480 | + db_multi_exec( | |
| 2481 | + /* List of forumpost.fpid values which match current | |
| 2482 | + filters. */ | |
| 2483 | + "CREATE TEMP TABLE trootid(id INTEGER PRIMARY KEY);" | |
| 2484 | + ); | |
| 2476 | 2485 | if( bHasStatus ){ |
| 2477 | - db_prepare(&qStat, | |
| 2486 | + db_prepare( | |
| 2487 | + /* FIXME/TODO: it would be nice to be able to get this info | |
| 2488 | + ** directly into the thread query below, rather than | |
| 2489 | + ** requiring a separate statement and lookup inside the | |
| 2490 | + ** q loop. */ | |
| 2491 | + &qStat, | |
| 2478 | 2492 | "SELECT tagxref.value, forumstatus.label\n" |
| 2479 | 2493 | " FROM forumstatus, tagxref\n" |
| 2480 | 2494 | " WHERE tagid=%d AND tagtype>=1\n" |
| 2481 | 2495 | " AND forumstatus.value=tagxref.value\n" |
| 2482 | 2496 | " AND rid=:rid\n" |
| 2483 | 2497 | " AND if(%d=0,1,tagxref.value=%Q)\n" |
| 2484 | 2498 | " ORDER BY mtime DESC", |
| 2485 | - db_int(0,"SELECT tagid FROM tag WHERE tagname='status'"), | |
| 2486 | - !!zStatusFilter, zStatusFilter | |
| 2499 | + iStatusTagId, !!zStatusFilter, zStatusFilter | |
| 2500 | + ); | |
| 2501 | + if( zStatusFilter ){ | |
| 2502 | + const int bIsDflt = | |
| 2503 | + 0==fossil_strcmp(pFstat->aStatus[0].zValue, zStatusFilter); | |
| 2504 | + db_multi_exec( | |
| 2505 | + "INSERT INTO trootid\n" | |
| 2506 | + /* Rules: | |
| 2507 | + | |
| 2508 | + (1) Filter on status=$zStatusFilter | |
| 2509 | + (2) If $zStatusFilter==default status then also include | |
| 2510 | + any posts with no status tag. | |
| 2511 | + (3) If no matching tag is found, assume a tag with the value | |
| 2512 | + of the first (default) status. | |
| 2513 | + | |
| 2514 | + We need to ensure that we filter only the most recent | |
| 2515 | + value of each tag and count tagtype=0 (cancel) tags | |
| 2516 | + properly. | |
| 2517 | + */ | |
| 2518 | + " SELECT fpid FROM forumpost, event\n" | |
| 2519 | + " LEFT JOIN tagxref x ON objid=rid\n" | |
| 2520 | + " WHERE froot=fpid AND firt IS NULL\n" | |
| 2521 | + " AND (x.tagid IS NULL OR x.tagid=%d)\n" | |
| 2522 | + " AND fpid=objid AND type='f'\n" | |
| 2523 | + " AND CASE\n" | |
| 2524 | + " WHEN %d THEN (x.value IS NULL OR x.value=%Q)\n" /* (2,3) */ | |
| 2525 | + " ELSE x.value=%Q\n" /* (1) */ | |
| 2526 | + " END", | |
| 2527 | + iStatusTagId, bIsDflt, zStatusFilter, zStatusFilter | |
| 2528 | + ); | |
| 2529 | + (void)bIsDflt; | |
| 2530 | + }else{ | |
| 2531 | + db_multi_exec( | |
| 2532 | + "INSERT INTO trootid\n" | |
| 2533 | + " SELECT fpid FROM forumpost, event\n" | |
| 2534 | + " WHERE froot=fpid AND firt IS NULL\n" | |
| 2535 | + " AND fpid=objid AND type='f'" | |
| 2536 | + ); | |
| 2537 | + } | |
| 2538 | + }else{ | |
| 2539 | + db_multi_exec( | |
| 2540 | + "INSERT INTO trootid\n" | |
| 2541 | + " SELECT fpid FROM forumpost, event\n" | |
| 2542 | + " WHERE froot=fpid AND firt IS NULL\n" | |
| 2543 | + " AND fpid=objid AND type='f'" | |
| 2487 | 2544 | ); |
| 2488 | 2545 | } |
| 2489 | 2546 | db_prepare(&q, |
| 2490 | 2547 | "WITH thread(root,endtime,lastrid) AS (\n" |
| 2491 | 2548 | " SELECT\n" |
| 2492 | 2549 | " froot,\n" |
| 2493 | 2550 | " max(fmtime),\n" |
| 2494 | 2551 | " fpid\n" |
| 2495 | - " FROM forumpost\n" | |
| 2552 | + " FROM forumpost, trootid\n" | |
| 2496 | 2553 | " WHERE %s/*ModForum*/\n" |
| 2554 | + " AND froot=trootid.id\n" | |
| 2497 | 2555 | " GROUP BY froot\n" |
| 2498 | 2556 | " ORDER BY 2 DESC\n" |
| 2499 | 2557 | " LIMIT %d OFFSET %d\n" |
| 2500 | 2558 | ")\n" |
| 2501 | 2559 | "SELECT\n" |
| @@ -2523,19 +2581,19 @@ | ||
| 2523 | 2581 | const char *zStatus; |
| 2524 | 2582 | const char *zStatusLbl; |
| 2525 | 2583 | const int bShowStatus = bHasStatus && !zStatusFilter; |
| 2526 | 2584 | const int nCols = bShowStatus ? 4 : 3 |
| 2527 | 2585 | /* When filtering on status, elide the status column */; |
| 2528 | - if( bHasStatus ){ | |
| 2586 | + if( qStat.pStmt ){ | |
| 2529 | 2587 | db_reset(&qStat); |
| 2530 | 2588 | db_bind_int(&qStat, ":rid", db_column_int(&q,6)); |
| 2531 | 2589 | if( db_step(&qStat)==SQLITE_ROW ){ |
| 2532 | 2590 | zStatus = db_column_text(&qStat, 0); |
| 2533 | 2591 | zStatusLbl = db_column_text(&qStat, 1); |
| 2534 | 2592 | }else{ |
| 2535 | - zStatus = forum_statuses()->aStatus[0].zValue; | |
| 2536 | - zStatusLbl = forum_statuses()->aStatus[0].zLabel; | |
| 2593 | + zStatus = pFstat->aStatus[0].zValue; | |
| 2594 | + zStatusLbl = pFstat->aStatus[0].zLabel; | |
| 2537 | 2595 | } |
| 2538 | 2596 | if( zStatusFilter && 0!=fossil_strcmp(zStatusFilter,zStatus) ){ |
| 2539 | 2597 | continue; |
| 2540 | 2598 | } |
| 2541 | 2599 | }else{ |
| @@ -2605,21 +2663,21 @@ | ||
| 2605 | 2663 | } |
| 2606 | 2664 | @ </td>\ |
| 2607 | 2665 | if( bShowStatus ){ |
| 2608 | 2666 | @ <td class='status'>%h(zStatusLbl)</td>\ |
| 2609 | 2667 | } |
| 2610 | - if( bHasStatus ){ | |
| 2668 | + if( qStat.pStmt ){ | |
| 2611 | 2669 | db_reset(&qStat); |
| 2612 | 2670 | } |
| 2613 | 2671 | @</tr> |
| 2614 | 2672 | fossil_free(zAge); |
| 2615 | 2673 | } |
| 2616 | 2674 | db_finalize(&q); |
| 2617 | - if( bHasStatus ) db_finalize(&qStat); | |
| 2675 | + if( qStat.pStmt ) db_finalize(&qStat); | |
| 2618 | 2676 | } |
| 2619 | 2677 | if( iCnt>0 ){ |
| 2620 | 2678 | @ </table></div> |
| 2621 | 2679 | }else{ |
| 2622 | 2680 | @ <h1>No forum posts found</h1> |
| 2623 | 2681 | } |
| 2624 | 2682 | style_finish_page(); |
| 2625 | 2683 | } |
| 2626 | 2684 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -2470,32 +2470,90 @@ | |
| 2470 | if( zStatusFilter && |
| 2471 | (!*zStatusFilter || 0==fossil_strcmp("*",zStatusFilter)) ){ |
| 2472 | zStatusFilter = 0; |
| 2473 | } |
| 2474 | if( db_table_exists("repository","forumpost") ){ |
| 2475 | Stmt qStat; |
| 2476 | if( bHasStatus ){ |
| 2477 | db_prepare(&qStat, |
| 2478 | "SELECT tagxref.value, forumstatus.label\n" |
| 2479 | " FROM forumstatus, tagxref\n" |
| 2480 | " WHERE tagid=%d AND tagtype>=1\n" |
| 2481 | " AND forumstatus.value=tagxref.value\n" |
| 2482 | " AND rid=:rid\n" |
| 2483 | " AND if(%d=0,1,tagxref.value=%Q)\n" |
| 2484 | " ORDER BY mtime DESC", |
| 2485 | db_int(0,"SELECT tagid FROM tag WHERE tagname='status'"), |
| 2486 | !!zStatusFilter, zStatusFilter |
| 2487 | ); |
| 2488 | } |
| 2489 | db_prepare(&q, |
| 2490 | "WITH thread(root,endtime,lastrid) AS (\n" |
| 2491 | " SELECT\n" |
| 2492 | " froot,\n" |
| 2493 | " max(fmtime),\n" |
| 2494 | " fpid\n" |
| 2495 | " FROM forumpost\n" |
| 2496 | " WHERE %s/*ModForum*/\n" |
| 2497 | " GROUP BY froot\n" |
| 2498 | " ORDER BY 2 DESC\n" |
| 2499 | " LIMIT %d OFFSET %d\n" |
| 2500 | ")\n" |
| 2501 | "SELECT\n" |
| @@ -2523,19 +2581,19 @@ | |
| 2523 | const char *zStatus; |
| 2524 | const char *zStatusLbl; |
| 2525 | const int bShowStatus = bHasStatus && !zStatusFilter; |
| 2526 | const int nCols = bShowStatus ? 4 : 3 |
| 2527 | /* When filtering on status, elide the status column */; |
| 2528 | if( bHasStatus ){ |
| 2529 | db_reset(&qStat); |
| 2530 | db_bind_int(&qStat, ":rid", db_column_int(&q,6)); |
| 2531 | if( db_step(&qStat)==SQLITE_ROW ){ |
| 2532 | zStatus = db_column_text(&qStat, 0); |
| 2533 | zStatusLbl = db_column_text(&qStat, 1); |
| 2534 | }else{ |
| 2535 | zStatus = forum_statuses()->aStatus[0].zValue; |
| 2536 | zStatusLbl = forum_statuses()->aStatus[0].zLabel; |
| 2537 | } |
| 2538 | if( zStatusFilter && 0!=fossil_strcmp(zStatusFilter,zStatus) ){ |
| 2539 | continue; |
| 2540 | } |
| 2541 | }else{ |
| @@ -2605,21 +2663,21 @@ | |
| 2605 | } |
| 2606 | @ </td>\ |
| 2607 | if( bShowStatus ){ |
| 2608 | @ <td class='status'>%h(zStatusLbl)</td>\ |
| 2609 | } |
| 2610 | if( bHasStatus ){ |
| 2611 | db_reset(&qStat); |
| 2612 | } |
| 2613 | @</tr> |
| 2614 | fossil_free(zAge); |
| 2615 | } |
| 2616 | db_finalize(&q); |
| 2617 | if( bHasStatus ) db_finalize(&qStat); |
| 2618 | } |
| 2619 | if( iCnt>0 ){ |
| 2620 | @ </table></div> |
| 2621 | }else{ |
| 2622 | @ <h1>No forum posts found</h1> |
| 2623 | } |
| 2624 | style_finish_page(); |
| 2625 | } |
| 2626 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -2470,32 +2470,90 @@ | |
| 2470 | if( zStatusFilter && |
| 2471 | (!*zStatusFilter || 0==fossil_strcmp("*",zStatusFilter)) ){ |
| 2472 | zStatusFilter = 0; |
| 2473 | } |
| 2474 | if( db_table_exists("repository","forumpost") ){ |
| 2475 | const ForumStatusList * pFstat = forum_statuses(); |
| 2476 | const int iStatusTagId = bHasStatus |
| 2477 | ? db_int(0, "SELECT tagid FROM TAG WHERE tagname='status'") |
| 2478 | : 0; |
| 2479 | Stmt qStat = empty_Stmt; |
| 2480 | db_multi_exec( |
| 2481 | /* List of forumpost.fpid values which match current |
| 2482 | filters. */ |
| 2483 | "CREATE TEMP TABLE trootid(id INTEGER PRIMARY KEY);" |
| 2484 | ); |
| 2485 | if( bHasStatus ){ |
| 2486 | db_prepare( |
| 2487 | /* FIXME/TODO: it would be nice to be able to get this info |
| 2488 | ** directly into the thread query below, rather than |
| 2489 | ** requiring a separate statement and lookup inside the |
| 2490 | ** q loop. */ |
| 2491 | &qStat, |
| 2492 | "SELECT tagxref.value, forumstatus.label\n" |
| 2493 | " FROM forumstatus, tagxref\n" |
| 2494 | " WHERE tagid=%d AND tagtype>=1\n" |
| 2495 | " AND forumstatus.value=tagxref.value\n" |
| 2496 | " AND rid=:rid\n" |
| 2497 | " AND if(%d=0,1,tagxref.value=%Q)\n" |
| 2498 | " ORDER BY mtime DESC", |
| 2499 | iStatusTagId, !!zStatusFilter, zStatusFilter |
| 2500 | ); |
| 2501 | if( zStatusFilter ){ |
| 2502 | const int bIsDflt = |
| 2503 | 0==fossil_strcmp(pFstat->aStatus[0].zValue, zStatusFilter); |
| 2504 | db_multi_exec( |
| 2505 | "INSERT INTO trootid\n" |
| 2506 | /* Rules: |
| 2507 | |
| 2508 | (1) Filter on status=$zStatusFilter |
| 2509 | (2) If $zStatusFilter==default status then also include |
| 2510 | any posts with no status tag. |
| 2511 | (3) If no matching tag is found, assume a tag with the value |
| 2512 | of the first (default) status. |
| 2513 | |
| 2514 | We need to ensure that we filter only the most recent |
| 2515 | value of each tag and count tagtype=0 (cancel) tags |
| 2516 | properly. |
| 2517 | */ |
| 2518 | " SELECT fpid FROM forumpost, event\n" |
| 2519 | " LEFT JOIN tagxref x ON objid=rid\n" |
| 2520 | " WHERE froot=fpid AND firt IS NULL\n" |
| 2521 | " AND (x.tagid IS NULL OR x.tagid=%d)\n" |
| 2522 | " AND fpid=objid AND type='f'\n" |
| 2523 | " AND CASE\n" |
| 2524 | " WHEN %d THEN (x.value IS NULL OR x.value=%Q)\n" /* (2,3) */ |
| 2525 | " ELSE x.value=%Q\n" /* (1) */ |
| 2526 | " END", |
| 2527 | iStatusTagId, bIsDflt, zStatusFilter, zStatusFilter |
| 2528 | ); |
| 2529 | (void)bIsDflt; |
| 2530 | }else{ |
| 2531 | db_multi_exec( |
| 2532 | "INSERT INTO trootid\n" |
| 2533 | " SELECT fpid FROM forumpost, event\n" |
| 2534 | " WHERE froot=fpid AND firt IS NULL\n" |
| 2535 | " AND fpid=objid AND type='f'" |
| 2536 | ); |
| 2537 | } |
| 2538 | }else{ |
| 2539 | db_multi_exec( |
| 2540 | "INSERT INTO trootid\n" |
| 2541 | " SELECT fpid FROM forumpost, event\n" |
| 2542 | " WHERE froot=fpid AND firt IS NULL\n" |
| 2543 | " AND fpid=objid AND type='f'" |
| 2544 | ); |
| 2545 | } |
| 2546 | db_prepare(&q, |
| 2547 | "WITH thread(root,endtime,lastrid) AS (\n" |
| 2548 | " SELECT\n" |
| 2549 | " froot,\n" |
| 2550 | " max(fmtime),\n" |
| 2551 | " fpid\n" |
| 2552 | " FROM forumpost, trootid\n" |
| 2553 | " WHERE %s/*ModForum*/\n" |
| 2554 | " AND froot=trootid.id\n" |
| 2555 | " GROUP BY froot\n" |
| 2556 | " ORDER BY 2 DESC\n" |
| 2557 | " LIMIT %d OFFSET %d\n" |
| 2558 | ")\n" |
| 2559 | "SELECT\n" |
| @@ -2523,19 +2581,19 @@ | |
| 2581 | const char *zStatus; |
| 2582 | const char *zStatusLbl; |
| 2583 | const int bShowStatus = bHasStatus && !zStatusFilter; |
| 2584 | const int nCols = bShowStatus ? 4 : 3 |
| 2585 | /* When filtering on status, elide the status column */; |
| 2586 | if( qStat.pStmt ){ |
| 2587 | db_reset(&qStat); |
| 2588 | db_bind_int(&qStat, ":rid", db_column_int(&q,6)); |
| 2589 | if( db_step(&qStat)==SQLITE_ROW ){ |
| 2590 | zStatus = db_column_text(&qStat, 0); |
| 2591 | zStatusLbl = db_column_text(&qStat, 1); |
| 2592 | }else{ |
| 2593 | zStatus = pFstat->aStatus[0].zValue; |
| 2594 | zStatusLbl = pFstat->aStatus[0].zLabel; |
| 2595 | } |
| 2596 | if( zStatusFilter && 0!=fossil_strcmp(zStatusFilter,zStatus) ){ |
| 2597 | continue; |
| 2598 | } |
| 2599 | }else{ |
| @@ -2605,21 +2663,21 @@ | |
| 2663 | } |
| 2664 | @ </td>\ |
| 2665 | if( bShowStatus ){ |
| 2666 | @ <td class='status'>%h(zStatusLbl)</td>\ |
| 2667 | } |
| 2668 | if( qStat.pStmt ){ |
| 2669 | db_reset(&qStat); |
| 2670 | } |
| 2671 | @</tr> |
| 2672 | fossil_free(zAge); |
| 2673 | } |
| 2674 | db_finalize(&q); |
| 2675 | if( qStat.pStmt ) db_finalize(&qStat); |
| 2676 | } |
| 2677 | if( iCnt>0 ){ |
| 2678 | @ </table></div> |
| 2679 | }else{ |
| 2680 | @ <h1>No forum posts found</h1> |
| 2681 | } |
| 2682 | style_finish_page(); |
| 2683 | } |
| 2684 |