]> git.ipfire.org Git - thirdparty/psycopg.git/log
thirdparty/psycopg.git
3 years agodocs: mention that conn.pipeline() yields a Pipeline object 295/head
Denis Laxalde [Sat, 7 May 2022 15:49:43 +0000 (17:49 +0200)] 
docs: mention that conn.pipeline() yields a Pipeline object

While reading the section, it is otherwise not obvious to understand
where to get the Pipeline object from.

3 years agodocs: add note about implicit transactions and sync in pipeline mode
Daniele Varrazzo [Sat, 7 May 2022 15:29:25 +0000 (17:29 +0200)] 
docs: add note about implicit transactions and sync in pipeline mode

3 years agodocs: split/reshuffle pipeline docs
Daniele Varrazzo [Sat, 7 May 2022 14:54:51 +0000 (16:54 +0200)] 
docs: split/reshuffle pipeline docs

- Postgres concept
- Psycopg usage
- detail about sync points
- disclaimer - don't call the semver police.

3 years agodocs: document that now rollback issues a sync point
Daniele Varrazzo [Sat, 7 May 2022 14:53:34 +0000 (16:53 +0200)] 
docs: document that now rollback issues a sync point

3 years agodocs: add warning disclaimer about pipeline mode
Daniele Varrazzo [Sat, 7 May 2022 14:21:07 +0000 (16:21 +0200)] 
docs: add warning disclaimer about pipeline mode

3 years agodocs: clarify flush and sync pipeline operations
Denis Laxalde [Sun, 3 Apr 2022 19:59:55 +0000 (21:59 +0200)] 
docs: clarify flush and sync pipeline operations

3 years agodocs: fix pipeline docs typos
Daniele Varrazzo [Sun, 3 Apr 2022 18:37:44 +0000 (20:37 +0200)] 
docs: fix pipeline docs typos

3 years agodocs: add note about features not supported in pipeline mode
Daniele Varrazzo [Sun, 3 Apr 2022 00:25:55 +0000 (02:25 +0200)] 
docs: add note about features not supported in pipeline mode

3 years agodocs: add first cut of pipeline mode docs
Daniele Varrazzo [Sat, 2 Apr 2022 22:55:18 +0000 (00:55 +0200)] 
docs: add first cut of pipeline mode docs

3 years agofix: sync pipeline state on rollback 267/head
Daniele Varrazzo [Mon, 4 Apr 2022 01:41:49 +0000 (03:41 +0200)] 
fix: sync pipeline state on rollback

3 years agoMerge branch 'pipeline-sync-no-fetch'
Daniele Varrazzo [Sat, 7 May 2022 13:12:56 +0000 (15:12 +0200)] 
Merge branch 'pipeline-sync-no-fetch'

3 years agofeat: only Sync nested pipelines at exit 269/head
Denis Laxalde [Wed, 6 Apr 2022 18:01:53 +0000 (20:01 +0200)] 
feat: only Sync nested pipelines at exit

It's not needed to force a results fetch when exiting a nested pipeline
as this would naturally happen either later in the outer pipeline or
eventually at the end of the outermost one. Rather, just do a Sync, as
it allows outer pipeline to resume normal execution in case the inner
one got into aborted state.

3 years agofix: only request a pipeline flush in returning executemany()
Denis Laxalde [Mon, 4 Apr 2022 15:19:55 +0000 (17:19 +0200)] 
fix: only request a pipeline flush in returning executemany()

A full Sync is not needed as we're only interested in getting results
when returning=True.

3 years agofix: do not fetch in Pipeline.sync()
Denis Laxalde [Mon, 4 Apr 2022 09:41:06 +0000 (11:41 +0200)] 
fix: do not fetch in Pipeline.sync()

During previous refactorings, we made Pipeline.sync() also fetch results
from the server. But this somehow breaks the semantics of the
synchronization point as defined by Postgres because the user might be
interested in emitting Sync message as a way to solely close the current
series of queries in the pipeline: i.e., flush queries from client to
server and reset the pipeline error state. In this respect, the 'fetch'
step should be explicit.

BasePipeline._sync_gen() is changed to only emit a Sync and a new
_exit_gen() method is introduced doing what _sync_gen() previously did.
Accordingly, the warning emitted when calling this _exit_gen() at
pipeline exit is adjusted to say "terminating" instead of "syncing".

3 years agofix: shorten tracebacks on pipeline sync and exit
Daniele Varrazzo [Mon, 4 Apr 2022 00:54:41 +0000 (02:54 +0200)] 
fix: shorten tracebacks on pipeline sync and exit

The details shown are only the communication bowels. So we go from:

    Traceback (most recent call last):
      File "trace.py", line 301, in <module>
        conn.execute("select pg_sleep(0.2)")
      File "/usr/lib/python3.8/contextlib.py", line 120, in __exit__
        next(self.gen)
      File "/home/piro/dev/psycopg3/psycopg/psycopg/connection.py", line 881, in pipeline
        yield pipeline
      File "/home/piro/dev/psycopg3/psycopg/psycopg/_pipeline.py", line 197, in __exit__
        self.sync()
      File "/home/piro/dev/psycopg3/psycopg/psycopg/_pipeline.py", line 183, in sync
        self._conn.wait(self._sync_gen())
      File "/home/piro/dev/psycopg3/psycopg/psycopg/connection.py", line 896, in wait
        return waiting.wait(gen, self.pgconn.socket, timeout=timeout)
      File "/home/piro/dev/psycopg3/psycopg/psycopg/waiting.py", line 237, in wait_epoll
        s = gen.send(ready)
      File "/home/piro/dev/psycopg3/psycopg/psycopg/_pipeline.py", line 92, in _sync_gen
        yield from self._communicate_gen()
      File "/home/piro/dev/psycopg3/psycopg/psycopg/_pipeline.py", line 105, in _communicate_gen
        self._process_results(queued, results)
      File "/home/piro/dev/psycopg3/psycopg/psycopg/_pipeline.py", line 149, in _process_results
        raise e.error_from_result(result, encoding=pgconn_encoding(self.pgconn))
    psycopg.errors.UndefinedColumn: column "foo" does not exist
    LINE 1: select foo
                   ^

to:

    Traceback (most recent call last):
      File "trace.py", line 301, in <module>
        conn.execute("select pg_sleep(0.2)")
      File "/usr/lib/python3.8/contextlib.py", line 120, in __exit__
        next(self.gen)
      File "/home/piro/dev/psycopg3/psycopg/psycopg/connection.py", line 881, in pipeline
        yield pipeline
      File "/home/piro/dev/psycopg3/psycopg/psycopg/_pipeline.py", line 205, in __exit__
        raise exc2.with_traceback(None)
    psycopg.errors.UndefinedColumn: column "foo" does not exist
    LINE 1: select foo
                   ^

which shows much more clearly that the traceback was raised at pipeline
block exit.

3 years agofix: allow to use cancel() on a closed connection
Daniele Varrazzo [Mon, 2 May 2022 00:45:21 +0000 (02:45 +0200)] 
fix: allow to use cancel() on a closed connection

3 years agodocs: add hint about using add_signal_handler() to interrupt async queries
Daniele Varrazzo [Mon, 2 May 2022 00:37:00 +0000 (02:37 +0200)] 
docs: add hint about using add_signal_handler() to interrupt async queries

Courtesy @gjcarneiro, thank you!

3 years agoMerge branch 'fix-286'
Daniele Varrazzo [Mon, 2 May 2022 00:53:32 +0000 (02:53 +0200)] 
Merge branch 'fix-286'

3 years agoperf: avoid unnecessary recvfrom() in cursor.stream()
Daniele Varrazzo [Sun, 1 May 2022 22:56:42 +0000 (00:56 +0200)] 
perf: avoid unnecessary recvfrom() in cursor.stream()

Call PQisBusy() before PQconsumeInput() on fetching results. If not
busy, don't call PQconsumeInput() at all but just go to fetching results
and notifications.

This is especially useful in single-row mode because most of the times
the libpq can produce several results after a single network fetch.
Previously we were calling PQconsumeInput() also when results were
already on the client and there was nothing new to read, which forced
the libpq to run a select() to tell apart a lack of data from an EOF,
see `the grumble`_, and caused the overhead reported in #286.

Close #286.

.. _the grumble: https://github.com/postgres/postgres/blob/ed57cac84d1c5642737dab1e4c4b8cb4f0c4305f/src/interfaces/libpq/fe-misc.c#L681

3 years agotest: add cursor.stream() test for empty result sets
Daniele Varrazzo [Sun, 1 May 2022 20:45:24 +0000 (22:45 +0200)] 
test: add cursor.stream() test for empty result sets

Also add a missing async test for results with no column.

3 years agorefactor: replace an assert with a type: ignore
Daniele Varrazzo [Sun, 1 May 2022 20:44:37 +0000 (22:44 +0200)] 
refactor: replace an assert with a type: ignore

It's not like we give away opcodes for free here.

3 years agorefactor: send only once per stream
Daniele Varrazzo [Sun, 1 May 2022 12:35:02 +0000 (14:35 +0200)] 
refactor: send only once per stream

No need to do it at every row, probably entirely wrong. However this is
not the cause of the slowness reported in #286.

3 years agorefactor: only clean up the wait() timeout if needed
Daniele Varrazzo [Sun, 1 May 2022 12:30:20 +0000 (14:30 +0200)] 
refactor: only clean up the wait() timeout if needed

Often we terminate the iteration at the first item, so no need to select
at all.

3 years agoRe-export from psycopg._cmodule
hauntsaninja [Sun, 1 May 2022 05:44:04 +0000 (23:44 -0600)] 
Re-export from psycopg._cmodule

3 years agotest: fix variable scope in ctrl-c test
Daniele Varrazzo [Sat, 30 Apr 2022 13:18:14 +0000 (15:18 +0200)] 
test: fix variable scope in ctrl-c test

3 years agotest: verify ctrl-c in async mode using get_event_loop
Daniele Varrazzo [Fri, 29 Apr 2022 23:16:02 +0000 (01:16 +0200)] 
test: verify ctrl-c in async mode using get_event_loop

3 years agotest: drop test guard for unsupported Python version
Daniele Varrazzo [Fri, 29 Apr 2022 23:54:04 +0000 (01:54 +0200)] 
test: drop test guard for unsupported Python version

3 years agodocs: document psycopg 3.0.12 released
Daniele Varrazzo [Fri, 29 Apr 2022 22:42:19 +0000 (00:42 +0200)] 
docs: document psycopg 3.0.12 released

3 years agodocs: improvements to the copy docs
Daniele Varrazzo [Fri, 29 Apr 2022 22:28:07 +0000 (00:28 +0200)] 
docs: improvements to the copy docs

3 years agodocs: add example of table copy across server
Daniele Varrazzo [Fri, 29 Apr 2022 22:07:47 +0000 (00:07 +0200)] 
docs: add example of table copy across server

See #285 for a conversation.

3 years agodocs: document that ticket #254 is fixed in 3.0.12
Daniele Varrazzo [Fri, 29 Apr 2022 21:42:20 +0000 (23:42 +0200)] 
docs: document that ticket #254 is fixed in 3.0.12

We can consider this just a bug, not a change of interface. It is
particularly bad because it doesn't allow to pipe a COPY FROM into a
COPY TO.

See https://github.com/psycopg/psycopg/discussions/285#discussioncomment-2663192
for details.

3 years agotest: add tests to verify copy across tables works
Daniele Varrazzo [Fri, 29 Apr 2022 21:39:36 +0000 (23:39 +0200)] 
test: add tests to verify copy across tables works

3 years agodocs: cleanup in types/enums docs
Daniele Varrazzo [Fri, 29 Apr 2022 20:46:31 +0000 (22:46 +0200)] 
docs: cleanup in types/enums docs

3 years agotypo fix
Utsav [Thu, 28 Apr 2022 02:28:23 +0000 (22:28 -0400)] 
typo fix

3 years agoMerge branch 'enum'
Daniele Varrazzo [Fri, 22 Apr 2022 17:14:31 +0000 (19:14 +0200)] 
Merge branch 'enum'

3 years agodocs(enum): typo-fix and rephrase 274/head
Denis Laxalde [Fri, 22 Apr 2022 06:38:40 +0000 (08:38 +0200)] 
docs(enum): typo-fix and rephrase

3 years agodocs(enum): restyle news entry
Daniele Varrazzo [Fri, 22 Apr 2022 01:34:35 +0000 (03:34 +0200)] 
docs(enum): restyle news entry

3 years agofeat(enum): add mapping override to `register_enum()`
Daniele Varrazzo [Fri, 22 Apr 2022 00:48:41 +0000 (02:48 +0200)] 
feat(enum): add mapping override to `register_enum()`

3 years agotest(enum): drop several hundreds of redundant tests
Daniele Varrazzo [Fri, 22 Apr 2022 00:25:40 +0000 (02:25 +0200)] 
test(enum): drop several hundreds of redundant tests

No need to exhaustively test encodings on ascii data or array properties
tested elsewhere.

3 years agorefactor(enum): introduce an explicit dump/load mapping
Daniele Varrazzo [Thu, 21 Apr 2022 14:04:32 +0000 (16:04 +0200)] 
refactor(enum): introduce an explicit dump/load mapping

This will allow mapping customization; it is also slightly faster
because it doesn't require data encoding/decoding.

3 years agofix(enum): raise DataError in case of labels mismatch on load
Daniele Varrazzo [Thu, 21 Apr 2022 08:47:11 +0000 (10:47 +0200)] 
fix(enum): raise DataError in case of labels mismatch on load

A DataError subclass is already raised on mismatch on dump. Be
consistent.

3 years agofix(enum): move `enum` arg of register_enum() as third item
Daniele Varrazzo [Thu, 21 Apr 2022 08:22:44 +0000 (10:22 +0200)] 
fix(enum): move `enum` arg of register_enum() as third item

This is more consistent with the other register_*() functions and allow
a more natural order of arguments if others must be added (e.g.
mapping).

3 years agotest(enum): refactor in order to write enum-specific type
Daniele Varrazzo [Thu, 21 Apr 2022 08:21:18 +0000 (10:21 +0200)] 
test(enum): refactor in order to write enum-specific type

They all get created, tests can choose to use only some of them.

3 years agotest(enum): drop unneeded cursor creation
Daniele Varrazzo [Thu, 21 Apr 2022 01:48:00 +0000 (03:48 +0200)] 
test(enum): drop unneeded cursor creation

3 years agodocs(enum): document the behaviour of unregistered and registered enums
Daniele Varrazzo [Wed, 20 Apr 2022 11:26:57 +0000 (13:26 +0200)] 
docs(enum): document the behaviour of unregistered and registered enums

3 years agotest(enum): add tests to verify the behaviour of unregistered enums
Daniele Varrazzo [Wed, 20 Apr 2022 11:26:37 +0000 (13:26 +0200)] 
test(enum): add tests to verify the behaviour of unregistered enums

3 years agorefactor(enum): rename python_type -> enum, enum_labels -> labels on EnumInfo
Daniele Varrazzo [Mon, 18 Apr 2022 17:23:32 +0000 (19:23 +0200)] 
refactor(enum): rename python_type -> enum, enum_labels -> labels on EnumInfo

The previous name were lifted from the composite adapters. However, that
class would have had a more ambiguous "type" attribute, and "types" for
the fields, hence the decision of using "python_" and "fields_" prefix
to disambiguate.

In the enum adapters context, enum is not ambiguous, so a more natural
name seems preferred.

3 years agofeat(enum): dump enums by keys instead of values
Daniele Varrazzo [Mon, 18 Apr 2022 17:15:35 +0000 (19:15 +0200)] 
feat(enum): dump enums by keys instead of values

This removes the need for enums to be str-based. It also removes the
asymmetry whereby automatically generated enums were *not* string based,
but pure enums.

3 years agorefactor: add conn_encoding function
Daniele Varrazzo [Thu, 21 Apr 2022 13:49:55 +0000 (15:49 +0200)] 
refactor: add conn_encoding function

Simplifies the chore of obtaining an encoding from the connection,
defaulting to utf-8 if not available.

3 years agotest(enum): add test to verify enums work with sql_ascii connections
Daniele Varrazzo [Sun, 17 Apr 2022 22:52:27 +0000 (00:52 +0200)] 
test(enum): add test to verify enums work with sql_ascii connections

3 years agotest(enum): typo fixed
Daniele Varrazzo [Sun, 17 Apr 2022 22:45:44 +0000 (00:45 +0200)] 
test(enum): typo fixed

3 years agotest(enum): more idiomatic sql composition
Daniele Varrazzo [Sun, 17 Apr 2022 22:44:43 +0000 (00:44 +0200)] 
test(enum): more idiomatic sql composition

3 years agotest(enum): disable Enum random testing
Daniele Varrazzo [Fri, 15 Apr 2022 05:33:12 +0000 (07:33 +0200)] 
test(enum): disable Enum random testing

3 years agotest(enum): added async tests from enums
Vladimir Osokin [Thu, 14 Apr 2022 11:03:26 +0000 (16:03 +0500)] 
test(enum): added async tests from enums

3 years agorefactor(enum): removed redundant `EnumDumper.dump` method override
Vladimir Osokin [Thu, 14 Apr 2022 10:49:09 +0000 (15:49 +0500)] 
refactor(enum): removed redundant `EnumDumper.dump` method override

3 years agofix(enum): code review fixes
Vladimir Osokin [Thu, 14 Apr 2022 10:37:56 +0000 (15:37 +0500)] 
fix(enum): code review fixes

* moved documentation to `docs/basic/adapt.rst`;
* use encoding in `EnumLoader`;
* oid-based dumpers;
* rewritten tests;
* minor fixes.

3 years agotest(enum): add failing tests to illustrate enum needed improvements
Daniele Varrazzo [Thu, 14 Apr 2022 01:08:59 +0000 (03:08 +0200)] 
test(enum): add failing tests to illustrate enum needed improvements

3 years agofeat: add enum support
Vladimir Osokin [Wed, 13 Apr 2022 11:49:14 +0000 (16:49 +0500)] 
feat: add enum support

3 years agofix: fix dumping int enums in text mode, python implementation
Daniele Varrazzo [Thu, 21 Apr 2022 01:29:05 +0000 (03:29 +0200)] 
fix: fix dumping int enums in text mode, python implementation

The error was hidden by a broken test, failing to test the text mode.

3 years agodocs: a few clarifications about composite adaptation
Daniele Varrazzo [Tue, 12 Apr 2022 22:22:04 +0000 (00:22 +0200)] 
docs: a few clarifications about composite adaptation

3 years agofix: drop debug logging left over
Daniele Varrazzo [Thu, 7 Apr 2022 17:57:07 +0000 (19:57 +0200)] 
fix: drop debug logging left over

3 years agodoc: add PipelineStatus to 'pq' page
Denis Laxalde [Mon, 4 Apr 2022 06:39:36 +0000 (08:39 +0200)] 
doc: add PipelineStatus to 'pq' page

3 years agofeat: add ConnectionInfo.pipeline_status
Daniele Varrazzo [Sun, 3 Apr 2022 21:33:55 +0000 (23:33 +0200)] 
feat: add ConnectionInfo.pipeline_status

3 years agodocs: clean up a couple of sentences
Daniele Varrazzo [Sun, 3 Apr 2022 23:26:42 +0000 (01:26 +0200)] 
docs: clean up a couple of sentences

- New version scheme is "starting from PG 10", not "after PG 10" (also,
  chunky bit moved from docstring to docs as for most other docs).
- The transaction status is of the session, not the server.

3 years agoMerge branch 'executemany-pipeline'
Daniele Varrazzo [Sat, 2 Apr 2022 23:23:30 +0000 (01:23 +0200)] 
Merge branch 'executemany-pipeline'

3 years agofeat: add PipelineAborted exception 260/head
Daniele Varrazzo [Sat, 2 Apr 2022 23:06:17 +0000 (01:06 +0200)] 
feat: add PipelineAborted exception

It is a condition that likely will have to be managed, so let's not
clobber it with other OperationalError.

3 years agofix: don't fail assert if fetching without result in pipeline mode
Daniele Varrazzo [Sat, 2 Apr 2022 01:44:26 +0000 (03:44 +0200)] 
fix: don't fail assert if fetching without result in pipeline mode

The error can be triggered easily by the user. The condition is handled
just naturally by all the methods calling _fetch_pipeline().

3 years agofix: consistent sync/exit and error management in pipeline contexts
Daniele Varrazzo [Tue, 29 Mar 2022 23:57:06 +0000 (01:57 +0200)] 
fix: consistent sync/exit and error management in pipeline contexts

Don't clobber an exception on exit of the nested block too. In order to
simplify the code, make the pipeline count the number of time it is
entered, and call _exit() only the last time it exits.

Drop assert that we have left pipeline mode leaving the block. If we get
in unrecoverable state, we will have not. By now we should probably just
close the connection; however, leaving it this way is a better
indication that the connection is broken because of something about
pipeline mode; closing it would hide it, and even if we raised a
warning, it would be much easier to miss it than to miss the exceptions
raised in broken state.

3 years agofix: forbid COPY in pipeline mode
Daniele Varrazzo [Tue, 29 Mar 2022 23:54:56 +0000 (01:54 +0200)] 
fix: forbid COPY in pipeline mode

COPY is not supported. Attempting it puts the connection in
unrecoverable state, with pipeline sync failing and pipeline exit
complaining that there are still results. So let's try to not get in
that state.

3 years agofix: restore sending a Sync on block exit but not on executemany end
Daniele Varrazzo [Tue, 29 Mar 2022 20:03:49 +0000 (22:03 +0200)] 
fix: restore sending a Sync on block exit but not on executemany end

It was removed a few commits ago, but as Denis suggests, it makes sense
to keep it. Reintroduce it (and test for it), but make sure executemany
doesn't send extra sync.

3 years agotest: add test to verify the number of roundtrips in pipelined executemany
Daniele Varrazzo [Tue, 29 Mar 2022 19:36:46 +0000 (21:36 +0200)] 
test: add test to verify the number of roundtrips in pipelined executemany

Add fixture to access the trace data as Python object. I think it's cute <3

3 years agotest: add fixture to write tests based on libpq trace data
Daniele Varrazzo [Tue, 29 Mar 2022 19:35:48 +0000 (21:35 +0200)] 
test: add fixture to write tests based on libpq trace data

3 years agofix: make no-tuple results available after executemany returning
Daniele Varrazzo [Tue, 29 Mar 2022 12:29:11 +0000 (14:29 +0200)] 
fix: make no-tuple results available after executemany returning

There could be useful info there, if the user asks for it. Now this
doesn't slow down the happy execute path, because the default of
returning is False.

3 years agofix: only flush the pipeline after executemany if returning
Daniele Varrazzo [Tue, 29 Mar 2022 12:26:26 +0000 (14:26 +0200)] 
fix: only flush the pipeline after executemany if returning

This has the side effect of breaking rowcount, as before, but can send
many executemany in the same pipeline.

`rowcount` is correct if `returning=True` is set instead, which is a
thing we can at least document, and makes sense: "if you want a result,
you flush the pipeline, dude".

3 years agorefactor: rename pipeline.communicate() -> sync()
Daniele Varrazzo [Tue, 29 Mar 2022 12:21:03 +0000 (14:21 +0200)] 
refactor: rename pipeline.communicate() -> sync()

This has the async/sync interface, is is more apt to expose it as public
interface to say "call this to restore the state" (as the changed tests
does).

Expose the try/finally logic behind sync() as the _sync_gen() method,
which can be useful to call if sync has to be performed inside a lock.

3 years agofix: keep Cursor._execmany_returning set until reset
Denis Laxalde [Tue, 29 Mar 2022 07:44:35 +0000 (09:44 +0200)] 
fix: keep Cursor._execmany_returning set until reset

Cursor's _execmany_returning attribute is now initialized at _reset()
and set during _executemany_gen_pipeline(). This way, the attribute is
kept for further results fetch that may occur outside executemany()
context: namely, this is needed because _execmany_returning is used by
_set_results_from_pipeline() which would be called by fetch*() methods.

As a consequence, in _fetch_pipeline(), actual fetch is skipped when
coming from executemany(..., returning=False) as the pgresult would
never be set. This ensures a consistent behavior by raising "no result
available" when calling fetch*() from a non-returning executemany().

3 years agofix: sync and fetch nested pipelines when they exit
Denis Laxalde [Tue, 29 Mar 2022 07:07:44 +0000 (09:07 +0200)] 
fix: sync and fetch nested pipelines when they exit

When running a nested pipeline, typically in executemany(), we now call
Pipeline.communicate() at exit similarly to a single (unnested) pipeline
but still keep the surrounding pipeline open (in contrast with unnested
one).

This resolves the issue around rowcount with returning executemany().
Accordingly, we check that rowcount is correct in test_executemany()
pipeline tests and drop the previous xfailed test.

3 years agorefactor: move final pipeline steps into a communicate() method
Denis Laxalde [Tue, 29 Mar 2022 06:53:57 +0000 (08:53 +0200)] 
refactor: move final pipeline steps into a communicate() method

3 years agotest: add missing returning=True to executemany() in pipeline tests
Denis Laxalde [Tue, 29 Mar 2022 07:00:07 +0000 (09:00 +0200)] 
test: add missing returning=True to executemany() in pipeline tests

Query in test_executemany() has a returning clause and we fetch results
from cursor after execution, so it seems the returning option to
executemany() is needed. These tests probably do not fail because of the
TODO in Cursor._set_results_from_pipeline().

3 years agodocs: add news entry about executemany() speedup
Daniele Varrazzo [Mon, 28 Mar 2022 18:07:32 +0000 (20:07 +0200)] 
docs: add news entry about executemany() speedup

3 years agotest: add xfailing test for rowcount in pipelined executemany
Daniele Varrazzo [Mon, 28 Mar 2022 18:03:55 +0000 (20:03 +0200)] 
test: add xfailing test for rowcount in pipelined executemany

3 years agofix: drop unneeded flush after executemany
Daniele Varrazzo [Mon, 28 Mar 2022 16:11:06 +0000 (18:11 +0200)] 
fix: drop unneeded flush after executemany

As per @dlax analysis, it is not needed. It was part of an attempt to
fix the problem of rowcount broken when executemany is called from within
a pipeline block, but that doesn't work anyway.

3 years agofix: fix 'executemany()' when pipeline mode is not available
Daniele Varrazzo [Sun, 27 Mar 2022 17:57:17 +0000 (19:57 +0200)] 
fix: fix 'executemany()' when pipeline mode is not available

3 years agoperf: base executemany on pipeline
Daniele Varrazzo [Sun, 27 Mar 2022 03:55:51 +0000 (05:55 +0200)] 
perf: base executemany on pipeline

This changeset also fix several glitches of executemany() run in
pipeline mode, around the management of returned value and rowcount.
These glitches still appear if executemany() is run in an explicit
pipeline() block, because certain events only happen at (outermost)
pipeline block exit.

Related to: #145.

3 years agoMerge branch 'pipeline4'
Daniele Varrazzo [Sat, 2 Apr 2022 23:22:44 +0000 (01:22 +0200)] 
Merge branch 'pipeline4'

3 years agofix: don't clobber exceptions exiting the pipeline block 175/head
Daniele Varrazzo [Sun, 27 Mar 2022 19:47:11 +0000 (21:47 +0200)] 
fix: don't clobber exceptions exiting the pipeline block

Problem found thanks to random failures in unrelated tests, e.g.
https://github.com/psycopg/psycopg/actions/runs/2048536089

3 years agofeat: add pretty repr to Pipeline objects
Daniele Varrazzo [Sun, 27 Mar 2022 20:04:47 +0000 (22:04 +0200)] 
feat: add pretty repr to Pipeline objects

3 years agofeat: add 'Pipeline.is_supported()'
Daniele Varrazzo [Sun, 27 Mar 2022 17:18:17 +0000 (19:18 +0200)] 
feat: add 'Pipeline.is_supported()'

This makes easier to write conditional code depending on whether we
support pipeline mode or not.

3 years agotest: do not catch OperationalError in test_pipeline_errors_processed_at_exit
Denis Laxalde [Sun, 27 Mar 2022 16:02:53 +0000 (18:02 +0200)] 
test: do not catch OperationalError in test_pipeline_errors_processed_at_exit

Co-authored-by: Daniele Varrazzo <daniele.varrazzo@gmail.com>
3 years agofix: better error on exit of a pipeline with broken connection
Daniele Varrazzo [Sun, 27 Mar 2022 15:35:06 +0000 (17:35 +0200)] 
fix: better error on exit of a pipeline with broken connection

Raise an OperationalError with a message "the connection is closed" rather
than "connection pointer is NULL". The exception class was right already.

3 years agorefactor: move pipeline finalisation code to Pipeline.__exit__
Daniele Varrazzo [Sun, 27 Mar 2022 15:01:11 +0000 (17:01 +0200)] 
refactor: move pipeline finalisation code to Pipeline.__exit__

This code has more internal knowledge of the Pipeline object than the
Connection object.

For some reason I don't understand, had to declare 'command_queue' and
'result_queue' types explicitly to the class definition. Leaving just the
definitions in '__init__()' causes mypy (0.940) to complain in 'cursor.py'.

3 years agotest: add support for using executemany() in pipeline demo
Denis Laxalde [Sun, 27 Mar 2022 12:17:39 +0000 (14:17 +0200)] 
test: add support for using executemany() in pipeline demo

3 years agofeat: let Connection.pipeline() return the Pipeline object
Denis Laxalde [Sun, 27 Mar 2022 10:56:40 +0000 (12:56 +0200)] 
feat: let Connection.pipeline() return the Pipeline object

In tests, add a type annotation on 'conn'/'aconn' fixture so that mypy
understands that pipeline() yields a Pipeline object.

3 years agofix: guard connection._pipeline using the connection lock
Daniele Varrazzo [Sat, 26 Mar 2022 18:02:32 +0000 (19:02 +0100)] 
fix: guard connection._pipeline using the connection lock

3 years agofix: allow re-entering pipeline mode
Daniele Varrazzo [Sat, 26 Mar 2022 17:56:31 +0000 (18:56 +0100)] 
fix: allow re-entering pipeline mode

3 years agorefactor: add and use `Cursor._set_results_from_pipeline()`
Daniele Varrazzo [Sun, 27 Mar 2022 02:48:18 +0000 (04:48 +0200)] 
refactor: add and use `Cursor._set_results_from_pipeline()`

This is a cleaner interface between the cursor and the pipeline.

3 years agorefactor: Pipeline classes moved to their module
Denis Laxalde [Sun, 27 Mar 2022 10:41:56 +0000 (12:41 +0200)] 
refactor: Pipeline classes moved to their module

3 years agotest: add support for trace file to pipeline demo
Daniele Varrazzo [Sat, 26 Mar 2022 17:08:53 +0000 (18:08 +0100)] 
test: add support for trace file to pipeline demo

3 years agoAdd support for pipeline mode in execute()/fetch*()
Denis Laxalde [Mon, 11 Oct 2021 15:16:39 +0000 (17:16 +0200)] 
Add support for pipeline mode in execute()/fetch*()

When activated on the connection, a pipeline active pipeline handles
a queue of commands to send and a queue of results to process.

The command queue simply contains Callable[[], None], which are built
from partial applications of pgconn.send_*() methods et al.

The queue of results to process either contains a None, when respective
command returns no tuple, or a tuple with respective cursor and query
information needed to maintain automatic prepared statement.

Everywhere we run the execute() generator in non-pipeline mode, we now
enqueue items in the pipeline queues. Then we run
pipeline_communicate(), through the _communicate_gen() method of
BasePipeline, in BaseCursor._execute(many)_gen().

Since pipeline_communicate() may not fetch all results, we need a
dedicated fetch (forced) step upon call to cursor.fetch*(); this is done
by Cursor._fetch_pipeline() called in fetch*() methods. This calls
PQsendFlushRequest() in order to avoid blocking on PQgetResult().

At exit of pipeline mode, we unconditionally emit a PQpipelineSync()
call in order to restore the connection in a usable state in case of
error and we force results fetch after sending any pending commands
(e.g. commands not emitted through an execute() call).

The pipeline-demo.py test script is updated to include examples using
the high-level API. This only works with the 'python' of libpq bindings
because we monkeypatch the pgconn attribute of the connection.

3 years agoAvoid multiple commands in transaction code
Denis Laxalde [Thu, 2 Dec 2021 14:13:08 +0000 (15:13 +0100)] 
Avoid multiple commands in transaction code

In pipeline mode, command strings containing multiple SQL commands are
disallowed so we remove all such usages from transaction code.

Accordingly, all generator methods in transaction classes now do not
return anything (the result was not used previously anyways).

In tests, the 'commands' list defined in patch_exec() is now filled by
appending instead of inserting so that we keep the natural order of
commands in assertions.