From c89156435407cc14e47c88d6db40e92e66bd4180 Mon Sep 17 00:00:00 2001 From: Mike Bonnet 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 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