Daniele Varrazzo [Thu, 20 Oct 2022 21:41:03 +0000 (23:41 +0200)]
fix: get element oid from the array itself in binary format
Getting it from the type was causing problems in CRDB because they seem
to have a different interpretation of what Int2 and Int4 are. Refactor
the binary parser to take a transformer, instead of a loader function,
in order to look up the loader from the oid parsed from the array.
Also refactor the text array parser to take the whole loader instead of
the load function only, which will be useful in order to optimize the
use of C loaders.
This implementation can be still improved: we always call the Python
loader to decode the single elements; we can try and call the C loader
if available.
fix(pool): make sure to throw a RuntimeError opening async pool without a loop
The error would be thrown anyway downstream, when tasks are created, but
other spurious warning might be raised too because certain tasks are not
awaited.
lint: fix type hints with disabled bytearray/memoryview/bytes equivalience
This changeset makes the code compatible with the current Mypy 0.981,
but passes most of the checks that Mypy 0.990 enforces if the byte
strings equivalence is disabled.
This change is backward compatible because bytes has a superset of the
memoryview interface and, in Python, to make pretty much any use of it,
it must be converted to bytes beforehand.
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.