Bugfix Issue 1180 tcAssignments QuickResult DBError - sebiboga/testlink-upgraded GitHub Wiki
Issue: #1180
Branch: fix/issue-1180
Status: VERIFIED-FIXED (2026-09-07)
On the modernized screen gui/templates/execute/tcAssignments.html, clicking any of the
Quick result buttons (passed / failed / blocked) shows the error toast and
nothing is saved. The BFF answers HTTP 200 but the body is the DB Access Error
debug page, and a new Event Viewer row is logged:
ERROR ON exec_query() - database.class.php
1054 - Unknown column 'testplan_id' in 'WHERE' - SELECT id FROM builds
Measured on a fresh DB + fixture tmp/fixtures_660.php (project 1 LOC660, plan 16, build 1):
the POST created no executions row (count stayed 1).
- Create a project/plan with an execution assignment on an open build
(fixture
tmp/fixtures_660.php; row L660-1 / BUILD-OPEN). - Log in as admin; open
gui/templates/execute/tcAssignments.html?tproject_id=1. - Click the green check (quick passed) on any row with a build assigned.
- Toast "Error", Event Viewer logs
1054 Unknown column 'testplan_id',executionsunchanged.
Expected: a new execution row with the chosen status (legacy quick & dirty exec works).
Actual (pre-fix): POST /api/tcassignments/quick_result → HTTP 200, body = DB Access Error backtrace (database.class.php(780) exec_query ←
api/tcassignments/index.php(400) get_recordset); no INSERT.

- The front-end (
tcAssignments.html:372-416) posts every quick result toPOST /api/tcassignments/quick_resultwith{tproject_id, tplan_id, platform_id, build_id, tcversion_id, result}. - The BFF validates three things before inserting: the
testplan_tcversionslink, the build, and the tcversion. - The build check ran
SELECT id FROM builds WHERE id = {build_id} AND testplan_id = {tplan_id}(api/tcassignments/index.php:400-402). - Since #503/#834 the
buildstable is testproject-scoped — there is notestplan_idcolumn (verifiedDESCRIBE builds→testproject_id). A plan's builds resolve throughtestplan::get_builds()→getProjectIdOfPlan()→WHERE testproject_id = <project>(lib/functions/testplan.class.php:2274+). The unknown column aborts the request before the INSERT at line 421.
Why it breaks now: the quick-result route was written against the pre-#834 build/tplan
scoping. Sibling BFFs already account for project-scoped builds
(api/execsetresults/index.php:186, api/execute/index.php:529); the tcAssignments
build check was the last remaining straggler.
Blast radius: a single query in api/tcassignments/index.php. Grep over api/** and
gui/** shows no other active call site of builds.testplan_id. The legacy screen
lib/testcases/tcAssignedToUser.php:42-56 inserts the execution with no build
validation at all, so nothing else shares this path.
Validate the build against its real scope — the test project owning the already-validated plan↔tcversion↔platform link:
// build must belong to this test project (builds are project-scoped
// since #503/#834; a plan's builds resolve via builds.testproject_id).
// Also cross-bind the plan to the same project so a caller cannot
// write executions combining a build and a plan of different projects.
$bTables = tlObjectWithDB::getDBTables(['builds', 'testplans']);
$brow = $db->get_recordset(
"SELECT B.id FROM {$bTables['builds']} B" .
" JOIN {$bTables['testplans']} TP ON TP.id = {$tplan_id}" .
" WHERE B.id = {$build_id}" .
" AND B.testproject_id = {$tproject_id}" .
" AND TP.testproject_id = {$tproject_id}");
if (!$brow) {
http_response_code(400);
out(['status' => 'error',
'message' => 'Build does not belong to this test project']);
}Minimal change that keeps the BFF's input-validation intent: the tcversion↔plan↔platform
link is still verified via testplan_tcversions, and the plan is additionally
cross-bound to the caller's project (testplans JOIN), so the execution is always
written inside a single, consistent project. The alternative (reverting to legacy's
completely unchecked INSERT) was rejected — the modern BFF explicitly documents that it
validates every id (index.php quick_result comment).
-
api/tcassignments/index.php— lines ~398-408: build predicatetestplan_id = {tplan_id}→testproject_id = {tproject_id}; error message text aligned ('does not belong to this test project').
Regression suite 1180.1–1180.7 (7 cases, 7/7 PASS) executed against a fresh DB +
tmp/fixtures_660.php (plus a cross-project build BUILD-X id=30 under project 50 to
exercise the rejection):
| Case | Result |
|---|---|
PRIMARY — quick result succeeds; executions gains status='p' row (plan 16, build 1, tcversion 5, tester 1) |
PASS |
| P→F→P full click cycle in the browser (toast + reload + chip flip) | PASS |
| Cross-project build (build 30 on plan of project 1) rejected — no insert, no new events | PASS |
| Cross-project plan/build binding — POST with tproject_id=50, tplan_id=16 (plan of project 1), build 30 rejected | PASS |
| Non-linked tcversion 14 rejected ('Version not linked to this test plan/platform') | PASS |
Rights gate intact — tester1 without testplan_execute gets 'Insufficient rights', no insert |
PASS |
| Event Viewer clean — zero new Error/Warning from the fixed flow (only the pre-fix event id 7 remains) | PASS |
| Browser console — no JS errors during the click cycle | PASS |

-
0c97bca0e— fix (project-scoped build check in quick_result) -
e575f67de— review hardening (plan↔project cross-bind) -
fb0e8e6a4— regression suitetmp/TLU_Test_Cases.md+ this documentation
Refs #1180.