Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

root/trunk/storage/storepypgsql.py

Revision 123 (checked in by fumanchu, 8 years ago)

Fix for #36 (column names not correctly escaped). Changes to StorageManagerDB (and its subclasses):

  1. identifier(*atoms) method changed to sql_name(name, quoted=True).
  2. New column_name(classname, name, full=False, quoted=True) method.
  3. SQLDecompiler now calls the StorageManager's column_name method (so decompilers now take the SM as a constructor arg).
  4. identifier_length is now sql_name_max_length.
  5. identifier_caseless is now sql_name_caseless.
  • Property svn:eol-style set to native
Line 
1 # Use libpq directly to avoid all of the DB-API overhead.
2 from pyPgSQL import libpq
3 import datetime
4 import dejavu
5 from dejavu.storage import db
6
7
8 class AdapterToPgSQL(db.AdapterToSQL):
9    
10     like_escapes = [("%", r"\\%"), ("_", r"\\_")]
11
12
13 class PgSQLDecompiler(db.SQLDecompiler):
14    
15     def dejavu_icontainedby(self, op1, op2):
16         if isinstance(op1, db.ConstWrapper):
17             # Looking for text in a field. Use ILike (reverse terms).
18             return op2 + " ILIKE '%" + self.adapter.escape_like(op1) + "%'"
19         else:
20             # Looking for field in (a, b, c).
21             # Force all args to lowercase for case-insensitive comparison.
22             atoms = [self.adapter.coerce(x).lower() for x in op2.basevalue]
23             return "LOWER(%s) IN (%s)" % (op1, ", ".join(atoms))
24    
25     def dejavu_istartswith(self, x, y):
26         return x + " ILIKE '" + self.adapter.escape_like(y) + "%'"
27    
28     def dejavu_iendswith(self, x, y):
29         return x + " ILIKE '%" + self.adapter.escape_like(y) + "'"
30    
31     def dejavu_ieq(self, x, y):
32         # ILIKE with no wildcards should behave like ieq.
33         return x + " ILIKE '" + self.adapter.escape_like(y) + "'"
34    
35     def dejavu_year(self, x):
36         return "date_part('year', " + x + ")"
37
38
39
40 class StorageManagerPgSQL(db.StorageManagerDB):
41     """StoreManager to save and retrieve Units via pyPgSQL 1.35."""
42    
43     sql_name_max_length = 63
44     close_connection_method = 'finish'
45     decompiler = PgSQLDecompiler
46     toAdapter = AdapterToPgSQL()
47    
48     def __init__(self, name, arena, allOptions={}):
49         db.StorageManagerDB.__init__(self, name, arena, allOptions)
50        
51         # connstring = (host=h port=p dbname=d user=u password=p options=o tty=t)
52         self.connstring = allOptions[u'Connect']
53         atoms = self.connstring.split(" ")
54         for atom in atoms:
55             k, v = atom.split("=", 1)
56             setattr(self, k, v)
57    
58     def sql_name(self, name, quoted=True):
59         name = db.StorageManagerDB.sql_name(self, name, quoted)
60         if quoted:
61             name = '"' + name.replace('"', '""') + '"'
62         return name
63    
64     def _get_conn(self):
65         try:
66             return libpq.PQconnectdb(self.connstring)
67         except libpq.DatabaseError, x:
68             msg = x.args[0]
69             if msg.endswith('does not exist\n'):
70                 if self.CreateIfMissing:
71                     self.create_database()
72                     return libpq.PQconnectdb(self.connstring)
73             elif msg.startswith('could not connect'):
74                 raise db.OutOfConnectionsError
75             raise x
76    
77     def _template_conn(self):
78         atoms = self.connstring.split(" ")
79         tmplconn = ""
80         for atom in atoms:
81             k, v = atom.split("=", 1)
82             if k == 'dbname': v = 'template1'
83             tmplconn += "%s=%s " % (k, v)
84         return libpq.PQconnectdb(tmplconn)
85    
86     def create_database(self):
87         c = self._template_conn()
88         self.execute('CREATE DATABASE %s' % self.sql_name(self.dbname), c)
89         c.finish()
90    
91     def drop_database(self):
92         c = self._template_conn()
93         self.execute("DROP DATABASE %s;" % self.sql_name(self.dbname), c)
94         c.finish()
95    
96     def version(self):
97         c = self._template_conn()
98         v = c.version
99         c.finish()
100         return v
101    
102     def fetch(self, query, conn=None):
103         """fetch(query, conn=None) -> rowdata, columns."""
104         res = self.execute(query, conn)
105        
106         columns = []
107         if res.resultType != libpq.EMPTY_QUERY:
108             for index in xrange(res.nfields):
109                 columns.append((res.fname(index), res.ftype(index)))
110        
111         data = [[res.getvalue(row, col) for col in xrange(res.nfields)]
112                 for row in xrange(res.ntuples)]
113         res.clear()
114        
115         return data, columns
116
Note: See TracBrowser for help on using the browser.