Skip to content

Conversation

davoclavo
Copy link
Contributor

@davoclavo davoclavo commented May 13, 2025

Hello! First of all, thank you for this amazing library

This PR addresses a bug where setting the PGHOST environment variable can unintentionally override explicitly passed connection options like :hostname, :socket_dir, :socket, or :endpoints.

Summary

  • Fix: Updated default_opts/1 to derive the host from PGHOST only if no endpoint-related options are explicitly provided (:socket, :socket_dir, :hostname, or :endpoints).
  • Test: Added test coverage to ensure that explicitly provided connection options correctly take precedence over environment-derived defaults.
  • Important note: This might cause breaking changes to existing users if they might be inadvertently overriding values that are currently ignored.

Motivation

When PGHOST is set (e.g., to a Unix socket path), Postgrex currently prioritizes it over explicitly passed options like :hostname. This causes surprising behavior: users trying to connect to a remote host (e.g., localhost over TCP) may find Postgrex silently attempting to connect over a non-existent socket.

This PR brings Postgrex closer in behavior to psql, which properly prioritizes CLI-supplied options over PGHOST.


Replication Instructions

You can reproduce the issue as follows:

  1. Set PGHOST to any path:

    PGHOST=/whatever iex -S mix
  2. Attempt to start a connection using valid TCP settings:

    Expected: Should connect over TCP to localhost
    Actual: Fails, as Postgrex attempts to connect via /whatever/.s.PGSQL.5432 socket specified via PGHOST.

    {:ok, pid} = Postgrex.start_link(
      hostname: "localhost",
      username: "postgres",
      password: "postgres",
      database: "postgres",
      port: 5432
    )
    
    Postgrex.query(pid, "SELECT 1", [])
  3. Current workaround (demonstrating expected behavior with a workaround using manual override to socket_dir: nil):

    {:ok, pid} = Postgrex.start_link(
      hostname: "localhost",
      username: "postgres",
      password: "postgres",
      database: "postgres",
      port: 5432,
      socket_dir: nil
    )
    
    Postgrex.query(pid, "SELECT 1", [])

Behavior Comparison with psql

To reinforce expected behavior, here’s how psql treats similar inputs:

Explicit -h localhost takes precedence over PGHOST:

PGHOST=/whatever psql -d postgres -h localhost -U postgres -c "SELECT 1"

This should fail as no -h is provided and the PGHOST socket doesn't exist

PGHOST=/whatever psql -d postgres -U postgres -c "SELECT 1"

 - Updated `default_opts/1` to apply PGHOST-derived host only when no
 endpoint-related options (:socket, :socket_dir, :hostname, :endpoints)
 are explicitly provided.

 - Added test coverage for new behavior, ensuring explicit endpoint keys
 override PGHOST-derived values.
@davoclavo davoclavo force-pushed the fix/prioritize_explicit_endpoints_over_PGHOST branch from 56c6f85 to 30efa5b Compare May 13, 2025 06:00
@josevalim josevalim merged commit 412b555 into elixir-ecto:master May 13, 2025
9 checks passed
@josevalim
Copy link
Member

💚 💙 💜 💛 ❤️

davoclavo added a commit to davoclavo/sequin that referenced this pull request May 13, 2025
This is a temporary workaround to override any PGHOST-related value that might
inadvertently set by default

We can revert this once a new Postgrex version >0.20.0 is published

See elixir-ecto/postgrex#742 for more information
davoclavo added a commit to davoclavo/sequin that referenced this pull request May 13, 2025
This is a temporary workaround to override any PGHOST-related value that might
inadvertently set by default

We can revert this once a new Postgrex version >0.20.0 is published

See elixir-ecto/postgrex#742 for more information
davoclavo added a commit to davoclavo/sequin that referenced this pull request May 13, 2025
This is a temporary workaround to override any PGHOST-related value that might
inadvertently set by default

We can revert this once a new Postgrex version >0.20.0 is published

See elixir-ecto/postgrex#742 for more information
acco pushed a commit to davoclavo/sequin that referenced this pull request May 17, 2025
This is a temporary workaround to override any PGHOST-related value that might
inadvertently set by default

We can revert this once a new Postgrex version >0.20.0 is published

See elixir-ecto/postgrex#742 for more information
acco pushed a commit to sequinstream/sequin that referenced this pull request May 17, 2025
)

This is a temporary workaround to override any PGHOST-related value that might
inadvertently set by default

We can revert this once a new Postgrex version >0.20.0 is published

See elixir-ecto/postgrex#742 for more information
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.

2 participants