/usr/lib/python2.7/dist-packages/koji/db.py is in koji-common 1.10.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | # python library
# db utilities for koji
# Copyright (c) 2005-2014 Red Hat, Inc.
#
# Koji is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation;
# version 2.1 of the License.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this software; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Authors:
# Mike McLean <mikem@redhat.com>
import logging
import sys
import pgdb
import time
import traceback
_quoteparams = None
try:
from pgdb import _quoteparams
except ImportError:
pass
assert pgdb.threadsafety >= 1
import context
## Globals ##
_DBopts = None
# A persistent connection to the database.
# A new connection will be created whenever
# Apache forks a new worker, and that connection
# will be used to service all requests handled
# by that worker.
# This probably doesn't need to be a ThreadLocal
# since Apache is not using threading,
# but play it safe anyway.
_DBconn = context.ThreadLocal()
class DBWrapper:
def __init__(self, cnx):
self.cnx = cnx
def __getattr__(self, key):
if not self.cnx:
raise StandardError, 'connection is closed'
return getattr(self.cnx, key)
def cursor(self, *args, **kw):
if not self.cnx:
raise StandardError, 'connection is closed'
return CursorWrapper(self.cnx.cursor(*args, **kw))
def close(self):
# Rollback any uncommitted changes and clear the connection so
# this DBWrapper is no longer usable after close()
if not self.cnx:
raise StandardError, 'connection is closed'
self.cnx.cursor().execute('ROLLBACK')
#We do this rather than cnx.rollback to avoid opening a new transaction
#If our connection gets recycled cnx.rollback will be called then.
self.cnx = None
class CursorWrapper:
def __init__(self, cursor):
self.cursor = cursor
self.logger = logging.getLogger('koji.db')
def __getattr__(self, key):
return getattr(self.cursor, key)
def _timed_call(self, method, args, kwargs):
start = time.time()
ret = getattr(self.cursor,method)(*args,**kwargs)
self.logger.debug("%s operation completed in %.4f seconds", method, time.time() - start)
return ret
def fetchone(self,*args,**kwargs):
return self._timed_call('fetchone',args,kwargs)
def fetchall(self,*args,**kwargs):
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
else:
quote = lambda a,b: a % b
try:
return quote(operation, parameters)
except Exception:
self.logger.exception('Unable to quote query:\n%s\nParameters: %s', operation, parameters)
return "INVALID QUERY"
def execute(self, operation, parameters=()):
debug = self.logger.isEnabledFor(logging.DEBUG)
if debug:
self.logger.debug(self.quote(operation, parameters))
start = time.time()
try:
ret = self.cursor.execute(operation, parameters)
except Exception:
self.logger.error('Query failed. Query was: %s', self.quote(operation, parameters))
raise
if debug:
self.logger.debug("Execute operation completed in %.4f seconds", time.time() - start)
return ret
## Functions ##
def provideDBopts(**opts):
global _DBopts
if _DBopts is None:
_DBopts = opts
def setDBopts(**opts):
global _DBopts
_DBopts = opts
def getDBopts():
return _DBopts
def connect():
logger = logging.getLogger('koji.db')
global _DBconn
if hasattr(_DBconn, 'conn'):
# Make sure the previous transaction has been
# closed. This is safe to call multiple times.
conn = _DBconn.conn
try:
# Under normal circumstances, the last use of this connection
# will have issued a raw ROLLBACK to close the transaction. To
# avoid 'no transaction in progress' warnings (depending on postgres
# configuration) we open a new one here.
# Should there somehow be a transaction in progress, a second
# BEGIN will be a harmless no-op, though there may be a warning.
conn.cursor().execute('BEGIN')
conn.rollback()
return DBWrapper(conn)
except pgdb.Error:
del _DBconn.conn
#create a fresh connection
opts = _DBopts
if opts is None:
opts = {}
try:
conn = pgdb.connect(**opts)
except Exception:
logger.error(''.join(traceback.format_exception(*sys.exc_info())))
raise
# XXX test
# return conn
_DBconn.conn = conn
return DBWrapper(conn)
if __name__ == "__main__":
setDBopts( database = "test", user = "test")
print "This is a Python library"
|