]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Added documentation for prepared statements
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Fri, 25 Dec 2020 02:10:47 +0000 (03:10 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Fri, 25 Dec 2020 02:44:47 +0000 (03:44 +0100)
docs/advanced/index.rst
docs/connection.rst
docs/cursor.rst
docs/index.rst
docs/lib/pg3_docs.py
docs/prepared.rst [new file with mode: 0644]
psycopg3/psycopg3/connection.py

index 86273149978ac850d8b8ed788c96bcef7c74fff3..d90415d616d78ad049136b6a8277300d2713cbda 100644 (file)
@@ -6,5 +6,6 @@ Advanced topics
     :caption: Contents:
 
     ../adaptation
+    ../prepared
     ../copy
     ../async
index 5a7d4befbc6cebd3f468839447b181202c41e8f0..d1d325095c14bd2444012a48ce2b940cb97c03a6 100644 (file)
@@ -61,15 +61,23 @@ The `!Connection` class
         .. note:: You can use :ref:`with conn.cursor(): ...<usage>`
             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
 
index 04cfea7ef3ae2d1f7e2a4bb5448f01be074f93bb..3dce837337bd386838fbe195c9ea32ac4e47b844 100644 (file)
@@ -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
 
index b3eabb42cf01de2a58435e858b471aed979a7846..d6f2132b3a831c83d828e1acf44f2dbf6f91a477 100644 (file)
@@ -37,4 +37,3 @@ Indices and tables
 
 * :ref:`genindex`
 * :ref:`modindex`
-* :ref:`search`
index e028e98af8fd7e46b6cd903b100df093427670ab..6dc56301bc767f48e6dbfb98ac1b18a03c2464d8 100644 (file)
@@ -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 (file)
index 0000000..3ef0c8f
--- /dev/null
@@ -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
index 60a05a4748620d9173056fff2b7a67517fadb2b2..b41e93f9b3cfcc35cbc3688e2f98b5d715368ad0 100644 (file)
@@ -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