Not every open-source contribution needs a saga. Sometimes the whole story is: hit an annoying error, find the one missing
COALESCE, ship a one-line diff, done. This is one of those — a small bug inusql, the universal command-line SQL client, that turned into a satisfying little fix with a slightly bumpy landing.
The bug: tab completion that complains before it works
While using usql against PostgreSQL, hitting Tab for autocompletion threw this at me every single time:
Error getting selectables sql: Scan error on column index 6, name "routine_definition": converting NULL to string is unsupported
The frustrating part: completion still worked afterward. The error was purely noise — but noise you'd see on every single tab-press, which gets old fast. I filed it as issue #554.
Root cause: not every function has a definition
usql builds its completion suggestions by querying information_schema.routines, and one of the columns it scans is routine_definition. That column holds the SQL body of a function or procedure — but only for functions written in SQL. For external or C-language functions, PostgreSQL simply has nothing to put there, so the column comes back NULL.
Go's database/sql scanning is strict about this: you can't scan a NULL straight into a string. You need a sql.NullString, a pointer type, or — the simplest fix when you're just displaying the value — coerce it at the SQL level.
Digging into drivers/metadata/informationschema/metadata.go, the surrounding query already knew this. Neighboring nullable columns were wrapped defensively:
"COALESCE(routine_type, '')",
"COALESCE(data_type, '')",
routine_definition was just the one column that had been missed.
The fix
One line, same pattern as its neighbors:
- "routine_definition",
+ "COALESCE(routine_definition, '')",
That's it. COALESCE swaps the NULL for an empty string before it ever reaches the scanner, consistent with how the query already treated routine_type and data_type. No new imports, no new types, no behavior change for the common case — just one more nullable column brought in line with its siblings.
I opened PR #555 with the fix, referencing #554.
Merged — sort of
Maintainer @kenshaw reviewed it quickly and closed out the issue, and a few days later the PR itself was closed with a note: "Added to main. Thanks!"
Except the PR wasn't merged in the GitHub sense — the change had been applied manually rather than through a merge commit. GitHub was straightforward about it too, flagging the PR as "Closed with unmerged commits" since my branch still had commits that were never actually merged into main.
I asked about it, since authorship tracking matters for contribution history:
"I noticed the changes were added manually instead of merging the PR. Would it be possible to preserve authorship in such cases (e.g., via merge or co-author)?"
@kenshaw's answer cleared it up immediately — this wasn't a snub, it was branch juggling:
"I used cherry-pick here as I needed to add it to the release-21 branch as well as main. I should have used rebase onto main, and then cherry-picked it to the release branch."
Which makes complete sense once you think about it: a one-line fix like this isn't just useful on main, it's useful on the active release branch too, and cherry-picking is the standard way to land the same commit in two places without a merge tangling up both histories. The trade-off is that GitHub's PR UI doesn't recognize a cherry-picked commit as "merged," even though the commit — author, committer, and all — is sitting right there in the Git history on both branches.
Takeaways
A few small things worth remembering from a fix this size:
-
COALESCEis your friend for optional metadata columns. Anywhere you're joining againstinformation_schemaor similar catalogs, assume any column can beNULLunless you know otherwise, and handle it at the query level if you're just going to stringify it anyway. - Consistency is a debugging shortcut. The fix here wasn't found through deep investigation — it was found by noticing the query already had a pattern for handling this exact problem on two other columns, and one column had been left out.
- "Closed, not merged" isn't always a red flag. If a maintainer needs a fix on multiple branches (like a release branch and main), cherry-picking is often the cleaner tool, even though it means GitHub won't show your PR as formally merged. Your authorship still travels with the commit either way.
Full trail if you want to see it:
Top comments (0)