Denis Laxalde [Tue, 4 Oct 2022 15:53:26 +0000 (17:53 +0200)]
fix: sync pipeline after implicit BEGIN
Prior to this change, the following code:
with conn.pipeline():
conn.execute("select 'x'").fetchone()
conn.execute("select 'y'")
would produce the following libpq trace:
F 13 Parse "" "BEGIN" 0
F 14 Bind "" "" 0 0 1 0
F 6 Describe P ""
F 9 Execute "" 0
F 18 Parse "" "select 'x'" 0
F 14 Bind "" "" 0 0 1 0
F 6 Describe P ""
F 9 Execute "" 0
F 4 Flush
B 4 ParseComplete
B 4 BindComplete
B 4 NoData
B 10 CommandComplete "BEGIN"
B 4 ParseComplete
B 4 BindComplete
B 33 RowDescription 1 "?column?" NNNN 0 NNNN 65535 -1 0
B 11 DataRow 1 1 'x'
B 13 CommandComplete "SELECT 1"
F 13 Parse "" "BEGIN" 0
F 14 Bind "" "" 0 0 1 0
F 6 Describe P ""
F 9 Execute "" 0
F 18 Parse "" "select 'y'" 0
F 14 Bind "" "" 0 0 1 0
F 6 Describe P ""
F 9 Execute "" 0
B 4 ParseComplete
B 4 BindComplete
B 4 NoData
B NN NoticeResponse S "WARNING" V "WARNING" C "25001" M "there is already a transaction in progress" F "SSSS" L "SSSS" R "SSSS" \x00
F 4 Sync
B 10 CommandComplete "BEGIN"
B 4 ParseComplete
B 4 BindComplete
B 33 RowDescription 1 "?column?" NNNN 0 NNNN 65535 -1 0
B 11 DataRow 1 1 'y'
B 13 CommandComplete "SELECT 1"
B 5 ReadyForQuery T
where we can see that the BEGIN statement (due to the connection being
in non-autocommit mode) is emitted twice, as notified by the server.
This is because the transaction state after the implicit BEGIN is not
"correct" (i.e. should be INTRANS, but is IDLE) since the result from
respective statement has not been received yet.
By syncing after the BEGIN, we fetch result from this command thus get
the transaction state INTRANS for following queries. This is similar to
what happens with explicit transaction, by using nested pipelines.
build: fix starting Postgres in macOS build script
The brew command fails with:
Could not enable service: 125: Domain does not support specified action
Error: Failure while executing; `/bin/launchctl enable gui/501/homebrew.mxcl.postgresql@14` exited with 125.
test: allow to trace libpq to STDERR, rename option to --pq-trace
By using STDERR, we get the trace directly in pytest output for failing
tests. Though this requires care when used in combination with
--capture=sys because this would make sys.stderr an in-memory file.
When STDERR is used, we don't insert the header since the test case
identifier will be interleaved already.
fix: also sync nested pipeline when a transaction is active
Upon enter, transaction() checks the in-transaction status to determine
if a BEGIN (when IDLE) or a SAVEPOINT (otherwise) should be inserted.
However, in pipeline mode, if the pipeline is in "implicit transaction"
(i.e. it has no active BEGIN) and statements have been sent, the
in-transaction status might be ACTIVE if those statements have not yet
completed (typically, when results have not been fetched).
By issuing a sync() before entering a nested pipeline (which will happen
when entering transaction(), if already within a pipeline), we force
completion of those statements, and thus get a predictable
in-transaction status before entering the transaction() block.
fix: catch any type of error if ZoneInfo creation fails
OSError would be enough to solve the problem reported in #371. However,
in case of error, Windows C implementation segfaults. I would prefer to
not chase this error just because of weirdness in the tzdata external
library, so let's cast a wider net.
fix: make sure to pass a port number to getaddrinfo
Was passing an empty string by mistake, if no port was specified. Mostly
not a problem, except on some platforms, where it causes an
"unrecognized service" error.
Daniele Varrazzo [Tue, 23 Aug 2022 22:39:40 +0000 (00:39 +0200)]
fix: avoid all uses of PQconn.send_query in pipeline mode
We stopped using it in normal querying because, until libpq 14.4, the
libpq complained about "message type 0x33 arrived from server while
idle" (see #314). But usage remained for internal queries such as BEGIN.
In libpq 14.5, Postgres devs tried to fix the issue... and broke
PQsendQuery altogether :(
Hopefully the issue will be solved in future libpq versions, but we can
work around it completely.
Daniele Varrazzo [Mon, 15 Aug 2022 00:46:19 +0000 (02:46 +0200)]
fix(psycopg_c): guard PQflush calls for invalid connections
Unlike other libpq functions, PQflush() doesn't have a guard for invalid
connections and will segfault if the connection gets closed.
Also check the return value of the PQflush calls: as we are not using
the wrapped version pgconn.flush(), the function doesn't automatically
throw an exception on failure.
Daniele Varrazzo [Fri, 12 Aug 2022 23:35:41 +0000 (01:35 +0200)]
ci: specify non-editable install in tox tests
Work around tox-dev/tox#2479 (editable installs in tox broken by setuptools
v64) and tox-dev/tox#2480 (failure to use `toxinidir` in `deps`).
Use -e consistently in the linting steps instead, because they are
defined with skip_install=True so it seems a good idea to use it. These
steps don't seem affect by the setuptools issue.