[PATCH] Fix getopt_long() argument handling and add tests
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:t253601psql -h localhost -U postgresBuilt from patchset v1 (message #1), August 29, 2026 at 05:10 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 t253601_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 t253601_1 && git checkout t253601_1Patchset v1 (message #1) is on t253601_1
Hi hackers,
While reworking the pg_waldump TAP test [1]/messages/by-id/CAH7T-araSEdsNpxiKaMOW8kr_ZHhekCLHx5yzm2ksq4FdgULbA@mail.gmail.com I ran "pg_waldump --stats
--limit 5" and it failed on Windows CI with 'could not locate WAL file
"5"'. For a long option with optional_argument and no "=", the port
getopt_long() increments optind in the missing-argument branch and
again at the end of the long option path, so the next option is
skipped and its value becomes a positional argument. The same branch
returns BADARG when optstring starts with a colon although nothing is
missing.
glibc handles both correctly, so this only happens in CI on Windows, for
--stats in pg_waldump and --install-missing in pg_amcheck when another
option follows. psql's --help is also optional_argument but exits
before anything after it matters.
0001 gives optional_argument its own branch that sets optarg to NULL
and falls through to the common optind increment. The remaining else
is then only the missing required argument case.
0002 adds src/test/modules/test_getopt_long, since nothing in
check-world exercises this file on Linux or macOS. A small harness
takes an optstring, a long option list and the arguments, and prints
one line per getopt_long() return plus the leftover non-options.
src/port/getopt_long.c is compiled into it directly so it is tested
everywhere. A second copy linked without it runs the same cases
against the system getopt_long().
The TAP test is a text table of named cases, each with its arguments
and expected output:
== long optional, separate not consumed
args: --gamma foo
--gamma
-- foo
== short missing arg, silent
optstring: :ab:
args: -b
:
--
It covers short options attached, separate and bundled, missing and
unknown options with and without the leading colon, long required
arguments in each form, long optional arguments first, middle and
last, the flag pointer form, "--", a lone "-" and non-option
reordering. Port and system output match on every case on Linux and
macOS. Only the error message wording differs and the test accepts
either.
0003 fixes a second problem the tests turned up. The port moves each
non-option to the end of argv as soon as it sees it, so by the time a
following option looks for its argument, a non-option that came before
it on the command line is already sitting after it and gets taken:
"pg_amcheck mydb --jobs" parses as --jobs=mydb rather than reporting
the missing argument. The system getopt_long() reports the missing
argument. The fix bounds the argument search by the start of the
moved block. 0004 adds the test cases for it, kept separate in case
0003 is backpatched without the test module.
This behavior comes from the non-option reordering added in 411b720343.
CC'ing Nathan in case I'm missing an intended aspect of that
implementation.
Without 0001 and 0003 the port binary fails 16 cases, the 12 optional
argument ones that 0001 fixes and the four from 0004 that 0003 fixes.
The system binary passes throughout on Linux. With both patches, all
244 checks pass.
Both fixes seem worth backpatching. The test module itself probably
doesn't need to be.
AI review also flagged a couple of possible portability issues with
the system getopt_long() comparison on BSD, particularly around
differences in error messages. I don't have a BSD system to test on,
so will see what the buildfarm says.
[1]: /messages/by-id/CAH7T-araSEdsNpxiKaMOW8kr_ZHhekCLHx5yzm2ksq4FdgULbA@mail.gmail.com
Regards,
-- Sehrope Sarkuni
Founder & CEO | JackDB, Inc. | https://www.jackdb.com/