X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=PLC%2FPostgreSQL.py;h=ae6c55a0c22889c23f5b87c3a24241298002da18;hb=6e915d8a9ac5474c20482751ab6d24e6ce13aec9;hp=eced84e4037b0025291e05368830da5837e4f9a3;hpb=cc23df37cd243cb7446f372435c24813cdb1bcd5;p=plcapi.git diff --git a/PLC/PostgreSQL.py b/PLC/PostgreSQL.py index eced84e..ae6c55a 100644 --- a/PLC/PostgreSQL.py +++ b/PLC/PostgreSQL.py @@ -1,5 +1,5 @@ # -# PostgreSQL database interface. +# PostgreSQL database interface. # Sort of like DBI(3) (Database independent interface for Perl). # # Mark Huang @@ -13,13 +13,13 @@ psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) psycopg2.extensions.register_type(psycopg2._psycopg.UNICODEARRAY) import types -from types import StringTypes, NoneType import traceback -import commands +import subprocess import re from pprint import pformat -from PLC.Debug import profile, log +from PLC.Logger import logger +from PLC.Debug import profile from PLC.Faults import * from datetime import datetime as DateTimeType @@ -57,35 +57,62 @@ class PostgreSQL: self.connection.close() self.connection = None + @staticmethod + # From pgdb, and simplify code + def _quote(x): + if isinstance(x, DateTimeType): + x = str(x) + elif isinstance(x, str): + x = x.encode( 'utf-8' ) + + if isinstance(x, bytes): + x = "'%s'" % str(x).replace("\\", "\\\\").replace("'", "''") + elif isinstance(x, (int, float)): + pass + elif x is None: + x = 'NULL' + elif isinstance(x, (list, tuple, set)): + x = 'ARRAY[%s]' % ', '.join([str(_quote(x)) for x in x]) + elif hasattr(x, '__pg_repr__'): + x = x.__pg_repr__() + else: + raise PLCDBError('Cannot quote type %s' % type(x)) + return x + + def quote(self, value): """ Returns quoted version of the specified value. """ - # The pgdb._quote function is good enough for general SQL - # quoting, except for array types. - if isinstance (value, (types.ListType, types.TupleType, set)): - 'ARRAY[%s]' % ', '.join( [ str(self.quote(x)) for x in value ] ) - else: - try: - # up to PyGreSQL-3.x, function was pgdb._quote - import pgdb - return pgdb._quote(value) - except: - # with PyGreSQL-4.x, use psycopg2's adapt - from psycopg2.extensions import adapt - return adapt (value) + return PostgreSQL._quote (value) + +# following is an unsuccessful attempt to re-use lib code as much as possible +# def quote(self, value): +# # The pgdb._quote function is good enough for general SQL +# # quoting, except for array types. +# if isinstance (value, (types.ListType, types.TupleType, set)): +# 'ARRAY[%s]' % ', '.join( [ str(self.quote(x)) for x in value ] ) +# else: +# try: +# # up to PyGreSQL-3.x, function was pgdb._quote +# import pgdb +# return pgdb._quote(value) +# except: +# # with PyGreSQL-4.x, use psycopg2's adapt +# from psycopg2.extensions import adapt +# return adapt (value) @classmethod def param(self, name, value): # None is converted to the unquoted string NULL - if isinstance(value, NoneType): + if isinstance(value, type(None)): conversion = "s" # True and False are also converted to unquoted strings elif isinstance(value, bool): conversion = "s" elif isinstance(value, float): conversion = "f" - elif not isinstance(value, StringTypes): + elif not isinstance(value, str): conversion = "d" else: conversion = "s" @@ -148,36 +175,33 @@ class PostgreSQL: if not params: if self.debug: - print >> log,'execute0',query + logger.debug('execute0: {}'.format(query)) cursor.execute(query) - elif isinstance(params,dict): + elif isinstance(params, dict): if self.debug: - print >> log,'execute-dict: params',params,'query',query%params - cursor.execute(query,params) + logger.debug('execute-dict: params {} query {}' + .format(params, query%params)) + cursor.execute(query, params) elif isinstance(params,tuple) and len(params)==1: if self.debug: - print >> log,'execute-tuple',query%params[0] + logger.debug('execute-tuple {}'.format(query%params[0])) cursor.execute(query,params[0]) else: param_seq=(params,) if self.debug: for params in param_seq: - print >> log,'executemany',query%params + logger.debug('executemany {}'.format(query%params)) cursor.executemany(query, param_seq) (self.rowcount, self.description, self.lastrowid) = \ (cursor.rowcount, cursor.description, cursor.lastrowid) - except Exception, e: + except Exception as e: try: self.rollback() except: pass - uuid = commands.getoutput("uuidgen") - print >> log, "Database error %s:" % uuid - print >> log, e - print >> log, "Query:" - print >> log, query - print >> log, "Params:" - print >> log, pformat(params) + uuid = subprocess.getoutput("uuidgen") + message = "Database error {}: - Query {} - Params {}".format(uuid, query, pformat(params)) + logger.exception(message) raise PLCDBError("Please contact " + \ self.api.config.PLC_NAME + " Support " + \ "<" + self.api.config.PLC_MAIL_SUPPORT_ADDRESS + ">" + \ @@ -204,7 +228,7 @@ class PostgreSQL: # Return each row as a dictionary keyed on field name # (like DBI selectrow_hashref()). labels = [column[0] for column in self.description] - rows = [dict(zip(labels, row)) for row in rows] + rows = [dict(list(zip(labels, row))) for row in rows] if key_field is not None and key_field in labels: # Return rows as a dictionary keyed on the specified field @@ -219,7 +243,7 @@ class PostgreSQL: """ if hasattr(self, 'fields_cache'): - if self.fields_cache.has_key((table, notnull, hasdef)): + if (table, notnull, hasdef) in self.fields_cache: return self.fields_cache[(table, notnull, hasdef)] else: self.fields_cache = {}