Return no-op instead of SQL error when ObservationLog has no valid entries - #2706
Return no-op instead of SQL error when ObservationLog has no valid entries#2706pujitha24 wants to merge 3 commits into
Conversation
…tries
Motivation:
RegisterObservationLog in pkg/db/v1beta1/mysql/mysql.go and
pkg/db/v1beta1/postgres/postgres.go builds an INSERT ... VALUES query by
appending a placeholder group per MetricLog entry with a non-empty
TimeStamp, then strips the trailing comma via
sqlQuery[0:len(sqlQuery)-1]. When every entry is skipped (empty
MetricLogs, or every entry has an empty TimeStamp), no placeholder
groups are appended, and the truncation instead chops the trailing
space off "...VALUES ", producing a malformed statement that fails
Prepare() with a SQL syntax error. That error is returned as-is by the
ReportObservationLog gRPC handler, so a call that should be a harmless
no-op fails the RPC instead. This is per-RPC only; it does not affect
the db-manager process itself.
Approach:
Add an early "if len(values) == 0 { return nil }" guard right after
the loop that builds values, before the query string is truncated, in
both mysql.go and postgres.go.
Validation:
Added TestRegisterObservationLogNoValidEntries to
pkg/db/v1beta1/mysql/mysql_test.go and
pkg/db/v1beta1/postgres/postgres_test.go, each registering an
ObservationLog with a single MetricLog whose TimeStamp is empty,
asserting RegisterObservationLog returns nil. Confirmed the tests
reproduce the exact bug: reverting only the two-line fix (keeping the
new tests) makes both fail with "Prepare SQL statement failed: ...
call to Prepare 'INSERT INTO observation_logs (trial_name, time,
metric_name, value) VALUES' query was not expected"; re-applying the
fix makes them pass.
Ran:
- go build ./pkg/db/... -> passes
- go test ./pkg/db/v1beta1/mysql/... ./pkg/db/v1beta1/postgres/... -> all pass
- gofmt -l on changed files -> clean
- go vet ./pkg/db/v1beta1/mysql/... ./pkg/db/v1beta1/postgres/... -> clean
- golangci-lint run on the changed packages reports 7 pre-existing
issues (errcheck on stmt.Close()/rows.Close(), staticcheck ST1005 on
capitalized error strings); verified via git stash that all 7 exist
identically on unmodified master, none introduced by this change.
Locally available golangci-lint is v2.12.2 vs this repo's pinned
v1.64.7 for make lint, a version mismatch disclosed here rather than
resolved since the flagged lines are outside this diff.
- Did not run against a live MySQL or PostgreSQL instance; validation
relies on this package's existing sqlmock-based unit test harness,
the same one the file's pre-existing RegisterObservationLog test
uses.
Report: kubeflow#2705
Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
Assisted-by: claude-sonnet-5 (via Claude Code)
|
🎉 Welcome to the Kubeflow Katib repo! 🎉 Thanks for opening your first PR! We're excited to have you onboard 🚀 Next steps:
Feel free to ask questions in the comments. Thanks again for contributing! 🙏 |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @pujitha24 , thanks for jumping on this so quickly! For transparency — I filed #2705 and also have a fix ready for this (same approach as proposed in the issue), which I was holding until maintainer feedback before submitting a PR. Since your PR is already up and looks correct, I'd suggest the maintainers move forward with it. I've left my review with a couple of small suggestions below.
|
Add a test covering a fully-empty MetricLogs slice (distinct from the existing empty-timestamp case) and a short comment explaining why the no-op path skips Prepare/Exec, per review feedback. Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
vjkumar2756
left a comment
There was a problem hiding this comment.
@pujitha24
Great fix Returning early when no valid metric entries exist prevents malformed SQL syntax errors and avoids unnecessary DB execution.
Some Suggestions
- Add
nilGuard (mysql.go&postgres.go)
IfobservationLogisnil, iterating overobservationLog.MetricLogswill cause a runtime panic (nil pointer dereference). Consider checkingobservationLog == nilat the top ofRegisterObservationLog:if observationLog == nil || len(observationLog.MetricLogs) == 0 { return nil }
Add an early nil check for observationLog in mysql.go and postgres.go to avoid a nil pointer dereference when iterating MetricLogs, per review feedback from vjkumar2756. Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
|
Thanks both for the suggestions — pushed two follow-up commits addressing them:
Both packages' test suites pass locally with these changes. |
What this PR does / why we need it:
RegisterObservationLoginpkg/db/v1beta1/mysql/mysql.goandpkg/db/v1beta1/postgres/postgres.gobuilds anINSERT ... VALUESquery by appending a(?, ?, ?, ?),placeholder group perMetricLogentry that has a non-emptyTimeStamp, then strips the trailing comma withsqlQuery[0:len(sqlQuery)-1]. When every entry in theObservationLogis skipped (emptyMetricLogs, or every entry has an emptyTimeStamp), no placeholder groups are appended, and the truncation instead chops the trailing space off"...VALUES ", producing a malformed statement.Prepare()then fails with a SQL syntax error, and that error is returned as-is by theReportObservationLoggRPC handler (cmd/db-manager/v1beta1/main.go), so a call that should be a harmless no-op fails the RPC instead. This is per-RPC only — it does not crash or otherwise affect the db-manager process itself, just that oneReportObservationLogcall.Approach: Add an early
if len(values) == 0 { return nil }guard right after the loop that buildsvalues, before the query string is truncated, in bothmysql.goandpostgres.go. This is the primary fix the issue proposed.RegisterObservationLog's only caller passes its error straight through as the gRPC error, so returningnilwhen there is nothing to insert is a safe no-op with no skipped side effects.Validation:
TestRegisterObservationLogNoValidEntriestopkg/db/v1beta1/mysql/mysql_test.goandpkg/db/v1beta1/postgres/postgres_test.go, each registering anObservationLogwith a singleMetricLogwhoseTimeStampis empty (so it is skipped), assertingRegisterObservationLogreturnsnil.Prepare SQL statement failed: ... call to Prepare 'INSERT INTO observation_logs (trial_name, time, metric_name, value) VALUES' query was not expected— sqlmock rejecting the malformed truncated query from the issue report. Re-applying the fix makes them pass.go build ./pkg/db/...— passes.go test ./pkg/db/v1beta1/mysql/... ./pkg/db/v1beta1/postgres/...— all tests pass, including the two new ones and the pre-existingTestRegisterObservationLog.gofmt -lon the changed files — clean.go vet ./pkg/db/v1beta1/mysql/... ./pkg/db/v1beta1/postgres/...— clean.golangci-lint run ./pkg/db/v1beta1/mysql/... ./pkg/db/v1beta1/postgres/...reports 7 pre-existing issues (errcheck onstmt.Close()/rows.Close(), staticcheck ST1005 on capitalized error strings); verified viagit stashthat all 7 are present identically on unmodifiedmasterand none are introduced by this change. Note: the locally availablegolangci-lintis v2.12.2, while this repo'smake lintpins v1.64.7 — a version mismatch, disclosed here rather than resolved, since the flagged lines are all pre-existing and outside this diff.sqlmock-based unit test harness (github.com/DATA-DOG/go-sqlmock), the same harness the file's pre-existingRegisterObservationLogtest uses.upstream/mastertip (dec5030ef9791add2a7224d8ba3cb9b699bf70da).Which issue(s) this PR fixes (optional, in
fixes #<issue number>(, fixes #<issue_number>, ...)format, will close the issue(s) when PR gets merged):Fixes #
Checklist:
Fixes #2705