Repository navigation
Conversation
… means to report as FAIL
ImportDatabaseStatement.executeSimple wrote result=FAIL in the InvocationTargetException handler
and then assigned result=OK unconditionally two lines below the enclosing try, so the FAIL branch
was unobservable by any caller: an import that never ran answered {"result":"OK"} with no rows and
no statistics.
The branch arrived with probeOnly (#1401). A probe asks whether a source can be parsed, and
Importer.load() converts a failed probe into an IllegalArgumentException precisely so the statement
can report it as a row rather than by throwing - which is why this keeps the in-band shape rather
than switching to CommandExecutionException: throwing would leave no way to ask the question.
- result=OK moves into the success path, right after the statistics are folded in, the shape
BackupDatabaseStatement already has. No flag, no second assignment.
- A reason property travels with FAIL. FAIL alone says nothing a caller can act on, and the server
log was the only place the message existed.
- e.getTargetException() is hoisted into a local and null-guarded; e.getCause() was dereferenced
unchecked and the two accessors were mixed for the same object.
The exact class-name comparison is deliberately kept rather than widened to an instanceof: the
IllegalArgumentException subclasses that reach here (NumberFormatException, from
ImporterSettings.parseParameter's Integer.parseInt on a numeric setting) have always been thrown,
and widening would turn those errors into rows.
The sweep found a second producer of the branch that the issue does not name:
ImporterSettings.parseParameter raises the same exact type for a WITH value it refuses, before the
import runs at all, so 'WITH onRowError = bogus' also answered OK for an import that never
happened. Both producers are covered.
Six regression tests in the integration module drive the statement through database.command("sql",
...): failed probe, successful probe, refused setting, successful import, non-probe import failure,
and the NumberFormatException subclass that must keep throwing.
Follow-up filed: #7484 - the startup 'import:' default-database command discards this result row,
so a FAIL is as silent there after this fix as before it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthrough
ChangesIMPORT DATABASE result handling
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix · Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to The change preserves failed import results and regression coverage passed; no current merge-blocking risk is identified. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 2 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Tick the box to add this pull request to the merge queue (same as
|
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 4 |
🟢 Coverage ∅ diff coverage · -6.38% coverage variation
Metric Results Coverage variation ✅ -6.38% coverage variation Diff coverage ✅ ∅ diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (d3d9a48) 178988 147639 82.49% Head commit (a2e694a) 211391 (+32403) 160871 (+13232) 76.10% (-6.38%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#7493) 0 0 ∅ (not applicable) Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
ReviewI traced the fix against Correctness
Tests
Nits (non-blocking)
Out of scope, correctly deferred
Overall this is a well-scoped, well-verified fix. No security or performance concerns - the SSRF/LFI guard's rethrow loop is unchanged in semantics, and no new dependencies were introduced. |
Adds the PR link, the adversarial pass with its four findings and their dispositions, the cycle-1 review outcome, and the CI analysis: the branch's own six tests pass in CI, while the two red lanes are inherited rather than caused here - three deterministic unit-test failures reproduced on an unrelated PR (#7495) and a hardcoded-port gRPC IT collision that picks a different victim each run (#7496). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
CI: the branch's own tests pass; both red lanes are inheritedPosting the analysis so nobody has to redo it. The new test ran in CI and passed - run 34657385125's
Evidence rather than inference: the unrelated PR #7489 (RDF importer only, run 34657353357) fails on exactly the same three report files, and locally
I did not re-run either lane to chase green: the three unit-test failures are deterministic on the base, and the gRPC one would only be another roll of the same dice. |
ReviewSolid, well-scoped fix. Correctness
Test coverage Minor/non-blocking notes
Security: The SSRF/LFI guard rethrow loop ( Performance: No concerns - this is exception-handling/result-shaping code on an already-slow-path (import), not a hot path. Nothing blocking. Nice, tightly scoped fix with a strong regression suite. |
Cycle 2 was triggered by the tracking-doc commit itself and closed with "Nothing blocking", so the final state is clean-approval after 2 cycles. Last cycle recorded: a further doc commit would only re-trigger a review of itself. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
ReviewWent through the diff ( Correctness
Minor / non-blocking
TestsGood coverage and good discipline: each test pins more than just the result string (root-cause exception type, schema untouched to prove a probe didn't actually import, reason text on both halves) which rules out the classic "green for the wrong reason" failure mode. The two regression guards ( Security / performanceNo concerns. The DocsThe Nice, tightly-scoped fix with a clear invariant and tests that actually pin the behavior rather than just the happy path. Nothing blocking from my pass. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7493 +/- ##
=======================================
Coverage 74.00% 74.01%
=======================================
Files 1957 1957
Lines 178988 178988
Branches 37784 37784
=======================================
+ Hits 132469 132476 +7
+ Misses 31386 31385 -1
+ Partials 15133 15127 -6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Superseded by #7497, which implemented all five issues (#7341, #7342, #7345, #7347, #7461) independently and merged first, and by #7498, which carries the four follow-ups this branch only filed (#7487, #7488, #7490, #7494). Main is ahead of this branch, so merging it would regress that work. Closing rather than resolving the conflicts. The regression tests on this branch are NOT superseded - they cover considerably more than what landed - and porting them onto the merged implementation's API is tracked separately. |
Closes #7461
ImportDatabaseStatement.executeSimplewroteresult=FAILin theInvocationTargetExceptionhandler and then assignedresult=OKunconditionally two lines below the enclosingtry, so theFAILbranch could not be observed by any caller: anIMPORT DATABASEthat never ran answered{"result":"OK"}with no rows and no statistics. The branch arrived withprobeOnly(#1401) and has been dead since the day it was written -Importer.load()converts a failed probe into anIllegalArgumentExceptionprecisely so this statement can report it as a row rather than by throwing, which is why this PR takes the issue's first option (keep the in-band shape, makeFAILsurvive, add areason) rather than the second: throwing aCommandExecutionExceptionwould leave no way to ask "can this source be parsed?" at all. Three changes -result=OKmoves into the success path immediately after the statistics are folded in (the shapeBackupDatabaseStatementalready has, so there is no flag and no second assignment); areasonproperty travels withFAIL, becauseFAILon its own tells a caller nothing it can act on and the server log was the only place the message existed; ande.getTargetException()is hoisted into a null-guarded local, sincee.getCause()was being dereferenced unchecked and the two accessors were mixed for the same object. The exact class-name comparison is deliberately kept rather than widened to aninstanceof: theIllegalArgumentExceptionsubclasses that reach here (NumberFormatException, fromImporterSettings.parseParameter'sInteger.parseInton a numeric setting) have always been thrown, and widening the branch would silently turn those errors into rows.The completeness sweep found a second producer of the branch that the issue does not name:
setSettingsreachesImporterSettings.parseParameter, which raises the same exact type for aWITH ...value it refuses - before the import runs at all - soIMPORT DATABASE ... WITH onRowError = 'bogus'also answeredOKfor an import that never happened. Both producers are covered and both now carry a reason.Test plan
New
integration/src/test/java/com/arcadedb/integration/importer/Issue7461ImportDatabaseFailResultTest.java, six tests, each driving the statement throughdatabase.command("sql", ...)- the same live path a client uses:aFailedProbeReportsFailWithAReason-WITH probeOnly = trueon a missing source returnsFAIL, with areasonnaming both the failure type and the file.aSuccessfulProbeStillReportsOk- a good source still returnsOK, and the schema is untouched, which is what proves the probe actually probed rather than imported.anUnusableSettingValueReportsFailWithAReason-WITH onRowError = 'bogus'returnsFAILwith the parser's own sentence, and nothing was loaded.aSuccessfulImportStillReportsOk- a plain import is unchanged:OK, statistics, 2 records, noreason.aGenuineImportFailureStillThrows- a non-probe import of a missing source still throwsCommandExecutionException, pinned by root cause so it cannot pass via an earlier guard.aNonNumericNumericSettingStillThrows-WITH commitEvery = 'abc'still throws, root causeNumberFormatException; this is the test that fails if someone widens the match to aninstanceof.Before the fix:
Tests run: 6, Failures: 2- exactly the twoFAILrows, with the four guard tests already green. After:Tests run: 6, Failures: 0.integrationmodule, full suite minus thebenchmark/slow/vectorlanes: 372 tests, 0 failures, 9 skipped.enginemodule, same lanes: 14870 tests, 1 failure -MultiColumnAggregationResultTest.emptySumAndCountStayZeroNotNaN(expected: 0.0 but was: NaN). Pre-existing onmainand unrelated: re-run withImportDatabaseStatement.javarestored to itsHEADcontent it fails identically. Time-series aggregation, nothing to do with this change - flagging it because it is red on the base commit.ImportDatabaseSecurityIT,Issue7443SqlMaintenanceSlotIT) were not run locally: port 2480 was already held by another process on this machine, and a server IT against an occupied port reports authentication errors rather than anything meaningful. CI covers them. TheSecurityExceptionrethrow they exercise is unchanged in semantics - the loop reads the same object through a local.Coverage
WITH probeOnly = true, unparseable source ->Importer.load()raisesIllegalArgumentExceptionWITH probeOnly = true, good source ->load()returnsnullOK)WITH onRowError = 'bogus'->setSettingsraises the exactIllegalArgumentExceptionload()wraps it inImportException, which never reached theFAILbranch and still throwsWITH commitEvery = 'abc'->NumberFormatExceptionSecurityException(SSRF/LFI guard)getTargetException()into a localImportDatabaseSecurityITBACKUP/EXPORT DATABASEsiblingsFAIL;EXPORT's catch always throws,BACKUPsetsOKinside its success branch.grep '"FAIL"'over the tree returns this one siteimport database <name> <url>(HTTP/gRPC/Studio button)ServerControlPlane.importDatabase, which drivesImporterdirectly and never reaches this statementKnown gaps
ArcadeDBServer.loadDefaultDatabasesruns theimport:startup command through this statement and discards the result set (// drain not needed), so aFAILrow is as silent after this fix as it was before it. This PR gives that path an answer worth reading; reading it is a server-module change. Filed before this PR opened.WITH commitEvery = 'abc'(throws) andWITH onRowError = 'bogus'(returns aFAILrow) is inherited, documented in the code comment, and pinned by two tests. Unifying it means deciding whether a refused setting is an error or a row for every setting - a contract change this PR deliberately does not make.Tracking doc:
docs/7461-import-database-result-ok-on-fail.md.🤖 Generated with Claude Code
https://claude.ai/code/session_01B1vgWQXZoDXYq7TqAwLYXY
Summary by CodeRabbit
IMPORT DATABASEnow correctly reportsFAILinstead of incorrectly marking failed operations as successful.OK.