Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wPsrT-0016kL-37 for pgsql-hackers@arkaria.postgresql.org; Thu, 21 May 2026 02:10:12 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wPsrR-008xFx-21 for pgsql-hackers@arkaria.postgresql.org; Thu, 21 May 2026 02:10:10 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wPsrR-008xFp-0G for pgsql-hackers@lists.postgresql.org; Thu, 21 May 2026 02:10:10 +0000 Received: from mail-pl1-x62b.google.com ([2607:f8b0:4864:20::62b]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wPsrP-000000001xv-1pni for pgsql-hackers@postgresql.org; Thu, 21 May 2026 02:10:08 +0000 Received: by mail-pl1-x62b.google.com with SMTP id d9443c01a7336-2b941cd869cso35183655ad.1 for ; Wed, 20 May 2026 19:10:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779329406; x=1779934206; darn=postgresql.org; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:from:to:cc:subject:date:message-id:reply-to; bh=nuZuW/fq40sDkJrKMcgzNP/TrCrzI549CIxlPgo1Vzw=; b=Gt3eIs6qFAXgz7TkOosdcZMlTAIL2kZ7RNr+7omBAWQ8ZSdWmjT6atecFo3P2szvNy Nvt3QbMjWzjm3qR4eJkj8xsAU3yqQff4zi6H95v1PiCV7vZ9y57+d2ano7J8dmkISPlN WcWSP5KTmOrH5UrSOGB+IgOSgCpPIjSXD+PPZmgCDny5WxV9BF9lfHI2Pz+oGhH2Di+F 0+cakGsG3ag2wEJ0Bx96SFV+/fABykjFKxAhgOgyU5wz++Cj7J4puEK8YASfEOAwTRTI T44VE3LmDuZm8+ZYVseDNUFbAS87fybt48DLhZ6TZckfwi8F78w5BvQPIS0PrEKd868p xJ5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779329406; x=1779934206; h=references:to:cc:in-reply-to:date:subject:mime-version:message-id :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=nuZuW/fq40sDkJrKMcgzNP/TrCrzI549CIxlPgo1Vzw=; b=SG0Wxg/r5rBqTI2IWgpNNiEW5pRJp7AJyNNsvtTT+l9M0lXtQVH9aTbwYO7y9lXKMQ L6hTEN+lo7p1w+HeoNAr1wM3jOCrWaS+bq1rjnrdR+KqhENzwn2OzWAZdeBh6eOc1E4j jAnDEA+1xL9VSS75uJ7wzTGEmth/IE2rDucETPaSCtK7CSgjXG3VVUvQAvvFxrsf6WRj mLuG1P+ptOVYSHC45fo+Ws6cirIbxufgSukxR/VtQB4AshdXgWZVTiriP1WDcV5zDeFC akZzEDTluX1S/V/oj7vix4eLAdnuniKZ88bHxavEuIFeHBGDkb0PviuzuhKePstRgijc 7Hzg== X-Gm-Message-State: AOJu0YxMfEE+TQbd2wYZezntAtiRv8+roUEW4Dh0PFY53BkXEO0XM5er fi0FAI/0ESPFwtybdKZMRkWvTtZCvpBOLM0wbNAhPGXZMeuNzDtCLrex X-Gm-Gg: Acq92OG+rTNtoRmKcMHBmE3wgtTyurkGo792JgdEGDJwe8goWg0GilPzzworxnumsaN E6lj1ysoiBQBnxb1n7718EvsGbW6w8ed36QIuqCJ+UcwIi1///Eqf6mfo/hWlRPAFj72RNsPuFb SlX0blMjZMGdkXUfiFjx4XeTGRN1YKumoovRDAQ3wOrq5SfwumEZx1vqEaJ/la5Wbw0yl2Gg+Ma 8xEpcOVf0lKSFQXWNcWLCgdH6ZuADn18oDdRKQeRoxCbs4hVNKAyRX9HwjTOZPmB+In6BYvt8bW 553PyVd05G1Y62A1bpmfhEq105hdKgAgUva5mR0AJomN9BAqk4zxKz211GaAz7NUrlGm3vu7KOQ Jjv9WBHIlDHHZ9t6taksb2qz6LTEgbQp89CWvMIRHj7HLEdkJh5lhjdIliN1zbLaoqTZOy30eB4 9+3iT8KiP9RYHqR421t+7eYXVtJdWMqYA= X-Received: by 2002:a17:902:cf0f:b0:2bc:7d09:dcef with SMTP id d9443c01a7336-2bea307a586mr8071735ad.29.1779329406264; Wed, 20 May 2026 19:10:06 -0700 (PDT) Received: from smtpclient.apple ([45.32.121.103]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2bd5cfe47c8sm237839625ad.51.2026.05.20.19.10.03 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 20 May 2026 19:10:05 -0700 (PDT) From: Chao Li Message-Id: <978D8971-08C3-4AAD-AE8B-976D753C882A@gmail.com> Content-Type: multipart/mixed; boundary="Apple-Mail=_81EE1C7E-88DC-4FCA-B452-3ED497E52E7C" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.600.51.1.1\)) Subject: Re: Set notice receiver before libpq connection startup Date: Thu, 21 May 2026 10:09:25 +0800 In-Reply-To: Cc: PostgreSQL-development , vignesh C To: Fujii Masao References: X-Mailer: Apple Mail (2.3864.600.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_81EE1C7E-88DC-4FCA-B452-3ED497E52E7C Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On May 20, 2026, at 17:19, Fujii Masao wrote: >=20 > On Wed, May 20, 2026 at 4:21=E2=80=AFPM Chao Li = wrote: >>=20 >> Hi, >>=20 >> While testing =E2=80=9CLog remote NOTICE, WARNING, and similar = messages using ereport()=E2=80=9D, I noticed that = libpqsrv_notice_receiver is only installed after libpqsrv_connect() = finishes. As a result, NOTICE messages generated during connection = establishment are missed by ereport() and are still printed to stderr. >>=20 >> To reproduce the issue, I created a separate database called remotedb = and defined a login trigger that emits a NOTICE message: >> ``` >> CREATE DATABASE remotedb; >>=20 >> \c remotedb >>=20 >> CREATE OR REPLACE FUNCTION repro_login_notice() >> RETURNS event_trigger >> LANGUAGE plpgsql AS $$ >> BEGIN >> RAISE NOTICE 'startup notice from remotedb login trigger'; >> END; >> $$; >>=20 >> CREATE EVENT TRIGGER repro_login_notice_trg >> ON login >> EXECUTE FUNCTION repro_login_notice(); >>=20 >> ALTER EVENT TRIGGER repro_login_notice_trg ENABLE ALWAYS; >> ``` >>=20 >> Then, from another database: >> ``` >> evantest=3D# create extension dblink; >> CREATE EXTENSION >> evantest=3D# SELECT dblink_connect('host=3D127.0.0.1 port=3D5432 = dbname=3Dremotedb user=3Dchaol sslmode=3Ddisable gssencmode=3Ddisable'); >> dblink_connect >> ---------------- >> OK >> (1 row) >> ``` >>=20 >> In the system log, the NOTICE message is printed directly: >> ``` >> 2026-05-20 13:02:19.350 CST [24909] STATEMENT: SELECT = dblink_connect('host=3D127.0.0.1 port=3D5432 dbname=3Dremotedb = user=3Dchaol sslmode=3Ddisable gssencmode=3Ddisable'); >> NOTICE: startup notice from remotedb login trigger >> ``` >>=20 >> To fix that, I think we should install libpqsrv_notice_receiver = before libpqsrv_connect_internal(). In the attached patch, I added two = helpers: libpqsrv_connect_with_notice_receiver() and = libpqsrv_connect_params_with_notice_receiver(). >>=20 >> With the fix, the NOTICE message now looks like this: >> ``` >> 2026-05-20 14:44:49.296 CST [45567] LOG: received message via remote = connection: NOTICE: startup notice from remotedb login trigger >> 2026-05-20 14:44:49.296 CST [45567] STATEMENT: SELECT = dblink_connect('host=3D127.0.0.1 port=3D5432 dbname=3Dremotedb = user=3Dchaol sslmode=3Ddisable gssencmode=3Ddisable'); >> ``` >>=20 >> Please see the attached patch for details. >=20 > Thanks for the report and patch! >=20 > I'd prefer to avoid adding notice-receiver-specific wrappers such as > libpqsrv_connect_with_notice_receiver(). Instead, how about splitting > libpqsrv_connect() into two steps: libpqsrv_connect_start(), which = performs > libpqsrv_connect_prepare() and PQconnectStart(), and > libpqsrv_connect_complete(), which runs libpqsrv_connect_internal()? >=20 > With this approach, callers could invoke PQsetNoticeReceiver() after > libpqsrv_connect_start() returns but before = libpqsrv_connect_complete() is > called. This would allow startup-time notices to be handled correctly = without > introducing a dedicated wrapper function. >=20 > Compared to the *_with_notice_receiver() approach, this design is more > general because it exposes the phase between PQconnectStart() and = connection > completion. It could also support other kinds of per-connection setup = in the > future, not just notice receiver installation. Thought? >=20 > Regards, >=20 > --=20 > Fujii Masao The idea sounds good to me, so v2 is implemented following that idea. A few things I want to point out abut v2: * Since libpqsrv_connect_complete() would only wrap = libpqsrv_connect_internal(), I just renamed libpqsrv_connect_internal() = to libpqsrv_connect_complete(). * Since libpqsrv_connect() is now split into two phases, = libpqsrv_connect_complete() must be called even if conn is NULL, because = it may need to call ReleaseExternalFD(). I mentioned this in the header = comment of libpqsrv_connect_start(). * In the postgres_fdw/connection.c change, I introduced a new local = variable, start_conn, to keep the original logic unchanged. Because = there is a PG_TRY/PG_CATCH block, conn is assigned only after = libpqsrv_connect_complete() finishes successfully. Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_81EE1C7E-88DC-4FCA-B452-3ED497E52E7C Content-Disposition: attachment; filename=v2-0001-Set-notice-receiver-before-libpq-connection-start.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0001-Set-notice-receiver-before-libpq-connection-start.patch" Content-Transfer-Encoding: quoted-printable =46rom=20f90baaca93f34cefbe829396fc532d7b04d35729=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Wed,=2020=20May=202026=2014:57:25=20+0800=0ASubject:=20[PATCH=20= v2]=20Set=20notice=20receiver=20before=20libpq=20connection=20startup=0A=0A= libpqsrv_connect()=20and=20libpqsrv_connect_params()=20complete=20the=20= libpq=0Aconnection=20startup=20before=20returning=20the=20PGconn.=20=20= As=20a=20result,=20callers=20that=0Ainstall=20a=20notice=20receiver=20= after=20these=20functions=20return=20can=20miss=20NOTICE,=0AWARNING,=20= and=20similar=20messages=20emitted=20during=20connection=20= establishment.=0A=0ASplit=20the=20connection=20helper=20API=20into=20= start=20and=20complete=20steps,=20so=20callers=0Acan=20install=20= per-connection=20setup=20such=20as=20notice=20receivers=20after=0A= PQconnectStart()=20returns=20but=20before=20the=20startup=20sequence=20= is=20completed.=0A=0ADocument=20the=20resource-lifetime=20rule=20for=20= the=20split=20API:=20callers=20must=20either=0Acall=20= libpqsrv_connect_complete(),=20even=20when=20the=20start=20function=20= returns=20NULL,=0Aor=20otherwise=20clean=20up=20the=20partially-started=20= connection=20and=20release=20the=0Areserved=20external=20FD=20if=20an=20= error=20is=20thrown=20before=20completion.=0A=0AAuthor:=20Chao=20Li=20= =0AReviewed-by:=20Fujii=20Masao=20= =0ADiscussion:=20= https://postgr.es/m/A2B8B7DE-C119-492F-A9FA-14CF86849777@gmail.com=0A---=0A= =20contrib/dblink/dblink.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20|=2018=20++---=0A=20= contrib/postgres_fdw/connection.c=20=20=20=20=20=20=20=20=20=20=20=20=20= |=2014=20++--=0A=20.../libpqwalreceiver/libpqwalreceiver.c=20=20=20=20=20= =20=20|=2013=20++--=0A=20src/include/libpq/libpq-be-fe-helpers.h=20=20=20= =20=20=20=20|=2069=20+++++++++++++++----=0A=204=20files=20changed,=2079=20= insertions(+),=2035=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/dblink/dblink.c=20b/contrib/dblink/dblink.c=0Aindex=20= d843eee7e97..0751df9e444=20100644=0A---=20a/contrib/dblink/dblink.c=0A= +++=20b/contrib/dblink/dblink.c=0A@@=20-222,7=20+222,11=20@@=20= dblink_get_conn(char=20*conname_or_str,=0A=20=09=09=09dblink_we_get_conn=20= =3D=20WaitEventExtensionNew("DblinkGetConnect");=0A=20=0A=20=09=09/*=20= OK=20to=20make=20connection=20*/=0A-=09=09conn=20=3D=20= libpqsrv_connect(connstr,=20dblink_we_get_conn);=0A+=09=09conn=20=3D=20= libpqsrv_connect_start(connstr);=0A+=09=09if=20(conn=20!=3D=20NULL)=0A+=09= =09=09PQsetNoticeReceiver(conn,=20libpqsrv_notice_receiver,=0A+=09=09=09=09= =09=09=09=09"received=20message=20via=20remote=20connection");=0A+=09=09= libpqsrv_connect_complete(conn,=20dblink_we_get_conn);=0A=20=0A=20=09=09= if=20(PQstatus(conn)=20=3D=3D=20CONNECTION_BAD)=0A=20=09=09{=0A@@=20= -235,9=20+239,6=20@@=20dblink_get_conn(char=20*conname_or_str,=0A=20=09=09= =09=09=09=20errdetail_internal("%s",=20msg)));=0A=20=09=09}=0A=20=0A-=09=09= PQsetNoticeReceiver(conn,=20libpqsrv_notice_receiver,=0A-=09=09=09=09=09=09= =09"received=20message=20via=20remote=20connection");=0A-=0A=20=09=09= dblink_security_check(conn,=20NULL,=20connstr);=0A=20=09=09if=20= (PQclientEncoding(conn)=20!=3D=20GetDatabaseEncoding())=0A=20=09=09=09= PQsetClientEncoding(conn,=20GetDatabaseEncodingName());=0A@@=20-321,7=20= +322,11=20@@=20dblink_connect(PG_FUNCTION_ARGS)=0A=20=09}=0A=20=0A=20=09= /*=20OK=20to=20make=20connection=20*/=0A-=09conn=20=3D=20= libpqsrv_connect(connstr,=20dblink_we_connect);=0A+=09conn=20=3D=20= libpqsrv_connect_start(connstr);=0A+=09if=20(conn=20!=3D=20NULL)=0A+=09=09= PQsetNoticeReceiver(conn,=20libpqsrv_notice_receiver,=0A+=09=09=09=09=09=09= =09"received=20message=20via=20remote=20connection");=0A+=09= libpqsrv_connect_complete(conn,=20dblink_we_connect);=0A=20=0A=20=09if=20= (PQstatus(conn)=20=3D=3D=20CONNECTION_BAD)=0A=20=09{=0A@@=20-336,9=20= +341,6=20@@=20dblink_connect(PG_FUNCTION_ARGS)=0A=20=09=09=09=09=20= errdetail_internal("%s",=20msg)));=0A=20=09}=0A=20=0A-=09= PQsetNoticeReceiver(conn,=20libpqsrv_notice_receiver,=0A-=09=09=09=09=09=09= "received=20message=20via=20remote=20connection");=0A-=0A=20=09/*=20= check=20password=20actually=20used=20if=20not=20superuser=20*/=0A=20=09= dblink_security_check(conn,=20connname,=20connstr);=0A=20=0Adiff=20--git=20= a/contrib/postgres_fdw/connection.c=20= b/contrib/postgres_fdw/connection.c=0Aindex=203d2a8d0519d..86178ec5fb2=20= 100644=0A---=20a/contrib/postgres_fdw/connection.c=0A+++=20= b/contrib/postgres_fdw/connection.c=0A@@=20-638,6=20+638,7=20@@=20= connect_pg_server(ForeignServer=20*server,=20UserMapping=20*user)=0A=20=09= =09const=20char=20**keywords;=0A=20=09=09const=20char=20**values;=0A=20=09= =09char=09=20=20=20*appname;=0A+=09=09PGconn=09=20=20=20*start_conn;=0A=20= =0A=20=09=09construct_connection_params(server,=20user,=20&keywords,=20= &values,=20&appname);=0A=20=0A@@=20-646,9=20+647,13=20@@=20= connect_pg_server(ForeignServer=20*server,=20UserMapping=20*user)=0A=20=09= =09=09pgfdw_we_connect=20=3D=20= WaitEventExtensionNew("PostgresFdwConnect");=0A=20=0A=20=09=09/*=20OK=20= to=20make=20connection=20*/=0A-=09=09conn=20=3D=20= libpqsrv_connect_params(keywords,=20values,=0A-=09=09=09=09=09=09=09=09=09= =20=20=20false,=09/*=20expand_dbname=20*/=0A-=09=09=09=09=09=09=09=09=09=20= =20=20pgfdw_we_connect);=0A+=09=09start_conn=20=3D=20= libpqsrv_connect_params_start(keywords,=20values,=0A+=09=09=09=09=09=09=09= =09=09=09=09=09=20=20=20/*=20expand_dbname=20=3D=20*/=20false);=0A+=09=09= if=20(start_conn=20!=3D=20NULL)=0A+=09=09=09= PQsetNoticeReceiver(start_conn,=20libpqsrv_notice_receiver,=0A+=09=09=09=09= =09=09=09=09"received=20message=20via=20remote=20connection");=0A+=09=09= libpqsrv_connect_complete(start_conn,=20pgfdw_we_connect);=0A+=09=09conn=20= =3D=20start_conn;=0A=20=0A=20=09=09if=20(!conn=20||=20PQstatus(conn)=20= !=3D=20CONNECTION_OK)=0A=20=09=09=09ereport(ERROR,=0A@@=20-657,9=20= +662,6=20@@=20connect_pg_server(ForeignServer=20*server,=20UserMapping=20= *user)=0A=20=09=09=09=09=09=09=09server->servername),=0A=20=09=09=09=09=09= =20errdetail_internal("%s",=20pchomp(PQerrorMessage(conn)))));=0A=20=0A-=09= =09PQsetNoticeReceiver(conn,=20libpqsrv_notice_receiver,=0A-=09=09=09=09=09= =09=09"received=20message=20via=20remote=20connection");=0A-=0A=20=09=09= /*=20Perform=20post-connection=20security=20checks.=20*/=0A=20=09=09= pgfdw_security_check(keywords,=20values,=20user,=20conn);=0A=20=0Adiff=20= --git=20a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c=20= b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c=0Aindex=20= 9f04c9ed25d..af2734cb328=20100644=0A---=20= a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c=0A+++=20= b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c=0A@@=20= -223,9=20+223,13=20@@=20libpqrcv_connect(const=20char=20*conninfo,=20= bool=20replication,=20bool=20logical,=0A=20=0A=20=09conn=20=3D=20= palloc0_object(WalReceiverConn);=0A=20=09conn->streamConn=20=3D=0A-=09=09= libpqsrv_connect_params(keys,=20vals,=0A-=09=09=09=09=09=09=09=09=20/*=20= expand_dbname=20=3D=20*/=20true,=0A-=09=09=09=09=09=09=09=09= WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);=0A+=09=09= libpqsrv_connect_params_start(keys,=20vals,=0A+=09=09=09=09=09=09=09=09=09= =20=20/*=20expand_dbname=20=3D=20*/=20true);=0A+=09if=20= (conn->streamConn=20!=3D=20NULL)=0A+=09=09= PQsetNoticeReceiver(conn->streamConn,=20libpqsrv_notice_receiver,=0A+=09=09= =09=09=09=09=09"received=20message=20via=20replication");=0A+=09= libpqsrv_connect_complete(conn->streamConn,=0A+=09=09=09=09=09=09=09=20=20= WAIT_EVENT_LIBPQWALRECEIVER_CONNECT);=0A=20=0A=20=09if=20(options_val=20= !=3D=20NULL)=0A=20=09=09pfree(options_val);=0A@@=20-245,9=20+249,6=20@@=20= libpqrcv_connect(const=20char=20*conninfo,=20bool=20replication,=20bool=20= logical,=0A=20=09=09=09=09=20errhint("Target=20server's=20authentication=20= method=20must=20be=20changed,=20or=20set=20password_required=3Dfalse=20= in=20the=20subscription=20parameters.")));=0A=20=09}=0A=20=0A-=09= PQsetNoticeReceiver(conn->streamConn,=20libpqsrv_notice_receiver,=0A-=09=09= =09=09=09=09"received=20message=20via=20replication");=0A-=0A=20=09/*=0A=20= =09=20*=20Set=20always-secure=20search=20path=20for=20the=20cases=20= where=20the=20connection=20is=0A=20=09=20*=20used=20to=20run=20SQL=20= queries,=20so=20malicious=20users=20can't=20get=20control.=0Adiff=20= --git=20a/src/include/libpq/libpq-be-fe-helpers.h=20= b/src/include/libpq/libpq-be-fe-helpers.h=0Aindex=20= 85d8b63f019..cd540f82106=20100644=0A---=20= a/src/include/libpq/libpq-be-fe-helpers.h=0A+++=20= b/src/include/libpq/libpq-be-fe-helpers.h=0A@@=20-39,10=20+39,32=20@@=0A=20= =0A=20=0A=20static=20inline=20void=20libpqsrv_connect_prepare(void);=0A= -static=20inline=20void=20libpqsrv_connect_internal(PGconn=20*conn,=20= uint32=20wait_event_info);=0A+static=20inline=20void=20= libpqsrv_connect_complete(PGconn=20*conn,=20uint32=20wait_event_info);=0A= =20static=20inline=20PGresult=20*libpqsrv_get_result_last(PGconn=20= *conn,=20uint32=20wait_event_info);=0A=20static=20inline=20PGresult=20= *libpqsrv_get_result(PGconn=20*conn,=20uint32=20wait_event_info);=0A=20=0A= +/*=0A+=20*=20Start=20a=20connection=20using=20PQconnectStart().=0A+=20*=0A= +=20*=20The=20returned=20connection=20has=20not=20yet=20completed=20its=20= startup=20sequence.=20=20Callers=0A+=20*=20may=20perform=20= per-connection=20setup,=20such=20as=20installing=20a=20notice=20= receiver,=0A+=20*=20before=20calling=20libpqsrv_connect_complete().=0A+=20= *=0A+=20*=20Callers=20must=20call=20libpqsrv_connect_complete(),=20even=20= if=20this=20function=20returns=0A+=20*=20NULL,=20because=20= libpqsrv_connect_prepare()=20may=20already=20have=20reserved=20an=0A+=20= *=20external=20FD=20that=20must=20be=20released.=0A+=20*/=0A+static=20= inline=20PGconn=20*=0A+libpqsrv_connect_start(const=20char=20*conninfo)=0A= +{=0A+=09PGconn=09=20=20=20*conn=20=3D=20NULL;=0A+=0A+=09= libpqsrv_connect_prepare();=0A+=0A+=09conn=20=3D=20= PQconnectStart(conninfo);=0A+=0A+=09return=20conn;=0A+}=0A=20=0A=20/*=0A=20= =20*=20PQconnectdb()=20wrapper=20that=20reserves=20a=20file=20descriptor=20= and=20processes=0A@@=20-54,14=20+76,31=20@@=20static=20inline=20PGresult=20= *libpqsrv_get_result(PGconn=20*conn,=20uint32=20wait_event_info=0A=20=20= */=0A=20static=20inline=20PGconn=20*=0A=20libpqsrv_connect(const=20char=20= *conninfo,=20uint32=20wait_event_info)=0A+{=0A+=09PGconn=09=20=20=20= *conn;=0A+=0A+=09conn=20=3D=20libpqsrv_connect_start(conninfo);=0A+=0A+=09= libpqsrv_connect_complete(conn,=20wait_event_info);=0A+=0A+=09return=20= conn;=0A+}=0A+=0A+/*=0A+=20*=20Start=20a=20connection=20using=20= PQconnectStartParams().=0A+=20*=0A+=20*=20See=20libpqsrv_connect_start()=20= for=20the=20resource-lifetime=20rules.=0A+=20*/=0A+static=20inline=20= PGconn=20*=0A+libpqsrv_connect_params_start(const=20char=20*const=20= *keywords,=0A+=09=09=09=09=09=09=09=20=20const=20char=20*const=20= *values,=0A+=09=09=09=09=09=09=09=20=20int=20expand_dbname)=0A=20{=0A=20=09= PGconn=09=20=20=20*conn=20=3D=20NULL;=0A=20=0A=20=09= libpqsrv_connect_prepare();=0A=20=0A-=09conn=20=3D=20= PQconnectStart(conninfo);=0A-=0A-=09libpqsrv_connect_internal(conn,=20= wait_event_info);=0A+=09conn=20=3D=20PQconnectStartParams(keywords,=20= values,=20expand_dbname);=0A=20=0A=20=09return=20conn;=0A=20}=0A@@=20= -76,13=20+115,11=20@@=20libpqsrv_connect_params(const=20char=20*const=20= *keywords,=0A=20=09=09=09=09=09=09int=20expand_dbname,=0A=20=09=09=09=09=09= =09uint32=20wait_event_info)=0A=20{=0A-=09PGconn=09=20=20=20*conn=20=3D=20= NULL;=0A+=09PGconn=09=20=20=20*conn;=0A=20=0A-=09= libpqsrv_connect_prepare();=0A-=0A-=09conn=20=3D=20= PQconnectStartParams(keywords,=20values,=20expand_dbname);=0A+=09conn=20= =3D=20libpqsrv_connect_params_start(keywords,=20values,=20= expand_dbname);=0A=20=0A-=09libpqsrv_connect_internal(conn,=20= wait_event_info);=0A+=09libpqsrv_connect_complete(conn,=20= wait_event_info);=0A=20=0A=20=09return=20conn;=0A=20}=0A@@=20-90,8=20= +127,9=20@@=20libpqsrv_connect_params(const=20char=20*const=20*keywords,=0A= =20/*=0A=20=20*=20PQfinish()=20wrapper=20that=20additionally=20releases=20= the=20reserved=20file=20descriptor.=0A=20=20*=0A-=20*=20It=20is=20= allowed=20to=20call=20this=20with=20a=20NULL=20pgconn=20iff=20NULL=20was=20= returned=20by=0A-=20*=20libpqsrv_connect*.=0A+=20*=20It=20is=20allowed=20= to=20call=20this=20with=20NULL=20only=20when=20the=20external=20FD=20= reservation=0A+=20*=20has=20already=20been=20released,=20for=20example=20= after=20calling=0A+=20*=20libpqsrv_connect_complete()=20with=20a=20NULL=20= connection.=0A=20=20*/=0A=20static=20inline=20void=0A=20= libpqsrv_disconnect(PGconn=20*conn)=0A@@=20-101,7=20+139,7=20@@=20= libpqsrv_disconnect(PGconn=20*conn)=0A=20=09=20*=20already=20released=20= it).=20This=20rule=20makes=20it=20easier=20to=20write=20PG_CATCH()=0A=20=09= =20*=20handlers=20for=20this=20facility's=20users.=0A=20=09=20*=0A-=09=20= *=20See=20also=20libpqsrv_connect_internal().=0A+=09=20*=20See=20also=20= libpqsrv_connect_complete().=0A=20=09=20*/=0A=20=09if=20(conn=20=3D=3D=20= NULL)=0A=20=09=09return;=0A@@=20-111,7=20+149,7=20@@=20= libpqsrv_disconnect(PGconn=20*conn)=0A=20}=0A=20=0A=20=0A-/*=20internal=20= helper=20functions=20follow=20*/=0A+/*=20lower-level=20connection=20= helper=20functions=20follow=20*/=0A=20=0A=20=0A=20/*=0A@@=20-144,10=20= +182,11=20@@=20libpqsrv_connect_prepare(void)=0A=20}=0A=20=0A=20/*=0A-=20= *=20Helper=20function=20for=20all=20connection=20establishment=20= functions.=0A+=20*=20Complete=20a=20connection=20started=20by=20= libpqsrv_connect_start()=20or=0A+=20*=20libpqsrv_connect_params_start().=0A= =20=20*/=0A=20static=20inline=20void=0A-libpqsrv_connect_internal(PGconn=20= *conn,=20uint32=20wait_event_info)=0A+libpqsrv_connect_complete(PGconn=20= *conn,=20uint32=20wait_event_info)=0A=20{=0A=20=09/*=0A=20=09=20*=20With=20= conn=20=3D=3D=20NULL=20libpqsrv_disconnect()=20wouldn't=20release=20the=20= FD.=20So=20do=0A--=20=0A2.50.1=20(Apple=20Git-155)=0A=0A= --Apple-Mail=_81EE1C7E-88DC-4FCA-B452-3ED497E52E7C--