[PATCH] pg_upgrade: handle failed nonblocking connects on Windows
Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.
You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:
docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t254184psql -h localhost -U postgresBuilt from patchset v1 (message #1), October 14, 2026 at 09:18 PM.
Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:
git clone --branch t254184_1 https://github.com/hackorum-dev/postgres.gitIn a checkout you already have, add the fork once:
git remote add hackorum https://github.com/hackorum-dev/postgres.gitthen, for this patchset and every later one:
git fetch hackorum t254184_1 && git checkout t254184_1Patchset v1 (message #1) is on t254184_1
pg_upgrade can stall when localhost first reaches a refused IPv6
endpoint on Windows. Its aggregate select loop omits the exception
set, so PQconnectPoll does not process the failure and try IPv4. Libpq
already handles this in its single-socket helper.
The patch handles exceptional readiness in pg_upgrade's existing state
machine. Its Windows TAP test checks both successful-first IPv4 and
refused-first localhost fallback, skipping when resolver/refusal
preconditions are unavailable.
All seven assertions pass on MSVC ARM64, MSVC x64 and MinGW x64. The
x64 runs use emulation on the ARM64 host. Earlier copied-upgrade tests
from released 18.0 x64 and official 19rc1 ARM64 also preserve the
seeded data.
The combined patch includes the tested production fix and test
controls. Exact revisions and coverage are recorded with the evidence.
Best,
Harrison
On 13/10/2026 23:58, Harrison Booth wrote:
pg_upgrade can stall when localhost first reaches a refused IPv6
endpoint on Windows. Its aggregate select loop omits the exception
set, so PQconnectPoll does not process the failure and try IPv4. Libpq
already handles this in its single-socket helper.The patch handles exceptional readiness in pg_upgrade's existing state
machine. Its Windows TAP test checks both successful-first IPv4 and
refused-first localhost fallback, skipping when resolver/refusal
preconditions are unavailable.All seven assertions pass on MSVC ARM64, MSVC x64 and MinGW x64. The
x64 runs use emulation on the ARM64 host. Earlier copied-upgrade tests
from released 18.0 x64 and official 19rc1 ARM64 also preserve the
seeded data.
Is there any harm in checking for the exception set on other systems too?
@@ -344,7 +347,18 @@ select_loop(int maxFd, fd_set *input, fd_set *output)
*input = save_input;
*output = save_output;+#ifdef WIN32 + /* Winsock reports failed nonblocking connects as exceptions. */ + exceptions = save_output; + i = select(maxFd + 1, input, output, &exceptions, NULL); + if (i > 0) + { + for (unsigned int j = 0; j < exceptions.fd_count; j++) + FD_SET(exceptions.fd_array[j], output); + } +#else i = select(maxFd + 1, input, output, NULL, NULL); +#endif
Looks wrong to set merge the exception set with the writable set like
that. I think it'd be better to add an 'exceptions' argument to the
function.
As a side-note, I'm not convinced that saving the fdsets and looping
here on EINTR is really worth it, the caller would reconstruct the
fdsets and loop back here anyway if there's no work to do. But that's
not new with this patch.
- Heikki