Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-psycopg2 for openSUSE:Factory 
checked in at 2022-11-01 13:42:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-psycopg2 (Old)
 and      /work/SRC/openSUSE:Factory/.python-psycopg2.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-psycopg2"

Tue Nov  1 13:42:13 2022 rev:41 rq:1032498 version:2.9.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-psycopg2/python-psycopg2.changes  
2021-12-30 15:56:07.036686774 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-psycopg2.new.2275/python-psycopg2.changes    
    2022-11-01 13:42:23.991842340 +0100
@@ -1,0 +2,20 @@
+Fri Oct 28 19:56:31 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com>
+
+- Update to 2.9.5 
+  * Add support for Python 3.11.
+  * Add support for rowcount in MERGE statements in binary packages
+    (ticket`#1497`).
+  * Wheel package compiled against OpenSSL 1.1.1r and PostgreSQL 15 libpq.
+
+- Update to 2.9.4
+  * Fix `~psycopg2.extras.register_composite()`,
+    `~psycopg2.extras.register_range()` with customized search_path
+    (ticket`#1487`).
+  * Handle correctly composite types with names or in schemas requiring escape.
+  * Find ``pg_service.conf file in the ``/etc/postgresql-common`` directory in
+    binary packages (ticket`1365`).
+  * `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
+    PostgreSQL 15.
+  * Wheel package compiled against OpenSSL 1.1.1q and PostgreSQL 14.4
+
+-------------------------------------------------------------------

Old:
----
  psycopg2-2.9.3.tar.gz

New:
----
  psycopg2-2.9.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-psycopg2.spec ++++++
--- /var/tmp/diff_new_pack.es5zoI/_old  2022-11-01 13:42:24.419844618 +0100
+++ /var/tmp/diff_new_pack.es5zoI/_new  2022-11-01 13:42:24.423844640 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-psycopg2
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-psycopg2
-Version:        2.9.3
+Version:        2.9.5
 Release:        0
 Summary:        Python-PostgreSQL Database Adapter
 License:        LGPL-3.0-or-later AND (LGPL-3.0-or-later OR ZPL-2.0) AND 
SUSE-GPL-2.0-with-openssl-exception

++++++ psycopg2-2.9.3.tar.gz -> psycopg2-2.9.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/NEWS new/psycopg2-2.9.5/NEWS
--- old/psycopg2-2.9.3/NEWS     2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/NEWS     2022-10-25 13:05:48.000000000 +0200
@@ -1,10 +1,34 @@
 Current release
 ---------------
 
+What's new in psycopg 2.9.5
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Add support for Python 3.11.
+- Add support for rowcount in MERGE statements in binary packages
+  (:ticket:`#1497`).
+- Wheel package compiled against OpenSSL 1.1.1r and PostgreSQL 15 libpq.
+
+
+What's new in psycopg 2.9.4
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Fix `~psycopg2.extras.register_composite()`,
+  `~psycopg2.extras.register_range()` with customized :sql:`search_path`
+  (:ticket:`#1487`).
+- Handle correctly composite types with names or in schemas requiring escape.
+- Find ``pg_service.conf`` file in the ``/etc/postgresql-common`` directory in
+  binary packages (:ticket:`#1365`).
+- `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
+  PostgreSQL 15.
+- Wheel package compiled against OpenSSL 1.1.1q and PostgreSQL 14.4 libpq.
+
+
 What's new in psycopg 2.9.3
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-- Alpine (musl) wheels now available (:ticket:`#1148`).
+- Alpine (musl) wheels now available (:ticket:`#1392`).
+- macOS arm64 (Apple M1) wheels now available (:ticket:`1482`).
 
 
 What's new in psycopg 2.9.2
@@ -14,14 +38,14 @@
 - `~psycopg2.errorcodes` map and `~psycopg2.errors` classes updated to
   PostgreSQL 14.
 - Add preliminary support for Python 3.11 (:tickets:`#1376, #1386`).
-- Wheel package compiled against OpenSSL 1.1.1l and PostgreSQL 14.1
+- Wheel package compiled against OpenSSL 1.1.1l and PostgreSQL 14.1 libpq
   (:ticket:`#1388`).
 
 
 What's new in psycopg 2.9.1
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Fix regression with named `sql.Placeholder` (:ticket:`#1291`).
+- Fix regression with named `~psycopg2.sql.Placeholder` (:ticket:`#1291`).
 
 
 What's new in psycopg 2.9
@@ -51,7 +75,7 @@
   platforms.
 - Provide :pep:`600` wheels packages (manylinux_2_24 tag) for aarch64 and
   ppc64le platforms.
-- Wheel package compiled against OpenSSL 1.1.1k and PostgreSQL 13.3.
+- Wheel package compiled against OpenSSL 1.1.1k and PostgreSQL 13.3 libpq.
 - Build system for Linux/MacOS binary packages moved to GitHub Actions.
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/PKG-INFO new/psycopg2-2.9.5/PKG-INFO
--- old/psycopg2-2.9.3/PKG-INFO 2021-12-29 13:51:57.495733500 +0100
+++ new/psycopg2-2.9.5/PKG-INFO 2022-10-25 13:05:49.455371100 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: psycopg2
-Version: 2.9.3
+Version: 2.9.5
 Summary: psycopg2 - Python-PostgreSQL Database Adapter
 Home-page: https://psycopg.org/
 Author: Federico Di Gregorio
@@ -95,6 +95,7 @@
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: C
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/requirements.txt 
new/psycopg2-2.9.5/doc/requirements.txt
--- old/psycopg2-2.9.3/doc/requirements.txt     2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/doc/requirements.txt     2022-10-25 13:05:48.000000000 
+0200
@@ -1,8 +1,58 @@
-# Packages only needed to build the docs
-Pygments>=2.2,<2.3
-Sphinx>=1.6,<=1.7
-sphinx-better-theme>=0.1.5,<0.2
-
-# 0.15.2 affected by https://sourceforge.net/p/docutils/bugs/353/
-# Can update to 0.16 after release (currently in rc) but must update Sphinx too
-docutils<0.15
+#
+# This file is autogenerated by pip-compile with python 3.8
+# To update, run:
+#
+#    pip-compile requirements.in
+#
+alabaster==0.7.12
+    # via sphinx
+babel==2.9.1
+    # via sphinx
+certifi==2021.10.8
+    # via requests
+charset-normalizer==2.0.12
+    # via requests
+docutils==0.17.1
+    # via sphinx
+idna==3.3
+    # via requests
+imagesize==1.3.0
+    # via sphinx
+importlib-metadata==4.11.3
+    # via sphinx
+jinja2==3.1.1
+    # via sphinx
+markupsafe==2.1.1
+    # via jinja2
+packaging==21.3
+    # via sphinx
+pygments==2.11.2
+    # via sphinx
+pyparsing==3.0.7
+    # via packaging
+pytz==2022.1
+    # via babel
+requests==2.27.1
+    # via sphinx
+snowballstemmer==2.2.0
+    # via sphinx
+sphinx==4.4.0
+    # via -r requirements.in
+sphinx-better-theme==0.1.5
+    # via -r requirements.in
+sphinxcontrib-applehelp==1.0.2
+    # via sphinx
+sphinxcontrib-devhelp==1.0.2
+    # via sphinx
+sphinxcontrib-htmlhelp==2.0.0
+    # via sphinx
+sphinxcontrib-jsmath==1.0.1
+    # via sphinx
+sphinxcontrib-qthelp==1.0.3
+    # via sphinx
+sphinxcontrib-serializinghtml==1.1.5
+    # via sphinx
+urllib3==1.26.9
+    # via requests
+zipp==3.7.0
+    # via importlib-metadata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/cursor.rst 
new/psycopg2-2.9.5/doc/src/cursor.rst
--- old/psycopg2-2.9.3/doc/src/cursor.rst       2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/doc/src/cursor.rst       2022-10-25 13:05:48.000000000 
+0200
@@ -208,6 +208,14 @@
         Parameters are bounded to the query using the same rules described in
         the `~cursor.execute()` method.
 
+        .. code:: python
+
+            >>> nums = ((1,), (5,), (10,))
+            >>> cur.executemany("INSERT INTO test (num) VALUES (%s)", nums)
+
+            >>> tuples = ((123, "foo"), (42, "bar"), (23, "baz"))
+            >>> cur.executemany("INSERT INTO test (num, data) VALUES (%s, 
%s)", tuples)
+
         .. warning::
             In its current implementation this method is not faster than
             executing `~cursor.execute()` in a loop. For better performance
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/errorcodes.rst 
new/psycopg2-2.9.5/doc/src/errorcodes.rst
--- old/psycopg2-2.9.3/doc/src/errorcodes.rst   2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/doc/src/errorcodes.rst   2022-10-25 13:05:48.000000000 
+0200
@@ -50,7 +50,7 @@
     '42P01'
 
 Constants representing all the error values defined by PostgreSQL versions
-between 8.1 and 13 are included in the module.
+between 8.1 and 15 are included in the module.
 
 
 .. autofunction:: lookup(code)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/errors.rst 
new/psycopg2-2.9.5/doc/src/errors.rst
--- old/psycopg2-2.9.3/doc/src/errors.rst       2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/doc/src/errors.rst       2022-10-25 13:05:48.000000000 
+0200
@@ -14,11 +14,15 @@
 
 .. versionchanged:: 2.8.6 added errors introduced in PostgreSQL 13
 
+.. versionchanged:: 2.9.2 added errors introduced in PostgreSQL 14
+
+.. versionchanged:: 2.9.4 added errors introduced in PostgreSQL 15
+
 This module exposes the classes psycopg raises upon receiving an error from
 the database with a :sql:`SQLSTATE` value attached (available in the
 `~psycopg2.Error.pgcode` attribute). The content of the module is generated
 from the PostgreSQL source code and includes classes for every error defined
-by PostgreSQL in versions between 9.1 and 13.
+by PostgreSQL in versions between 9.1 and 15.
 
 Every class in the module is named after what referred as "condition name" `in
 the documentation`__, converted to CamelCase: e.g. the error 22012,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/extras.rst 
new/psycopg2-2.9.5/doc/src/extras.rst
--- old/psycopg2-2.9.3/doc/src/extras.rst       2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/doc/src/extras.rst       2022-10-25 13:05:48.000000000 
+0200
@@ -1029,6 +1029,14 @@
 
 .. autofunction:: execute_batch
 
+    .. code:: python
+
+        >>> nums = ((1,), (5,), (10,))
+        >>> execute_batch(cur, "INSERT INTO test (num) VALUES (%s)", nums)
+
+        >>> tuples = ((123, "foo"), (42, "bar"), (23, "baz"))
+        >>> execute_batch(cur, "INSERT INTO test (num, data) VALUES (%s, %s)", 
tuples)
+
     .. versionadded:: 2.7
 
 .. note::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/install.rst 
new/psycopg2-2.9.5/doc/src/install.rst
--- old/psycopg2-2.9.3/doc/src/install.rst      2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/doc/src/install.rst      2022-10-25 13:05:48.000000000 
+0200
@@ -131,10 +131,17 @@
 ..
     NOTE: keep consistent with setup.py and the /features/ page.
 
-- Python versions from 3.6 to 3.10
-- PostgreSQL server versions from 7.4 to 14
+- Python versions from 3.6 to 3.11
+- PostgreSQL server versions from 7.4 to 15
 - PostgreSQL client library version from 9.1
 
+.. note::
+
+    Not all the psycopg2 versions support all the supported Python versions.
+
+    Please see the :ref:`release notes <news>` to verify when the support for
+    a new Python version was added and when the support for an old Python
+    version was removed.
 
 
 .. _build-prerequisites:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/news.rst 
new/psycopg2-2.9.5/doc/src/news.rst
--- old/psycopg2-2.9.3/doc/src/news.rst 2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/doc/src/news.rst 2022-10-25 13:05:48.000000000 +0200
@@ -2,6 +2,8 @@
     single: Release notes
     single: News
 
+.. _news:
+
 Release notes
 =============
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/doc/src/sql.rst 
new/psycopg2-2.9.5/doc/src/sql.rst
--- old/psycopg2-2.9.3/doc/src/sql.rst  2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/doc/src/sql.rst  2022-10-25 13:05:48.000000000 +0200
@@ -33,7 +33,7 @@
     # This works, but it is not optimal
     table_name = 'my_table'
     cur.execute(
-        "insert into %s values (%%s, %%s)" % ext.quote_ident(table_name),
+        "insert into %s values (%%s, %%s)" % ext.quote_ident(table_name, cur),
         [10, 20])
 
 This is now safe, but it somewhat ad-hoc. In case, for some reason, it is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/lib/_range.py 
new/psycopg2-2.9.5/lib/_range.py
--- old/psycopg2-2.9.3/lib/_range.py    2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/lib/_range.py    2022-10-25 13:05:48.000000000 +0200
@@ -143,10 +143,6 @@
     def __bool__(self):
         return self._bounds is not None
 
-    def __nonzero__(self):
-        # Python 2 compatibility
-        return type(self).__bool__(self)
-
     def __eq__(self, other):
         if not isinstance(other, Range):
             return False
@@ -367,33 +363,54 @@
             schema = 'public'
 
         # get the type oid and attributes
-        try:
-            curs.execute("""\
-select rngtypid, rngsubtype,
-    (select typarray from pg_type where oid = rngtypid)
+        curs.execute("""\
+select rngtypid, rngsubtype, typarray
 from pg_range r
 join pg_type t on t.oid = rngtypid
 join pg_namespace ns on ns.oid = typnamespace
 where typname = %s and ns.nspname = %s;
 """, (tname, schema))
+        rec = curs.fetchone()
 
-        except ProgrammingError:
-            if not conn.autocommit:
-                conn.rollback()
-            raise
-        else:
-            rec = curs.fetchone()
+        if not rec:
+            # The above algorithm doesn't work for customized seach_path
+            # (#1487) The implementation below works better, but, to guarantee
+            # backwards compatibility, use it only if the original one failed.
+            try:
+                savepoint = False
+                # Because we executed statements earlier, we are either INTRANS
+                # or we are IDLE only if the transaction is autocommit, in
+                # which case we don't need the savepoint anyway.
+                if conn.status == STATUS_IN_TRANSACTION:
+                    curs.execute("SAVEPOINT register_type")
+                    savepoint = True
 
-            # revert the status of the connection as before the command
-            if (conn_status != STATUS_IN_TRANSACTION
-            and not conn.autocommit):
-                conn.rollback()
+                curs.execute("""\
+SELECT rngtypid, rngsubtype, typarray, typname, nspname
+from pg_range r
+join pg_type t on t.oid = rngtypid
+join pg_namespace ns on ns.oid = typnamespace
+WHERE t.oid = %s::regtype
+""", (name, ))
+            except ProgrammingError:
+                pass
+            else:
+                rec = curs.fetchone()
+                if rec:
+                    tname, schema = rec[3:]
+            finally:
+                if savepoint:
+                    curs.execute("ROLLBACK TO SAVEPOINT register_type")
+
+        # revert the status of the connection as before the command
+        if conn_status != STATUS_IN_TRANSACTION and not conn.autocommit:
+            conn.rollback()
 
         if not rec:
             raise ProgrammingError(
-                f"PostgreSQL type '{name}' not found")
+                f"PostgreSQL range '{name}' not found")
 
-        type, subtype, array = rec
+        type, subtype, array = rec[:3]
 
         return RangeCaster(name, pyrange,
             oid=type, subtype_oid=subtype, array_oid=array)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/lib/errorcodes.py 
new/psycopg2-2.9.5/lib/errorcodes.py
--- old/psycopg2-2.9.3/lib/errorcodes.py        2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/lib/errorcodes.py        2022-10-25 13:05:48.000000000 
+0200
@@ -223,6 +223,7 @@
 TOO_MANY_JSON_ARRAY_ELEMENTS = '2203D'
 TOO_MANY_JSON_OBJECT_MEMBERS = '2203E'
 SQL_JSON_SCALAR_REQUIRED = '2203F'
+SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE = '2203G'
 FLOATING_POINT_EXCEPTION = '22P01'
 INVALID_TEXT_REPRESENTATION = '22P02'
 INVALID_BINARY_REPRESENTATION = '22P03'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/lib/extras.py 
new/psycopg2-2.9.5/lib/extras.py
--- old/psycopg2-2.9.3/lib/extras.py    2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/lib/extras.py    2022-10-25 13:05:48.000000000 +0200
@@ -357,10 +357,6 @@
         except StopIteration:
             return
 
-    # ascii except alnum and underscore
-    _re_clean = _re.compile(
-        '[' + _re.escape(' !"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~') + ']')
-
     def _make_nt(self):
         key = tuple(d[0] for d in self.description) if self.description else ()
         return self._cached_make_nt(key)
@@ -369,7 +365,7 @@
     def _do_make_nt(cls, key):
         fields = []
         for s in key:
-            s = cls._re_clean.sub('_', s)
+            s = _re_clean.sub('_', s)
             # Python identifier cannot start with numbers, namedtuple fields
             # cannot start with underscore. So...
             if s[0] == '_' or '0' <= s[0] <= '9':
@@ -1061,6 +1057,7 @@
         return rv
 
     def _create_type(self, name, attnames):
+        name = _re_clean.sub('_', name)
         self.type = namedtuple(name, attnames)
         self._ctor = self.type._make
 
@@ -1098,9 +1095,41 @@
 
         recs = curs.fetchall()
 
+        if not recs:
+            # The above algorithm doesn't work for customized seach_path
+            # (#1487) The implementation below works better, but, to guarantee
+            # backwards compatibility, use it only if the original one failed.
+            try:
+                savepoint = False
+                # Because we executed statements earlier, we are either INTRANS
+                # or we are IDLE only if the transaction is autocommit, in
+                # which case we don't need the savepoint anyway.
+                if conn.status == _ext.STATUS_IN_TRANSACTION:
+                    curs.execute("SAVEPOINT register_type")
+                    savepoint = True
+
+                curs.execute("""\
+SELECT t.oid, %s, attname, atttypid, typname, nspname
+FROM pg_type t
+JOIN pg_namespace ns ON typnamespace = ns.oid
+JOIN pg_attribute a ON attrelid = typrelid
+WHERE t.oid = %%s::regtype
+    AND attnum > 0 AND NOT attisdropped
+ORDER BY attnum;
+""" % typarray, (name, ))
+            except psycopg2.ProgrammingError:
+                pass
+            else:
+                recs = curs.fetchall()
+                if recs:
+                    tname = recs[0][4]
+                    schema = recs[0][5]
+            finally:
+                if savepoint:
+                    curs.execute("ROLLBACK TO SAVEPOINT register_type")
+
         # revert the status of the connection as before the command
-        if (conn_status != _ext.STATUS_IN_TRANSACTION
-        and not conn.autocommit):
+        if conn_status != _ext.STATUS_IN_TRANSACTION and not conn.autocommit:
             conn.rollback()
 
         if not recs:
@@ -1304,3 +1333,8 @@
         raise ValueError("the query doesn't contain any '%s' placeholder")
 
     return pre, post
+
+
+# ascii except alnum and underscore
+_re_clean = _re.compile(
+    '[' + _re.escape(' !"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~') + ']')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/psycopg/sqlstate_errors.h 
new/psycopg2-2.9.5/psycopg/sqlstate_errors.h
--- old/psycopg2-2.9.3/psycopg/sqlstate_errors.h        2021-12-29 
13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/psycopg/sqlstate_errors.h        2022-10-25 
13:05:48.000000000 +0200
@@ -111,6 +111,7 @@
 {"2203D", "TooManyJsonArrayElements"},
 {"2203E", "TooManyJsonObjectMembers"},
 {"2203F", "SqlJsonScalarRequired"},
+{"2203G", "SqlJsonItemCannotBeCastToTargetType"},
 {"22P01", "FloatingPointException"},
 {"22P02", "InvalidTextRepresentation"},
 {"22P03", "InvalidBinaryRepresentation"},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/psycopg2.egg-info/PKG-INFO 
new/psycopg2-2.9.5/psycopg2.egg-info/PKG-INFO
--- old/psycopg2-2.9.3/psycopg2.egg-info/PKG-INFO       2021-12-29 
13:51:57.000000000 +0100
+++ new/psycopg2-2.9.5/psycopg2.egg-info/PKG-INFO       2022-10-25 
13:05:49.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: psycopg2
-Version: 2.9.3
+Version: 2.9.5
 Summary: psycopg2 - Python-PostgreSQL Database Adapter
 Home-page: https://psycopg.org/
 Author: Federico Di Gregorio
@@ -95,6 +95,7 @@
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3 :: Only
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: C
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/psycopg2.egg-info/SOURCES.txt 
new/psycopg2-2.9.5/psycopg2.egg-info/SOURCES.txt
--- old/psycopg2-2.9.3/psycopg2.egg-info/SOURCES.txt    2021-12-29 
13:51:57.000000000 +0100
+++ new/psycopg2-2.9.5/psycopg2.egg-info/SOURCES.txt    2022-10-25 
13:05:49.000000000 +0200
@@ -138,12 +138,14 @@
 scripts/build/appveyor.py
 scripts/build/build_libpq.sh
 scripts/build/build_macos.sh
+scripts/build/build_macos_arm64.sh
 scripts/build/build_manylinux2014.sh
 scripts/build/build_manylinux_2_24.sh
 scripts/build/build_musllinux_1_1.sh
 scripts/build/build_sdist.sh
 scripts/build/download_packages_appveyor.py
 scripts/build/download_packages_github.py
+scripts/build/run_build_macos_arm64.sh
 scripts/build/strip_wheel.sh
 tests/__init__.py
 tests/dbapi20.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/build_libpq.sh 
new/psycopg2-2.9.5/scripts/build/build_libpq.sh
--- old/psycopg2-2.9.3/scripts/build/build_libpq.sh     2021-12-29 
13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/scripts/build/build_libpq.sh     2022-10-25 
13:05:48.000000000 +0200
@@ -5,10 +5,14 @@
 set -euo pipefail
 set -x
 
-openssl_version="1.1.1l"
+# Last release: https://www.postgresql.org/ftp/source/
+postgres_version="15.0"
+# last release: https://www.openssl.org/source/
+openssl_version="1.1.1r"
+# last release: https://openldap.org/software/download/
 ldap_version="2.4.59"
-sasl_version="2.1.27"
-postgres_version="14.1"
+# last release: https://github.com/cyrusimap/cyrus-sasl/releases
+sasl_version="2.1.28"
 
 yum install -y zlib-devel krb5-devel pam-devel
 
@@ -113,7 +117,8 @@
     fi
 
     ./configure --prefix=/usr/local --without-readline \
-        --with-gssapi --with-openssl --with-pam --with-ldap
+        --with-gssapi --with-openssl --with-pam --with-ldap \
+        --sysconfdir=/etc/postgresql-common
     make -C src/interfaces/libpq
     make -C src/bin/pg_config
     make -C src/include
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/scripts/build/build_macos_arm64.sh 
new/psycopg2-2.9.5/scripts/build/build_macos_arm64.sh
--- old/psycopg2-2.9.3/scripts/build/build_macos_arm64.sh       1970-01-01 
01:00:00.000000000 +0100
+++ new/psycopg2-2.9.5/scripts/build/build_macos_arm64.sh       2022-10-25 
13:05:48.000000000 +0200
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# Build psycopg2-binary wheel packages for Apple M1 (cpNNN-macosx_arm64)
+#
+# This script is designed to run on Scaleway Apple Silicon machines.
+#
+# The script cannot be run as sudo (installing brew fails), but requires sudo,
+# so it can pretty much only be executed by a sudo user as it is.
+
+set -euo pipefail
+set -x
+
+python_versions="3.8.10 3.9.13 3.10.5 3.11"
+postgres_version=15
+
+# Move to the root of the project
+dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+cd "${dir}/../../"
+
+# Add /usr/local/bin to the path. It seems it's not, in non-interactive 
sessions
+if ! (echo $PATH | grep -q '/usr/local/bin'); then
+    export PATH=/usr/local/bin:$PATH
+fi
+
+# Install brew, if necessary. Otherwise just make sure it's in the path
+if [[ -x /opt/homebrew/bin/brew ]]; then
+    eval "$(/opt/homebrew/bin/brew shellenv)"
+else
+    command -v brew > /dev/null || (
+        # Not necessary: already installed
+        # xcode-select --install
+        NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL \
+            
https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
+    )
+    eval "$(/opt/homebrew/bin/brew shellenv)"
+fi
+
+# Install PostgreSQL, if necessary
+command -v pg_config > /dev/null || (
+    brew install postgresql@${postgres_version}
+    # Currently not working
+    # brew services start postgresql@${postgres_version}
+    pg_ctl \
+        -D /opt/homebrew/var/postgresql@${postgres_version} \
+        -l /opt/homebrew/var/log/postgresql@${postgres_version}.log \
+        start
+)
+
+# Install the Python versions we want to build
+for ver3 in $python_versions; do
+    ver2=$(echo $ver3 | sed 's/\([^\.]*\)\(\.[^\.]*\)\(.*\)/\1\2/')
+    command -v python${ver2} > /dev/null || (
+        (cd /tmp &&
+            curl -fsSl -O \
+                
https://www.python.org/ftp/python/${ver3}/python-${ver3}-macos11.pkg)
+        sudo installer -pkg /tmp/python-${ver3}-macos11.pkg -target /
+    )
+done
+
+# Create a virtualenv where to work
+if [[ ! -x .venv/bin/python ]]; then
+    python3 -m venv .venv
+fi
+
+source .venv/bin/activate
+pip install cibuildwheel
+
+# Build the binary packages
+export CIBW_PLATFORM=macos
+export CIBW_ARCHS=arm64
+export CIBW_BUILD='cp{38,39,310}-*'
+export CIBW_TEST_COMMAND='python -c "import tests; 
tests.unittest.main(defaultTest=\"tests.test_suite\")"'
+
+export PSYCOPG2_TESTDB=postgres
+export PYTHONPATH=$(pwd)
+
+# For some reason, cibuildwheel tests says that psycopg2 is already installed,
+# refuses to install, then promptly fails import. So, please, seriously,
+# install this thing.
+export PIP_FORCE_REINSTALL=1
+
+# Replace the package name
+sed -i .bak 's/^setup(name="psycopg2"/setup(name="psycopg2-binary"/' setup.py
+
+cibuildwheel
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/psycopg2-2.9.3/scripts/build/download_packages_appveyor.py 
new/psycopg2-2.9.5/scripts/build/download_packages_appveyor.py
--- old/psycopg2-2.9.3/scripts/build/download_packages_appveyor.py      
2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/scripts/build/download_packages_appveyor.py      
2022-10-25 13:05:48.000000000 +0200
@@ -69,7 +69,7 @@
             fn = af["fileName"]
             if fn.startswith("dist/"):
                 fn = fn.split("/", 1)[1]
-            dest = Path("packages") / fn
+            dest = Path("wheelhouse") / fn
             logger.info(f"downloading {dest}")
             resp = s.get(
                 
f"{API_URL}/buildjobs/{job['jobId']}/artifacts/{af['fileName']}"
@@ -81,7 +81,7 @@
             with dest.open("wb") as f:
                 f.write(resp.content)
 
-    logger.info("now you can run: 'twine upload -s packages/*'")
+    logger.info("now you can run: 'twine upload -s wheelhouse/*'")
 
 
 def parse_cmdline():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/psycopg2-2.9.3/scripts/build/download_packages_github.py 
new/psycopg2-2.9.5/scripts/build/download_packages_github.py
--- old/psycopg2-2.9.3/scripts/build/download_packages_github.py        
2021-12-29 13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/scripts/build/download_packages_github.py        
2022-10-25 13:05:48.000000000 +0200
@@ -57,7 +57,7 @@
     resp.raise_for_status()
     artifacts = resp.json()["artifacts"]
 
-    dest = Path("packages")
+    dest = Path("wheelhouse")
     if not dest.exists():
         logger.info(f"creating dir {dest}")
         dest.mkdir(parents=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/psycopg2-2.9.3/scripts/build/run_build_macos_arm64.sh 
new/psycopg2-2.9.5/scripts/build/run_build_macos_arm64.sh
--- old/psycopg2-2.9.3/scripts/build/run_build_macos_arm64.sh   1970-01-01 
01:00:00.000000000 +0100
+++ new/psycopg2-2.9.5/scripts/build/run_build_macos_arm64.sh   2022-10-25 
13:05:48.000000000 +0200
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Build psycopg2-binary wheel packages for Apple M1 (cpNNN-macosx_arm64)
+#
+# This script is designed to run on a local machine: it will clone the repos
+# remotely and execute the `build_macos_arm64.sh` script remotely, then will
+# download the built packages. A tag to build must be specified.
+#
+# In order to run the script, the `m1` host must be specified in
+# `~/.ssh/config`; for instance:
+#
+#   Host m1
+#     User m1
+#     HostName 1.2.3.4
+
+set -euo pipefail
+# set -x
+
+tag=${1:-}
+
+if [[ ! "${tag}" ]]; then
+    echo "Usage: $0 TAG" >&2
+    exit 2
+fi
+
+rdir=psycobuild
+
+# Clone the repos
+ssh m1 rm -rf "${rdir}"
+ssh m1 git clone https://github.com/psycopg/psycopg2.git --branch ${tag} 
"${rdir}"
+
+# Allow sudoing without password, to allow brew to install
+ssh -t m1 bash -c \
+    'test -f /etc/sudoers.d/m1 || echo "m1 ALL=(ALL) NOPASSWD:ALL" | sudo tee 
/etc/sudoers.d/m1'
+
+# Build the wheel packages
+ssh m1 "${rdir}/scripts/build/build_macos_arm64.sh"
+
+# Transfer the packages locally
+scp -r "m1:${rdir}/wheelhouse" .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/scripts/make_errorcodes.py 
new/psycopg2-2.9.5/scripts/make_errorcodes.py
--- old/psycopg2-2.9.3/scripts/make_errorcodes.py       2021-12-29 
13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/scripts/make_errorcodes.py       2022-10-25 
13:05:48.000000000 +0200
@@ -33,7 +33,7 @@
     file_start = read_base_file(filename)
     # If you add a version to the list fix the docs (in errorcodes.rst)
     classes, errors = fetch_errors(
-        ['9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '10', '11', '12', '13', 
'14'])
+        '9.1 9.2 9.3 9.4 9.5 9.6 10 11 12 13 14 15'.split())
 
     disambiguate(errors)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/scripts/make_errors.py 
new/psycopg2-2.9.5/scripts/make_errors.py
--- old/psycopg2-2.9.3/scripts/make_errors.py   2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/scripts/make_errors.py   2022-10-25 13:05:48.000000000 
+0200
@@ -30,7 +30,7 @@
 
     # If you add a version to the list fix the docs (in errors.rst)
     classes, errors = fetch_errors(
-        ['9.1', '9.2', '9.3', '9.4', '9.5', '9.6', '10', '11', '12', '13', 
'14'])
+        '9.1 9.2 9.3 9.4 9.5 9.6 10 11 12 13 14 15'.split())
 
     f = open(filename, "w")
     print("/*\n * Autogenerated by 'scripts/make_errors.py'.\n */\n", file=f)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/setup.py new/psycopg2-2.9.5/setup.py
--- old/psycopg2-2.9.3/setup.py 2021-12-29 13:51:57.000000000 +0100
+++ new/psycopg2-2.9.5/setup.py 2022-10-25 13:05:48.000000000 +0200
@@ -44,7 +44,7 @@
 # Take a look at https://www.python.org/dev/peps/pep-0440/
 # for a consistent versioning pattern.
 
-PSYCOPG_VERSION = '2.9.3'
+PSYCOPG_VERSION = '2.9.5'
 
 
 # note: if you are changing the list of supported Python version please fix
@@ -60,6 +60,7 @@
 Programming Language :: Python :: 3.8
 Programming Language :: Python :: 3.9
 Programming Language :: Python :: 3.10
+Programming Language :: Python :: 3.11
 Programming Language :: Python :: 3 :: Only
 Programming Language :: Python :: Implementation :: CPython
 Programming Language :: C
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_async.py 
new/psycopg2-2.9.5/tests/test_async.py
--- old/psycopg2-2.9.3/tests/test_async.py      2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/tests/test_async.py      2022-10-25 13:05:48.000000000 
+0200
@@ -390,6 +390,7 @@
         # fetching from the correct cursor works
         self.assertEquals(cur1.fetchone()[0], 1)
 
+    @skip_if_crdb("batch statements", version="< 22.1")
     def test_error(self):
         cur = self.conn.cursor()
         cur.execute("insert into table1 values (%s)", (1, ))
@@ -402,9 +403,8 @@
         # this should fail as well (Postgres behaviour)
         self.assertRaises(psycopg2.IntegrityError, self.wait, cur)
         # but this should work
-        if crdb_version(self.sync_conn) is None:
-            cur.execute("insert into table1 values (%s)", (2, ))
-            self.wait(cur)
+        cur.execute("insert into table1 values (%s)", (2, ))
+        self.wait(cur)
         # and the cursor should be usable afterwards
         cur.execute("insert into table1 values (%s)", (3, ))
         self.wait(cur)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_connection.py 
new/psycopg2-2.9.5/tests/test_connection.py
--- old/psycopg2-2.9.3/tests/test_connection.py 2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/tests/test_connection.py 2022-10-25 13:05:48.000000000 
+0200
@@ -1928,11 +1928,16 @@
                 self.assertIsInstance(self.conn.info.ssl_attribute(attrib), 
str)
         else:
             for attrib in attribs:
+                # Behaviour changed in PostgreSQL 15
+                if attrib == "library":
+                    continue
                 self.assertIsNone(self.conn.info.ssl_attribute(attrib))
 
         self.assertIsNone(self.conn.info.ssl_attribute('wat'))
 
         for attrib in attribs:
+            if attrib == "library":
+                continue
             self.assertIsNone(self.bconn.info.ssl_attribute(attrib))
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_cursor.py 
new/psycopg2-2.9.5/tests/test_cursor.py
--- old/psycopg2-2.9.3/tests/test_cursor.py     2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/tests/test_cursor.py     2022-10-25 13:05:48.000000000 
+0200
@@ -379,6 +379,12 @@
     @skip_before_postgres(8, 2)
     def test_rowcount_on_executemany_returning(self):
         cur = self.conn.cursor()
+        try:
+            cur.execute("drop table execmany")
+            self.conn.commit()
+        except psycopg2.DatabaseError:
+            self.conn.rollback()
+
         cur.execute("create table execmany(id serial primary key, data int)")
         cur.executemany(
             "insert into execmany (data) values (%s)",
@@ -412,7 +418,7 @@
         self.assert_(curs.pgresult_ptr is None)
 
 
-@skip_if_crdb("named cursor")
+@skip_if_crdb("named cursor", version="< 22.1")
 class NamedCursorTests(ConnectingTestCase):
     def test_invalid_name(self):
         curs = self.conn.cursor()
@@ -436,6 +442,7 @@
             curs.execute("insert into withhold values (%s)", (i,))
         curs.close()
 
+    @skip_if_crdb("cursor with hold")
     def test_withhold(self):
         self.assertRaises(psycopg2.ProgrammingError, self.conn.cursor,
                           withhold=True)
@@ -460,6 +467,7 @@
         curs.execute("drop table withhold")
         self.conn.commit()
 
+    @skip_if_crdb("cursor with hold")
     def test_withhold_no_begin(self):
         self._create_withhold_table()
         curs = self.conn.cursor("w", withhold=True)
@@ -484,6 +492,7 @@
         self.assertEqual(self.conn.info.transaction_status,
                          psycopg2.extensions.TRANSACTION_STATUS_IDLE)
 
+    @skip_if_crdb("cursor with hold")
     def test_withhold_autocommit(self):
         self._create_withhold_table()
         self.conn.commit()
@@ -506,6 +515,7 @@
         self.assertEqual(self.conn.info.transaction_status,
                          psycopg2.extensions.TRANSACTION_STATUS_IDLE)
 
+    @skip_if_crdb("scroll cursor")
     def test_scrollable(self):
         self.assertRaises(psycopg2.ProgrammingError, self.conn.cursor,
                           scrollable=True)
@@ -679,6 +689,7 @@
         self.assertRaises((IndexError, psycopg2.ProgrammingError),
             cur.scroll, 1)
 
+    @skip_if_crdb("scroll cursor")
     @skip_before_postgres(8, 0)
     def test_scroll_named(self):
         cur = self.conn.cursor('tmp', scrollable=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_extras_dictcursor.py 
new/psycopg2-2.9.5/tests/test_extras_dictcursor.py
--- old/psycopg2-2.9.3/tests/test_extras_dictcursor.py  2021-12-29 
13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/tests/test_extras_dictcursor.py  2022-10-25 
13:05:48.000000000 +0200
@@ -64,7 +64,7 @@
 class ExtrasDictCursorTests(_DictCursorBase):
     """Test if DictCursor extension class works."""
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def testDictConnCursorArgs(self):
         self.conn.close()
         self.conn = 
self.connect(connection_factory=psycopg2.extras.DictConnection)
@@ -132,19 +132,19 @@
                 return row
         self._testWithNamedCursor(getter)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("greedy cursor")
     @skip_before_postgres(8, 2)
     def testDictCursorWithNamedCursorNotGreedy(self):
         curs = self.conn.cursor('tmp', 
cursor_factory=psycopg2.extras.DictCursor)
         self._testNamedCursorNotGreedy(curs)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     @skip_before_postgres(8, 0)
     def testDictCursorWithNamedCursorIterRowNumber(self):
         curs = self.conn.cursor('tmp', 
cursor_factory=psycopg2.extras.DictCursor)
         self._testIterRowNumber(curs)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def _testWithNamedCursor(self, getter):
         curs = self.conn.cursor('aname', 
cursor_factory=psycopg2.extras.DictCursor)
         curs.execute("SELECT * FROM ExtrasDictCursorTests")
@@ -285,19 +285,19 @@
                 return row
         self._testWithNamedCursorReal(getter)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("greedy cursor")
     @skip_before_postgres(8, 2)
     def testDictCursorRealWithNamedCursorNotGreedy(self):
         curs = self.conn.cursor('tmp', 
cursor_factory=psycopg2.extras.RealDictCursor)
         self._testNamedCursorNotGreedy(curs)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     @skip_before_postgres(8, 0)
     def testDictCursorRealWithNamedCursorIterRowNumber(self):
         curs = self.conn.cursor('tmp', 
cursor_factory=psycopg2.extras.RealDictCursor)
         self._testIterRowNumber(curs)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def _testWithNamedCursorReal(self, getter):
         curs = self.conn.cursor('aname',
             cursor_factory=psycopg2.extras.RealDictCursor)
@@ -376,7 +376,7 @@
         curs.execute("INSERT INTO nttest VALUES (3, 'baz')")
         self.conn.commit()
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def test_cursor_args(self):
         cur = self.conn.cursor('foo', 
cursor_factory=psycopg2.extras.DictCursor)
         self.assertEqual(cur.name, 'foo')
@@ -533,7 +533,7 @@
         finally:
             NamedTupleCursor._make_nt = f_orig
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     @skip_before_postgres(8, 0)
     def test_named(self):
         curs = self.conn.cursor('tmp')
@@ -544,28 +544,28 @@
         recs.extend(curs.fetchall())
         self.assertEqual(list(range(10)), [t.i for t in recs])
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def test_named_fetchone(self):
         curs = self.conn.cursor('tmp')
         curs.execute("""select 42 as i""")
         t = curs.fetchone()
         self.assertEqual(t.i, 42)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def test_named_fetchmany(self):
         curs = self.conn.cursor('tmp')
         curs.execute("""select 42 as i""")
         recs = curs.fetchmany(10)
         self.assertEqual(recs[0].i, 42)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def test_named_fetchall(self):
         curs = self.conn.cursor('tmp')
         curs.execute("""select 42 as i""")
         recs = curs.fetchall()
         self.assertEqual(recs[0].i, 42)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("greedy cursor")
     @skip_before_postgres(8, 2)
     def test_not_greedy(self):
         curs = self.conn.cursor('tmp')
@@ -580,7 +580,7 @@
         self.assert_(recs[1].ts - recs[0].ts < timedelta(seconds=0.005))
         self.assert_(recs[2].ts - recs[1].ts > timedelta(seconds=0.0099))
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     @skip_before_postgres(8, 0)
     def test_named_rownumber(self):
         curs = self.conn.cursor('tmp')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_green.py 
new/psycopg2-2.9.5/tests/test_green.py
--- old/psycopg2-2.9.3/tests/test_green.py      2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/tests/test_green.py      2022-10-25 13:05:48.000000000 
+0200
@@ -219,7 +219,7 @@
 
         self.fail("you should have had a success or an error by now")
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def test_errors_named_cursor(self):
         for i in range(100):
             self.to_error = None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_types_basic.py 
new/psycopg2-2.9.5/tests/test_types_basic.py
--- old/psycopg2-2.9.3/tests/test_types_basic.py        2021-12-29 
13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/tests/test_types_basic.py        2022-10-25 
13:05:48.000000000 +0200
@@ -272,6 +272,8 @@
         ]:
             curs.execute("select %s::int[]", (a,))
             self.assertEqual(curs.fetchone()[0], a)
+            curs.execute("select array[%s::int[]]", (a,))
+            self.assertEqual(curs.fetchone()[0], [a])
 
     def testTypeRoundtripBytes(self):
         o1 = bytes(range(256))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_types_extras.py 
new/psycopg2-2.9.5/tests/test_types_extras.py
--- old/psycopg2-2.9.3/tests/test_types_extras.py       2021-12-29 
13:51:56.000000000 +0100
+++ new/psycopg2-2.9.5/tests/test_types_extras.py       2022-10-25 
13:05:48.000000000 +0200
@@ -585,6 +585,68 @@
         self.assertEqual(curs.fetchone()[0], (4, 8))
 
     @skip_if_no_composite
+    def test_composite_namespace_path(self):
+        curs = self.conn.cursor()
+        curs.execute("""
+            select nspname from pg_namespace
+            where nspname = 'typens';
+            """)
+        if not curs.fetchone():
+            curs.execute("create schema typens;")
+            self.conn.commit()
+
+        self._create_type("typens.typensp_ii",
+            [("a", "integer"), ("b", "integer")])
+        curs.execute("set search_path=typens,public")
+        t = psycopg2.extras.register_composite(
+            "typensp_ii", self.conn)
+        self.assertEqual(t.schema, 'typens')
+        curs.execute("select (4,8)::typensp_ii")
+        self.assertEqual(curs.fetchone()[0], (4, 8))
+
+    @skip_if_no_composite
+    def test_composite_weird_name(self):
+        curs = self.conn.cursor()
+        curs.execute("""
+            select nspname from pg_namespace
+            where nspname = 'qux.quux';
+            """)
+        if not curs.fetchone():
+            curs.execute('create schema "qux.quux";')
+
+        self._create_type('"qux.quux"."foo.bar"',
+            [("a", "integer"), ("b", "integer")])
+        t = psycopg2.extras.register_composite(
+            '"qux.quux"."foo.bar"', self.conn)
+        self.assertEqual(t.name, 'foo.bar')
+        self.assertEqual(t.schema, 'qux.quux')
+        curs.execute('select (4,8)::"qux.quux"."foo.bar"')
+        self.assertEqual(curs.fetchone()[0], (4, 8))
+
+    @skip_if_no_composite
+    def test_composite_not_found(self):
+
+        self.assertRaises(
+            psycopg2.ProgrammingError, psycopg2.extras.register_composite,
+            "nosuchtype", self.conn)
+        self.assertEqual(self.conn.status, ext.STATUS_READY)
+
+        cur = self.conn.cursor()
+        cur.execute("select 1")
+        self.assertRaises(
+            psycopg2.ProgrammingError, psycopg2.extras.register_composite,
+            "nosuchtype", self.conn)
+
+        self.assertEqual(self.conn.status, ext.STATUS_IN_TRANSACTION)
+
+        self.conn.rollback()
+        self.conn.autocommit = True
+        self.assertRaises(
+            psycopg2.ProgrammingError, psycopg2.extras.register_composite,
+            "nosuchtype", self.conn)
+        self.assertEqual(self.conn.status, ext.STATUS_READY)
+
+    @skip_if_no_composite
     @skip_before_postgres(8, 4)
     def test_composite_array(self):
         self._create_type("type_isd",
@@ -710,22 +772,15 @@
     def _create_type(self, name, fields):
         curs = self.conn.cursor()
         try:
+            curs.execute("savepoint x")
             curs.execute(f"drop type {name} cascade;")
         except psycopg2.ProgrammingError:
-            self.conn.rollback()
+            curs.execute("rollback to savepoint x")
 
         curs.execute("create type {} as ({});".format(name,
             ", ".join(["%s %s" % p for p in fields])))
-        if '.' in name:
-            schema, name = name.split('.')
-        else:
-            schema = 'public'
-
-        curs.execute("""\
-            SELECT t.oid
-            FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid
-            WHERE typname = %s and nspname = %s;
-            """, (name, schema))
+
+        curs.execute("SELECT %s::regtype::oid", (name, ))
         oid = curs.fetchone()[0]
         self.conn.commit()
         return oid
@@ -1560,6 +1615,18 @@
         cur = self.conn.cursor()
         self.assertRaises(psycopg2.ProgrammingError,
             register_range, 'nosuchrange', 'FailRange', cur)
+        self.assertEqual(self.conn.status, ext.STATUS_READY)
+
+        cur.execute("select 1")
+        self.assertRaises(psycopg2.ProgrammingError,
+            register_range, 'nosuchrange', 'FailRange', cur)
+
+        self.assertEqual(self.conn.status, ext.STATUS_IN_TRANSACTION)
+
+        self.conn.rollback()
+        self.conn.autocommit = True
+        self.assertRaises(psycopg2.ProgrammingError,
+            register_range, 'nosuchrange', 'FailRange', cur)
 
     @restore_types
     def test_schema_range(self):
@@ -1574,7 +1641,7 @@
         register_range('r1', 'r1', cur)
         ra2 = register_range('r2', 'r2', cur)
         rars2 = register_range('rs.r2', 'r2', cur)
-        register_range('rs.r3', 'r3', cur)
+        rars3 = register_range('rs.r3', 'r3', cur)
 
         self.assertNotEqual(
             ra2.typecaster.values[0],
@@ -1588,6 +1655,27 @@
             register_range, 'rs.r1', 'FailRange', cur)
         cur.execute("rollback to savepoint x;")
 
+        cur2 = self.conn.cursor()
+        cur2.execute("set local search_path to rs,public")
+        ra3 = register_range('r3', 'r3', cur2)
+        self.assertEqual(ra3.typecaster.values[0], rars3.typecaster.values[0])
+
+    @skip_if_no_composite
+    def test_rang_weird_name(self):
+        cur = self.conn.cursor()
+        cur.execute("""
+            select nspname from pg_namespace
+            where nspname = 'qux.quux';
+            """)
+        if not cur.fetchone():
+            cur.execute('create schema "qux.quux";')
+
+        cur.execute('create type "qux.quux"."foo.range" as range 
(subtype=text)')
+        r = psycopg2.extras.register_range(
+            '"qux.quux"."foo.range"', "foorange", cur)
+        cur.execute('''select '[a,z]'::"qux.quux"."foo.range"''')
+        self.assertEqual(cur.fetchone()[0], r.range('a', 'z', '[]'))
+
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromName(__name__)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/test_with.py 
new/psycopg2-2.9.5/tests/test_with.py
--- old/psycopg2-2.9.3/tests/test_with.py       2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/tests/test_with.py       2022-10-25 13:05:48.000000000 
+0200
@@ -290,7 +290,7 @@
         self.assert_(curs.closed)
         self.assert_(closes)
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     def test_exception_swallow(self):
         # bug #262: __exit__ calls cur.close() that hides the exception
         # with another error.
@@ -304,7 +304,7 @@
         else:
             self.fail("where is my exception?")
 
-    @skip_if_crdb("named cursor")
+    @skip_if_crdb("named cursor", version="< 22.1")
     @skip_before_postgres(8, 2)
     def test_named_with_noop(self):
         with self.conn.cursor('named'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/psycopg2-2.9.3/tests/testutils.py 
new/psycopg2-2.9.5/tests/testutils.py
--- old/psycopg2-2.9.3/tests/testutils.py       2021-12-29 13:51:56.000000000 
+0100
+++ new/psycopg2-2.9.5/tests/testutils.py       2022-10-25 13:05:48.000000000 
+0200
@@ -467,11 +467,13 @@
 crdb_reasons = {
     "2-phase commit": 22329,
     "backend pid": 35897,
+    "batch statements": 44803,
     "cancel": 41335,
     "cast adds tz": 51692,
     "cidr": 18846,
     "composite": 27792,
     "copy": 41608,
+    "cursor with hold": 77101,
     "deferrable": 48307,
     "encoding": 35882,
     "hstore": 41284,
@@ -483,6 +485,7 @@
     "notify": 41522,
     "password_encryption": 42519,
     "range": 41282,
+    "scroll cursor": 77102,
     "stored procedure": 1751,
 }
 

Reply via email to