From: Daniele Varrazzo Date: Fri, 25 Dec 2020 02:10:47 +0000 (+0100) Subject: Added documentation for prepared statements X-Git-Tag: 3.0.dev0~253^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=66490c0db7a44ef8c9feb771bfc0655cf498d5d5;p=thirdparty%2Fpsycopg.git Added documentation for prepared statements --- diff --git a/docs/advanced/index.rst b/docs/advanced/index.rst index 862731499..d90415d61 100644 --- a/docs/advanced/index.rst +++ b/docs/advanced/index.rst @@ -6,5 +6,6 @@ Advanced topics :caption: Contents: ../adaptation + ../prepared ../copy ../async diff --git a/docs/connection.rst b/docs/connection.rst index 5a7d4befb..d1d325095 100644 --- a/docs/connection.rst +++ b/docs/connection.rst @@ -61,15 +61,23 @@ The `!Connection` class .. note:: You can use :ref:`with conn.cursor(): ...` to close the cursor automatically when the block is exited. - .. automethod:: execute(query: Query, params: Optional[Args]=None) -> Cursor + .. automethod:: execute(query, params=None, prepare=None) -> Cursor - :param query: The query to execute + :param query: The query to execute. :type query: `!str`, `!bytes`, or `sql.Composable` - :param params: The parameters to pass to the query, if any + :param params: The parameters to pass to the query, if any. :type params: Sequence or Mapping + :param prepare: Force (`!True`) or disallow (`!False`) preparation of + the query. By default (`!None`) prepare automatically. See + :ref:`prepared-statements`. + :type prepare: `!bool` - The cursor is what returned calling `cursor()` without parameters. See - :ref:`query-parameters` for all the details about executing queries. + The cursor is what returned calling `cursor()` without parameters. The + parameters are passed to its `~Cursor.execute()` and the cursor is + returned. + + See :ref:`query-parameters` for all the details about executing + queries. .. rubric:: Transaction management methods @@ -125,10 +133,32 @@ The `!Connection` class .. __: https://www.postgresql.org/docs/current/multibyte.html + .. attribute:: info TODO + + .. autoattribute:: prepare_threshold + + Number of times a query is executed before it is prepared. + + If it is set to 0, every query is prepared the first time is executed. + If it is set to `!None`, prepared statements are disabled on the + connection. + + See :ref:`prepared-statements` for details. + + + .. autoattribute:: prepared_max + + Maximum number of prepared statements on the connection. + + If more queries need to be prepared, old ones are deallocated__. + + .. __: https://www.postgresql.org/docs/current/sql-deallocate.html + + .. rubric:: Methods you can use to do something cool .. automethod:: notifies @@ -176,7 +206,7 @@ The `!AsyncConnection` class automatically when the block is exited, but be careful about the async quirkness: see :ref:`async-with` for details. - .. automethod:: execute(query: Query, params: Optional[Args]=None) -> AsyncCursor + .. automethod:: execute(query, params=None, prepare=None) -> AsyncCursor .. automethod:: commit .. automethod:: rollback diff --git a/docs/cursor.rst b/docs/cursor.rst index 04cfea7ef..3dce83733 100644 --- a/docs/cursor.rst +++ b/docs/cursor.rst @@ -46,12 +46,15 @@ The `!Cursor` class .. rubric:: Methods to send commands - .. automethod:: execute(query: Query, params: Optional[Args]=None) -> Cursor + .. automethod:: execute(query, params=None, prepare=None) -> Cursor - :param query: The query to execute + :param query: The query to execute. :type query: `!str`, `!bytes`, or `sql.Composable` - :param params: The parameters to pass to the query, if any + :param params: The parameters to pass to the query, if any. :type params: Sequence or Mapping + :param prepare: Force (`!True`) or disallow (`!False`) preparation of + the query. By default (`!None`) prepare automatically. See + :ref:`prepared-statements`. Return the cursor itself, so that it will be possible to chain a fetch operation after the call. @@ -144,7 +147,7 @@ The `!AsyncCursor` class automatically when the block is exited, but be careful about the async quirkness: see :ref:`async-with` for details. - .. automethod:: execute(query: Query, params: Optional[Args]=None) -> AsyncCursor + .. automethod:: execute(query, params=None, prepare=None) -> AsyncCursor .. automethod:: executemany(query: Query, params_seq: Sequence[Args]) .. automethod:: copy(statement: Query) -> AsyncCopy diff --git a/docs/index.rst b/docs/index.rst index b3eabb42c..d6f2132b3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,4 +37,3 @@ Indices and tables * :ref:`genindex` * :ref:`modindex` -* :ref:`search` diff --git a/docs/lib/pg3_docs.py b/docs/lib/pg3_docs.py index e028e98af..6dc56301b 100644 --- a/docs/lib/pg3_docs.py +++ b/docs/lib/pg3_docs.py @@ -72,16 +72,23 @@ def monkeypatch_autodoc(): """ Patch autodoc in order to use information found by `recover_defined_module`. """ - from sphinx.ext.autodoc import Documenter + from sphinx.ext.autodoc import Documenter, AttributeDocumenter - orig_get_real_modname = Documenter.get_real_modname + orig_doc_get_real_modname = Documenter.get_real_modname + orig_attr_get_real_modname = AttributeDocumenter.get_real_modname - def fixed_get_real_modname(self): + def fixed_doc_get_real_modname(self): if self.object in recovered_classes: return recovered_classes[self.object] - return orig_get_real_modname(self) + return orig_doc_get_real_modname(self) - Documenter.get_real_modname = fixed_get_real_modname + def fixed_attr_get_real_modname(self): + if self.parent in recovered_classes: + return recovered_classes[self.parent] + return orig_attr_get_real_modname(self) + + Documenter.get_real_modname = fixed_doc_get_real_modname + AttributeDocumenter.get_real_modname = fixed_attr_get_real_modname def walk_modules(d): diff --git a/docs/prepared.rst b/docs/prepared.rst new file mode 100644 index 000000000..3ef0c8f1b --- /dev/null +++ b/docs/prepared.rst @@ -0,0 +1,45 @@ +.. currentmodule:: psycopg3 + +.. index:: + single: Prepared statements + +.. _prepared-statements: + +Prepared statements +=================== + +`!psycopg3` uses an automatic system to manage *prepared statements*. When a +query is prepared, its parsing and planning is stored in the server session, +so that further executions of the same query on the same connection (even with +different parameters) are optimised. + +A query is prepared automatically after it is executed more than +`~Connection.prepare_threshold` times on a connection. `!psycopg3` will make +sure that no more than `~Connection.prepared_max` statements are planned: if +further queries are executed, the least recently used ones are deallocated and +the associated resources freed. + +Statement preparation can be controlled in several ways: + +- You can decide to prepare a query immediately by passing ``prepare=True`` to + `Connection.execute()` or `Cursor.execute()`. The query is prepared, if it + wasn't already, and executed as prepared from its first use. + +- Conversely, passing ``prepare=False`` to `!execute()` will avoid to prepare + the query, regardless of the number of times it is executed. The default of + the parameter is `!None`, meaning that the query is prepared if the + conditions described above are met. + +- You can disable the use of prepared statements on a connection by setting + its `~Connection.prepare_threshold` attribute to `!None`. + +.. seealso:: + + The `PREPARE`__ PostgreSQL documentation contains plenty of details about + prepared statements in PostgreSQL. + + Note however that `!psycopg3` doesn't use SQL statements such as + :sql:`PREPARE` and :sql:`EXECUTE`, but protocol level commands such as the + ones exposed by :pq:`PQsendPrepare`, :pq:`PQsendQueryPrepared`. + + .. __: https://www.postgresql.org/docs/current/sql-prepare.html diff --git a/psycopg3/psycopg3/connection.py b/psycopg3/psycopg3/connection.py index 60a05a474..b41e93f9b 100644 --- a/psycopg3/psycopg3/connection.py +++ b/psycopg3/psycopg3/connection.py @@ -102,19 +102,11 @@ class BaseConnection: cursor_factory: Type["BaseCursor[Any]"] + # Number of times a query is executed before it is prepared. prepare_threshold: Optional[int] = 5 - """ - Number of times a query is executed before it is prepared. - - `!None` to disable preparing queries automatically. - """ + # Maximum number of prepared statements on the connection. prepared_max = 100 - """ - Maximum number of prepared statements on the connection. - - If more are prepared, the least used are deallocated. - """ def __init__(self, pgconn: "PGconn"): self.pgconn = pgconn # TODO: document this