Daniele Varrazzo [Sun, 14 Feb 2021 01:22:20 +0000 (02:22 +0100)]
Add connection pool close()
When the pool is closed, raise an exception in the thread of the clients
already waiting and refuse new requests. Let the current request finish
anyway.
Daniele Varrazzo [Sat, 13 Feb 2021 23:45:50 +0000 (00:45 +0100)]
Make sure the pool can be deleted with no warning
Make sure to delete reference loops between the pool and the maintenance
tasks after they have run.
Do not raise a warning if a connection in a pool is deleted without
being closed as this is a normal condition (imagining a pool being
created as a global object).
Daniele Varrazzo [Sun, 21 Feb 2021 01:16:28 +0000 (02:16 +0100)]
Fix return error without exception on PQsocket call of broken connection
Still some weirdness here around: the method raises an exception on my
box (both with unix and tcp socket) but it seems to raise still a valid
number on certain databases on Travis. Make sure, in the test, at least
that it is a reasonable value.
Daniele Varrazzo [Wed, 24 Feb 2021 14:23:23 +0000 (15:23 +0100)]
Make the row_maker non-optional
Use the `tuple` type as return value for `tuple_row()`, which has a
valid interface and can also be used in the Cython code to fast-path the
case where the tuples created internally are good enough.
Daniele Varrazzo [Wed, 24 Feb 2021 02:05:15 +0000 (03:05 +0100)]
Make the row_factory attribute non-nullable
Added a `tuple_row()` factory for completeness. Note that it returns None, not
a callable, and the row_maker on the Transformer hasn't changed. The
signature of RowFactory now allows that.
This
makes simpler to specify the row_factory option on `conn.cursor()`: None
means default (the connection `row_factory`), specifying `tuple_row()`
overrides it to the normal tuplish behaviour.
Denis Laxalde [Fri, 12 Feb 2021 09:31:30 +0000 (10:31 +0100)]
Add row_factory as connection attribute and connect argument
When passing 'row_factory' to connect(), respective attribute will be
set on the connection instance. This will be used as default at cursor
creation and can be overridden with conn.cursor(row_factory=...) or
conn.execute(row_factory=...).
We use a '_null_row_factory' marker to handle None-value passed to
.cursor() or .execute() for disabling the default row factory.
Daniele Varrazzo [Fri, 12 Feb 2021 02:21:35 +0000 (03:21 +0100)]
Set up row maker and loaders only once in a server-side cursor lifetime
It wasn't happening once per movement, as I was fearing, but it was happening
exactly twice: once on DECLARE, once on describe_portal(). We actually
don't care about the DECLARE result: it was being set on the cursor only
to detect errors, so now that's done manually.
Daniele Varrazzo [Fri, 12 Feb 2021 01:23:16 +0000 (02:23 +0100)]
Don't recalculate loaders when not needed
The case it's not needed is when the new result is guaranteed to have
the same fields as the previous one. This happens querying in single-row
mode and on server-side cursors fetch.
Denis Laxalde [Thu, 11 Feb 2021 11:22:32 +0000 (12:22 +0100)]
Move the row maker as a Transformer attribute
Instead of carrying the row maker (_make_row attribute) on the cursor
and possibly calling it to transform each row in cursor methods, we
define a 'make_row' attribute on Transformer that is possibly used in
load_row() and load_rows().
In the Python implementation of Transformer.load_rows(), we use tuple as
as make_row() when the attribute is unset.
In the Cython implementation, we make 'make_row' a plain property with a
'_make_row' attribute under the hood. We finally transform individual or
list of records using self.make_row().
Denis Laxalde [Thu, 11 Feb 2021 15:15:23 +0000 (16:15 +0100)]
Use no row factory in TypeInfo.fetch*()
TypeInfo.fetch() and TypeInfo.fetch_async() delegate results processing
to TypeInfo._fetch() which only handle results as tuples. Therefore, we
build the cursor with no row factory to guarantee this. Still we need to
add a type hint on 'recs' variable because this cannot be inferred (this
fixes the mypy error introduced in previous commits).
Denis Laxalde [Wed, 10 Feb 2021 16:58:42 +0000 (17:58 +0100)]
Make row factory optional
We change the default value of row_factory argument in
connection.cursor() to None and thus use a keyword argument.
On cursor side, we only set the '_make_row' attribute if a 'row_factory'
got passed and we guard all possible calls to _make_row() by an
'if self._make_row' to avoid a Python call per row. Note that, on the
other hand, we now need to cast 'row' values to the 'Row' type in order
to satisfy type checking.
The default_row_factory() is now useless and thus dropped.
Denis Laxalde [Tue, 9 Feb 2021 15:51:11 +0000 (16:51 +0100)]
Introduce row_factory option in connection.cursor()
We add a row_factory keyword argument in connection.cursor() and cursor
classes that will be used to produce individual rows of the result set.
A RowFactory can be implemented as a class with a __call__ method
accepting raw values and initialized with a cursor instance; the
RowFactory instance is created when results are available. Type
definitions for RowFactory (and its respective RowMaker) are defined as
callback protocols so as to allow user to define a row factory without
the need for writing a class.