pgconsole/database.py
changeset 10 f3a1b9792cc9
child 76 3a41b351b122
equal deleted inserted replaced
9:2fcc8ef0b97d 10:f3a1b9792cc9
       
     1 import psycopg2
       
     2 import psycopg2.extensions
       
     3 import psycopg2.extras
       
     4 
       
     5 
       
     6 class DatabaseError(Exception):
       
     7     def __init__(self, msg, query=None):
       
     8         self.query = query
       
     9         Exception.__init__(self, msg)
       
    10 
       
    11 
       
    12 class BadConnectionError(Exception):
       
    13     pass
       
    14 
       
    15 
       
    16 class Row(dict):
       
    17     def __getattr__(self, key):
       
    18         return self[key]
       
    19 
       
    20 
       
    21 class Database:
       
    22     def __init__(self):
       
    23         # pool of database connections
       
    24         # indexed by conninfo, items are lists of connections
       
    25         self.pool = {}
       
    26         # number of unused connections per conninfo to keep open
       
    27         self.pool_keep_open = 1
       
    28 
       
    29 
       
    30     def __del__(self):
       
    31         for conninfo in self.pool.keys():
       
    32             for conn in self.pool[conninfo]:
       
    33                 conn.close()
       
    34 
       
    35 
       
    36     def connect(self, conninfo):
       
    37         try:
       
    38             conn = psycopg2.connect(conninfo, async=1)
       
    39             psycopg2.extras.wait_select(conn)
       
    40         except psycopg2.DatabaseError, e:
       
    41             raise DatabaseError(str(e))
       
    42         return conn
       
    43 
       
    44 
       
    45     def get_conn(self, conninfo):
       
    46         if not conninfo in self.pool:
       
    47             self.pool[conninfo] = []
       
    48             return self.connect(conninfo)
       
    49         else:
       
    50             conn = None
       
    51             while len(self.pool[conninfo]) and conn is None:
       
    52                 conn = self.pool[conninfo].pop()
       
    53                 if conn.closed:
       
    54                     conn = None
       
    55             if conn is None:
       
    56                 return self.connect(conninfo)
       
    57         return conn
       
    58 
       
    59 
       
    60     def put_conn(self, conninfo, conn):
       
    61         if len(self.pool[conninfo]) >= self.pool_keep_open:
       
    62             conn.close()
       
    63         else:
       
    64             self.pool[conninfo].append(conn)
       
    65 
       
    66 
       
    67     def execute(self, q, args=[]):
       
    68         conn = self.get_conn()
       
    69         try:
       
    70             curs = conn.cursor()
       
    71             curs.execute(q, args)
       
    72             psycopg2.extras.wait_select(curs.connection)
       
    73 #            conn.commit()
       
    74         except psycopg2.OperationalError, e:
       
    75             # disconnected?
       
    76 #            conn.rollback()
       
    77             conn.close()
       
    78             raise BadConnectionError(str(e))
       
    79         except psycopg2.DatabaseError, e:
       
    80 #            conn.rollback()
       
    81             raise DatabaseError(str(e), curs.query)
       
    82         return curs
       
    83 
       
    84 
       
    85     def finish(self, curs):
       
    86         self.put_conn(curs.connection)
       
    87 
       
    88 
       
    89     def row(self, curs, row):
       
    90         return Row(zip([x[0] for x in curs.description], row))
       
    91 
       
    92 
       
    93     def fetchone(self, curs):
       
    94         return self.row(curs, curs.fetchone())
       
    95 
       
    96 
       
    97     def fetchall(self, curs):
       
    98         rows = curs.fetchall()
       
    99         return [self.row(curs, row) for row in rows]
       
   100 
       
   101