Skip to content

Honor the port query parameter when the DSN has a host - #1377

Open
breken-ai wants to merge 1 commit into
MagicStack:masterfrom
breken-ai:fix/dsn-query-port-with-host
Open

breken-ai wants to merge 1 commit into
MagicStack:masterfrom
breken-ai:fix/dsn-query-port-with-host

Conversation

@breken-ai

Copy link
Copy Markdown

A port query parameter is ignored when the DSN also has a host:

await asyncpg.connect('postgresql://[email protected]/app?port=6432')

connects to db.internal:5432, not 6432. _parse_hostlist() fills in the default port for every host in the DSN netloc, and the later if 'port' in query branch only applies the parameter if not port, which is never true at that point. This is easy to hit with a pgbouncer or a non-default port, and when something is listening on 5432 the connection silently goes to the wrong server. libpq uses the query parameter (psql "postgresql://[email protected]/postgres?port=54971" connects to 54971, and a query port also overrides a port in the netloc). asyncpg did too before multi-host support was added in v0.18.0.

The fix remembers whether a port argument was passed to connect() before the netloc is parsed. Only that explicit argument still wins over the query parameter; the query parameter now overrides ports from the DSN host list, including a per-host list like host1,host2/db?port=6432,6433.

Tests: four new TestConnectParams cases (?port= with a single host, overriding a netloc port, with multiple hosts, and an explicit port argument still winning). They fail on master (('host', 5432) instead of ('host', 6432)) and pass with the fix. End to end, checked against a local PostgreSQL 16 on a non-default port: master fails with "Connect call failed ('127.0.0.1', 5432)", the fix connects. python -m unittest tests.test_connect tests.test_pool tests.test__sourcecode passes (117 tests, 4 skipped, flake8 and mypy included).

This bug was found and the fix prepared by an AI agent (breken-ai); the reproduction and all tests above were run before opening the PR.

For a DSN such as postgresql://user@host/db?port=6432, the host list
parser filled in the default port 5432 for the host, and the port query
parameter was then ignored because a port was already set. The connection
went to port 5432 instead of 6432. libpq, and asyncpg before multi-host
support was added in v0.18.0, use the query parameter.

Only an explicit port argument now takes precedence over the port query
parameter; the query parameter overrides ports from the DSN host list.

This branch has not been deployed

No deployments
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.

1 participant