Thanks for your detailed analysis. I appreciate you digging deeper into the root cause.
For this patch, I'd like to keep the changes to `initdb` minimal and focused on rejecting empty usernames, as that seems to be the consensus from the previous discussion.
I'll be happy to discuss the `getid()` and `aclitem` parsing behavior in a separate thread.
On 02.07.25 04:55, Jianghua Yang wrote: > While working with `initdb`, I noticed that passing an empty string to > the `-U` option (e.g., `initdb -U ''`) causes it to fail with a > misleading error: > > performing post-bootstrap initialization ... 2025-07-01 19:48:42.006 PDT > [14888] FATAL:role """ does not exist at character 72 > > 2025-07-01 19:48:42.006 PDT [14888] STATEMENT: > > UPDATE pg_class SET relacl = (SELECT array_agg(a.acl) FROM(SELECT > E'=r/""' as acl UNION SELECT unnest(pg_catalog.acldefault(CASE WHEN > relkind = 'S' THEN 's'ELSE 'r' END::"char",10::oid)) ) as a) WHERE > relkind IN ('r', 'v', 'm', 'S')AND relacl IS NULL; > > This happens because `initdb` accepts the empty string as a valid role > name and attempts to use it as the database superuser, which is not > intended and fails during bootstrap SQL.
I'll start by saying, of course an empty user name isn't going to work, so we should reject it.
But let's dig a little deeper into why it fails. Observe the error:
FATAL:role """ does not exist at character 72
It thinks that the role name is `"` (a sole double-quote, not empty!). Why is that?
This error comes from the literal
E'=r/""'
interpreted as an aclitem value. The aclitem parsing ends up in getid() in src/backend/utils/adt/acl.c, which thinks that an input string consisting entirely of "" is an escaped double quote.
Maybe it's worth fixing that, and making putid() also print empty user names correspondingly.
Alternatively, it's the fault of initdb that it constructs aclitem values that don't follow the aclitem-specific quoting rules.
Another thought is, if we don't allow zero-length names, shouldn't namein() reject empty input strings? Then this whole thing would fail as postgres.bki is being loaded. (This is more hypothetical, since this appears to break a number of other things.)
All of this is to say, it's worth looking at the actual cause and think about if there are related problems, maybe other name patterns that we don't handle well, instead of just papering over it at the top level.