Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ltSA8-0005tc-Kl for pgsql-hackers@arkaria.postgresql.org; Wed, 16 Jun 2021 09:48:44 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1ltSA7-0004pA-IQ for pgsql-hackers@arkaria.postgresql.org; Wed, 16 Jun 2021 09:48:43 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ltSA7-0004oZ-4J for pgsql-hackers@lists.postgresql.org; Wed, 16 Jun 2021 09:48:43 +0000 Received: from codesynthesis.com ([188.40.148.39]) by magus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1ltSA4-0005PW-KE for pgsql-hackers@lists.postgresql.org; Wed, 16 Jun 2021 09:48:42 +0000 Received: from brak.codesynthesis.com (unknown [105.225.47.95]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by codesynthesis.com (Postfix) with ESMTPSA id 1FB6B5F201; Wed, 16 Jun 2021 09:48:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codesynthesis.com; s=mail1; t=1623836918; bh=ff5GwN2FZLvTjOvj8zQPWicmnt49w9+szM7UZndD3dc=; h=Date:From:To:Subject:Message-ID:MIME-Version:From; b=pZ2zsI54qltNF/ZnaTv2jNKJT9K7+awkr0hA4riD0PytWlhzbVokOE+KXt3oV9UKn FaDvidBnTSOQOm9pQxpBEPk3sLYvEFkFFf1LQxG/6D0J0c24VRkONHY9OZIFDxdesB L3SVjEe4/1QN12xzCzBMXyZ2PHZvO94blzRpEcDKzVOj01Q21G5d/qpe8k9Mhy0sQV HFySQlfoSTBDSW2ML/U8KNpxJoL0YloNtDXbFvtUQccXYgNqED8Pqr7ZPv+NbwOLbT JEZm81DUHqAGUsSO8qxW8HKm2KsLN89UxB/9mxDtSpQNwKC/RG4mSw2u1bPnZSjs3K RiaEFctta6p2w== Received: by brak.codesynthesis.com (Postfix, from userid 1000) id B4AD71A802C0; Wed, 16 Jun 2021 11:48:28 +0200 (SAST) Date: Wed, 16 Jun 2021 11:48:28 +0200 From: Boris Kolpackov To: pgsql-hackers@lists.postgresql.org Cc: alvaro.herrera@2ndquadrant.com Subject: Pipeline mode and PQpipelineSync() Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Organization: Code Synthesis User-Agent: Mutt/1.5.24 (2015-08-30) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk I am trying to add bulk operation support to ODB (a C++ ORM) using the new pipeline mode added to libpq in PostgreSQL 14. However, things don't seem to be working according to the documentation (or perhaps I am misunderstanding something). Specifically, the documentation[1] makes it sound like the use of PQpipelineSync() is optional (34.5.1.1 "Issuing Queries"): "After entering pipeline mode, the application dispatches requests using PQsendQuery, PQsendQueryParams, or its prepared-query sibling PQsendQueryPrepared. These requests are queued on the client-side until flushed to the server; this occurs when PQpipelineSync is used to establish a synchronization point in the pipeline, or when PQflush is called. [...] The server executes statements, and returns results, in the order the client sends them. The server will begin executing the commands in the pipeline immediately, not waiting for the end of the pipeline. [...]" Based on this I expect to be able to queue a single prepared INSERT statement with PQsendQueryPrepared() and then call PQflush() and PQconsumeInput() to send/receive the data. This, however, does not work: the client gets blocked because there is no data to read. Here is the call sequence: select() # socket is writable PQsendQueryPrepared() # success PQflush() # returns 0 (queue is now empty) select() # blocked here indefinitely In contrast, if I add the PQpipelineSync() call after PQsendQueryPrepared(), then everything starts functioning as expected: select() # socket is writable PQsendQueryPrepared() # success PQpipelineSync() # success PQflush() # returns 0 (queue is now empty) select() # socket is readable PQconsumeInput() # success PQgetResult() # INSERT result PQgetResult() # NULL PQgetResult() # PGRES_PIPELINE_SYNC So to me it looks like, contrary to the documentation, the server does not start executing the statements immediately, instead waiting for the synchronization point. Or am I missing something here? The above tests were performed using libpq from 14beta1 running against PostgreSQL server version 9.5. If you would like to take a look at the actual code, you can find it here[2] (the PIPELINE_SYNC macro controls whether PQpipelineSync() is used). On a related note, I've been using libpq_pipeline.c[3] as a reference and I believe it has a busy loop calling PQflush() repeatedly on line 721 since once everything has been sent and we are waiting for the result, select() will keep returning with an indication that the socket is writable (you can find one way to fix this in [2]). [1] https://www.postgresql.org/docs/14/libpq-pipeline-mode.html [2] https://git.codesynthesis.com/cgit/odb/libodb-pgsql/tree/odb/pgsql/statement.cxx?h=bulk#n771 [3] https://doxygen.postgresql.org/libpq__pipeline_8c_source.html