From c89156435407cc14e47c88d6db40e92e66bd4180 Mon Sep 17 00:00:00 2001
From: Mike Bonnet <mikeb@redhat.com>
Date: Dec 14 2016 13:06:01 +0000
Subject: [PATCH 1/2] convert from pygresql to psycopg2


---

diff --git a/koji/db.py b/koji/db.py
index 9e23d3b..681eb93 100644
--- a/koji/db.py
+++ b/koji/db.py
@@ -23,16 +23,21 @@
 
 import logging
 import sys
-import pgdb
+import psycopg2
+import psycopg2.extensions
+# don't convert timestamp fields to DateTime objects
+del psycopg2.extensions.string_types[1114]
+del psycopg2.extensions.string_types[1184]
+del psycopg2.extensions.string_types[1082]
+del psycopg2.extensions.string_types[1083]
+del psycopg2.extensions.string_types[1266]
 import time
 import traceback
-_quoteparams = None
-try:
-    from pgdb import _quoteparams
-except ImportError:  # pragma: no cover
-    pass
-assert pgdb.threadsafety >= 1
 import context
+import re
+
+POSITIONAL_RE = re.compile(r'%[a-z]')
+NAMED_RE = re.compile(r'%\(([^\)]+)\)[a-z]')
 
 ## Globals ##
 _DBopts = None
@@ -92,10 +97,8 @@ class CursorWrapper:
         return self._timed_call('fetchall', args, kwargs)
 
     def quote(self, operation, parameters):
-        if _quoteparams is not None:
-            quote = _quoteparams
-        elif hasattr(self.cursor, "_quoteparams"):
-            quote = self.cursor._quoteparams
+        if hasattr(self.cursor, "mogrify"):
+            quote = self.cursor.mogrify
         else:
             quote = lambda a, b: a % b
         try:
@@ -104,8 +107,27 @@ class CursorWrapper:
             self.logger.exception('Unable to quote query:\n%s\nParameters: %s', operation, parameters)
             return "INVALID QUERY"
 
+    def preformat(self, sql, params):
+        """psycopg2 requires all variable placeholders to use the string (%s) datatype,
+        regardless of the actual type of the data. Format the sql string to be compliant.
+        It also requires IN parameters to be in tuple rather than list format."""
+        sql = POSITIONAL_RE.sub(r'%s', sql)
+        sql = NAMED_RE.sub(r'%(\1)s', sql)
+        if isinstance(params, dict):
+            for name, value in params.items():
+                if isinstance(value, list):
+                    params[name] = tuple(value)
+        else:
+            if isinstance(params, tuple):
+                params = list(params)
+            for i, item in enumerate(params):
+                if isinstance(item, list):
+                    params[i] = tuple(item)
+        return sql, params
+
     def execute(self, operation, parameters=()):
         debug = self.logger.isEnabledFor(logging.DEBUG)
+        operation, parameters = self.preformat(operation, parameters)
         if debug:
             self.logger.debug(self.quote(operation, parameters))
             start = time.time()
@@ -123,7 +145,7 @@ class CursorWrapper:
 def provideDBopts(**opts):
     global _DBopts
     if _DBopts is None:
-        _DBopts = opts
+        _DBopts = dict(filter(lambda i: i[1] is not None, opts.items()))
 
 def setDBopts(**opts):
     global _DBopts
@@ -149,14 +171,14 @@ def connect():
             conn.cursor().execute('BEGIN')
             conn.rollback()
             return DBWrapper(conn)
-        except pgdb.Error:
+        except psycopg2.Error:
             del _DBconn.conn
     #create a fresh connection
     opts = _DBopts
     if opts is None:
         opts = {}
     try:
-        conn = pgdb.connect(**opts)
+        conn = psycopg2.connect(**opts)
     except Exception:
         logger.error(''.join(traceback.format_exception(*sys.exc_info())))
         raise

From e3a8f259e5ff3e6d737b7577fd73ac5ed1604a2f Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Dec 14 2016 13:11:08 +0000
Subject: [PATCH 2/2] add psycopg2 requires to spec


---

diff --git a/koji.spec b/koji.spec
index 004d626..774593a 100644
--- a/koji.spec
+++ b/koji.spec
@@ -52,7 +52,7 @@ License: LGPLv2 and GPLv2
 # rpmdiff lib (from rpmlint) is GPLv2 (only)
 Requires: httpd
 Requires: mod_wsgi
-Requires: postgresql-python
+Requires: python-psycopg2
 %if 0%{?rhel} == 5
 Requires: python-simplejson
 %endif
@@ -153,7 +153,7 @@ virtual machine. This package is not required for most installations.
 Summary: Koji Utilities
 Group: Applications/Internet
 License: LGPLv2
-Requires: postgresql-python
+Requires: python-psycopg2
 Requires: %{name} = %{version}-%{release}
 %if %{use_systemd}
 Requires(post): systemd
@@ -171,7 +171,7 @@ License: LGPLv2
 Requires: httpd
 Requires: mod_wsgi
 Requires: mod_auth_kerb
-Requires: postgresql-python
+Requires: python-psycopg2
 Requires: python-cheetah
 Requires: %{name} = %{version}-%{release}
 Requires: python-krbV >= 1.0.13

