]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
feat: allow to customize the oid to dump None
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Wed, 25 May 2022 08:45:29 +0000 (10:45 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 12 Jul 2022 11:58:34 +0000 (12:58 +0100)
On Postgres >= 10, INVALID_OID is ok, because it has a fallback text
cast. CRDB doesn't have such cast, but can convert implicitly from text
to other types, so TEXT_OID is a better choice.

psycopg/psycopg/_transform.py
psycopg_c/psycopg_c/_psycopg/transform.pyx

index 200f31c45d905712b770875da41068a7be2987f3..7303587274985450279be1efb3c3a2157b3078e5 100644 (file)
@@ -29,6 +29,7 @@ OidDumperCache: TypeAlias = Dict[int, "Dumper"]
 LoaderCache: TypeAlias = Dict[int, "Loader"]
 
 TEXT = pq.Format.TEXT
+PY_TEXT = PyFormat.TEXT
 
 
 class Transformer(AdaptContext):
@@ -169,7 +170,7 @@ class Transformer(AdaptContext):
                     out[i] = self._row_dumpers[i].dump(param)
             return out
 
-        types = [INVALID_OID] * nparams
+        types = [self._get_none_oid()] * nparams
         pqformats = [TEXT] * nparams
 
         for i in range(nparams):
@@ -187,7 +188,7 @@ class Transformer(AdaptContext):
         return out
 
     def as_literal(self, obj: Any) -> Buffer:
-        dumper = self.get_dumper(obj, PyFormat.TEXT)
+        dumper = self.get_dumper(obj, PY_TEXT)
         rv = dumper.quote(obj)
         # If the result is quoted, and the oid not unknown or text,
         # add an explicit type cast.
@@ -244,6 +245,19 @@ class Transformer(AdaptContext):
             dumper = cache[key1] = dumper.upgrade(obj, format)
             return dumper
 
+    def _get_none_oid(self):
+        try:
+            return self._none_oid
+        except AttributeError:
+            pass
+
+        try:
+            rv = self._none_oid = self._adapters.get_dumper(NoneType, PY_TEXT).oid
+        except KeyError:
+            raise e.InterfaceError("None dumper not found")
+
+        return rv
+
     def get_dumper_by_oid(self, oid: int, format: pq.Format) -> "Dumper":
         """
         Return a Dumper to dump an object to the type with given oid.
index 8f2b5f3ee202e570dacacab45395d440abe041e6..7adfd792397527c2c2bc060e5d39d211fe5aca5e 100644 (file)
@@ -76,6 +76,7 @@ cdef class Transformer:
     cdef readonly object types
     cdef readonly object formats
     cdef str _encoding
+    cdef int _none_oid
 
     # mapping class -> Dumper instance (auto, text, binary)
     cdef dict _auto_dumpers
@@ -107,6 +108,7 @@ cdef class Transformer:
             self.connection = None
 
         self.types = self.formats = None
+        self._none_oid = -1
 
     @classmethod
     def from_context(cls, context: Optional["AdaptContext"]):
@@ -361,6 +363,9 @@ cdef class Transformer:
         cdef object dumped
         cdef Py_ssize_t size
 
+        if self._none_oid < 0:
+            self._none_oid = self.adapters.get_dumper(NoneType, "s").oid
+
         dumpers = self._row_dumpers
 
         if dumpers:
@@ -406,7 +411,7 @@ cdef class Transformer:
                 fmt = (<RowDumper>dumper_ptr).format
             else:
                 dumped = None
-                oid = oids.INVALID_OID
+                oid = self._none_oid
                 fmt = PQ_TEXT
 
             Py_INCREF(dumped)