Skip to content

fix(connection): check socket file existence in default_host(), not directory#725

Merged
NikolayS merged 4 commits intomainfrom
fix/default-host-socket-check
Mar 24, 2026
Merged

fix(connection): check socket file existence in default_host(), not directory#725
NikolayS merged 4 commits intomainfrom
fix/default-host-socket-check

Conversation

@NikolayS
Copy link
Copy Markdown
Owner

Closes #721

Previously checked if the candidate socket directory existed. Now checks if the actual socket file (.s.PGSQL.) exists inside it, preventing false positives when the directory exists but no Postgres is running.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Mar 24, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.80%. Comparing base (9bf4b40) to head (9d39fd7).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #725   +/-   ##
=======================================
  Coverage   68.79%   68.80%           
=======================================
  Files          46       46           
  Lines       30999    31000    +1     
=======================================
+ Hits        21325    21327    +2     
+ Misses       9674     9673    -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@NikolayS
Copy link
Copy Markdown
Owner Author

REV: fix(connection): check socket file existence in default_host(), not directory

Verdict: REQUEST CHANGES — the fix is directionally correct and the bug is real, but there are two issues worth addressing before merge.


1. Correctness: directory scan matches .s.PGSQL.<port>.lock too

The .starts_with(".s.PGSQL.") predicate matches both the Unix-domain socket (.s.PGSQL.5432) and the lock file (.s.PGSQL.5432.lock). The lock file is a regular file created alongside the socket by postmaster. In practice this means has_socket can be true if only the lock file is present — which could happen in a crash scenario where the socket was cleaned up but the lock file wasn't. Not a common case, but it's a latent false positive that partially reintroduces the bug this PR is trying to fix.

The fix is straightforward: check file type explicitly.

e.file_type().map(|ft| ft.is_socket()).unwrap_or(false)
    && e.file_name().to_string_lossy().starts_with(".s.PGSQL.")

Or alternatively, since the port is already known (defaults to 5432), skip the directory scan entirely and check directly:

let socket = path.join(format!(".s.PGSQL.{}", DEFAULT_PORT));
if socket.exists() {
    return (*dir).to_owned();
}

The direct check is O(1) vs O(n) directory scan and cannot accidentally match a socket for a different port (see point 2).


2. Correctness: scanning all sockets ignores the target port

The current implementation returns a directory if any .s.PGSQL.* socket exists in it, regardless of port. If /tmp/.s.PGSQL.5433 exists but there is no .s.PGSQL.5432, the code returns /tmp and then the connection attempt to port 5432 fails. The user gets a confusing error: the directory was "detected" as having Postgres, but the connection still fails.

libpq sidesteps this by not probing at all — it just tries to connect and lets the OS return ENOENT or ECONNREFUSED. If we want to probe, we should probe the specific socket that will actually be used.


3. Performance: read_dir() on every default connection attempt

default_host() is called from Default for ConnParams and from resolve_params(), which is on every connection path when no host is specified. read_dir() is a syscall + directory traversal. For the common case (a single Postgres instance), this is one stat() call if we use the direct path check instead of read_dir(). Not a significant concern in practice for a terminal tool, but the direct approach is both simpler and faster.


4. Error handling: silent .ok() on read_dir()

Silently ignoring read_dir() errors is acceptable here — if we can't read the directory, we can't tell if a socket exists, and falling back to localhost is the right default behavior. No concern.


5. Doc comment: backtick-quoted PostgreSQL is unconventional

contains an active \PostgreSQL` socket file— the backticks aroundPostgreSQL` look odd; that's identifier formatting, not prose formatting. Just write it as plain text: "contains an active PostgreSQL socket file".


6. Unrelated: version bump and CHANGELOG belong in PR #720

This PR contains two commits: the fix (correct) and a chore: bump version to 0.8.1 commit. The Cargo.toml bump to 0.8.1 and the new ## [0.8.1] CHANGELOG entry were already added in the separate version-bump PR #720. Having both in this PR creates a merge conflict risk and makes the history harder to read. The version bump commit should be dropped from this PR.

Note also: the CHANGELOG entry for 0.8.1 describes fixes #708 and #711, not this fix (#721). Either this fix should be added to that entry, or the entry is misplaced here.


Summary

# Issue Severity
1 Lock file matches prefix, partial false-positive reintroduced Medium
2 Scan matches wrong-port sockets Medium
3 read_dir() more expensive than needed Low
4 Silent read_dir() error suppression OK
5 Doc comment backtick style Nit
6 Version bump / CHANGELOG leak from PR #720 Should fix

The simplest fix for 1, 2, and 3 together: replace the read_dir() scan with a single path.join(".s.PGSQL.5432").exists() check (using the resolved port, or the default if not yet resolved).

@NikolayS NikolayS force-pushed the fix/default-host-socket-check branch from 8d0ee9a to 4187d38 Compare March 24, 2026 03:49
@NikolayS NikolayS force-pushed the fix/default-host-socket-check branch from 4187d38 to 30f4149 Compare March 24, 2026 03:52
@NikolayS NikolayS merged commit dc09357 into main Mar 24, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(connection): default_host() checks directory existence instead of socket file

2 participants