Don't commit in the middle of loading modules
[odoo/odoo.git] / bin / sql_db.py
1 ##############################################################################
2 #
3 # Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
4 #
5 # $Id: pooler.py 1310 2005-09-08 20:40:15Z pinky $
6 #
7 # WARNING: This program as such is intended to be used by professional
8 # programmers who take the whole responsability of assessing all potential
9 # consequences resulting from its eventual inadequacies and bugs
10 # End users who are looking for a ready-to-use solution with commercial
11 # garantees and support are strongly adviced to contract a Free Software
12 # Service Company
13 #
14 # This program is Free Software; you can redistribute it and/or
15 # modify it under the terms of the GNU General Public License
16 # as published by the Free Software Foundation; either version 2
17 # of the License, or (at your option) any later version.
18 #
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 # GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License
25 # along with this program; if not, write to the Free Software
26 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27 #
28 ##############################################################################
29
30 import psycopg
31 import tools
32 import sys,os
33
34 #try:
35 #       import decimal
36 #except ImportError:
37 #       from tools import decimal
38
39
40 import re
41
42 from mx import DateTime as mdt
43 re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$');
44 re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$');
45
46 class fake_cursor:
47         nbr = 0
48         _tables = {}
49         sql_from_log = {}
50         sql_into_log = {}
51         sql_log = False
52         count = 0
53
54         def __init__(self, db, con, dbname):
55                 self.db = db
56                 self.obj = db.cursor()
57                 self.con = con
58                 self.dbname = dbname
59
60         def execute_not_run(self,*args):
61                 #if not fake_cursor.nbr % 1:
62                 #       print 'sql: ',fake_cursor.nbr, args
63                 res = re.match('^select.* from ([a-zA-Z_]+) .*$', args[0], re.I)
64                 if res:
65                         fake_cursor._tables.setdefault(res.group(1), 0)
66                         fake_cursor._tables[res.group(1)] += 1
67
68                 #else:
69                 #       if len(args)>1:
70                 #               print 'sql: ',fake_cursor.nbr, args[0], args[1]
71                 #       else:
72                 #               print 'sql: ',fake_cursor.nbr, args[0]
73
74                 #if not fake_cursor.nbr % 5000:
75                 #       ct = []
76                 #       for t,c in fake_cursor._tables.items():
77                 #               ct.append([c,t])
78                 #       ct.sort()
79                 #       ct.reverse()
80                 #       print 'After %d queries' % (fake_cursor.nbr,)
81                 #       for line in ct[:50]:
82                 #               print '    %s: %d' % (line[1], line[0])
83
84                 #if len(args)>1:
85                 #       print 'sql: ',fake_cursor.nbr, args[0], args[1]
86                 #else:
87                 #       print 'sql: ',fake_cursor.nbr, args[0]
88
89                 fake_cursor.nbr += 1
90                 return self.obj.execute(*args)
91
92         def execute(self, sql, params=None):
93                 if not params:
94                         params=()
95                 def base_string(s):
96                         if isinstance(s, unicode):
97                                 return s.encode('utf-8')
98                         return s
99                 p=map(base_string, params)
100                 if isinstance(sql, unicode):
101                         sql = sql.encode('utf-8')
102                 if self.sql_log:
103                         now = mdt.now()
104                 if p:
105                         res = self.obj.execute(sql, p)
106                 else:
107                         res = self.obj.execute(sql)
108                 if self.sql_log:
109                         self.count+=1
110                         res_from = re_from.match(sql.lower())
111                         if res_from:
112                                 self.sql_from_log.setdefault(res_from.group(1), [0, 0])
113                                 self.sql_from_log[res_from.group(1)][0] += 1
114                                 self.sql_from_log[res_from.group(1)][1] += mdt.now() - now
115                         res_into = re_into.match(sql.lower())
116                         if res_into:
117                                 self.sql_into_log.setdefault(res_into.group(1), [0, 0])
118                                 self.sql_into_log[res_into.group(1)][0] += 1
119                                 self.sql_into_log[res_into.group(1)][1] += mdt.now() - now
120                 return res
121
122         def print_log(self, type='from'):
123                 print "SQL LOG %s:" % (type,)
124                 if type == 'from':
125                         logs = self.sql_from_log.items()
126                 else:
127                         logs = self.sql_into_log.items()
128                 logs.sort(lambda x, y: cmp(x[1][1], y[1][1]))
129                 sum=0
130                 for r in logs:
131                         print "table:", r[0], ":", str(r[1][1]), "/", r[1][0]
132                         sum+= r[1][1]
133                 print "SUM:%s/%d"% (sum, self.count)
134
135         def close(self):
136                 if self.sql_log:
137                         self.print_log('from')
138                         self.print_log('into')
139                 self.obj.close()
140
141                 # This force the cursor to be freed, and thus, available again. It is 
142                 # important because otherwise we can overload the server very easily 
143                 # because of a cursor shortage (because cursors are not garbage
144                 # collected as fast as they should). The problem is probably due in 
145                 # part because browse records keep a reference to the cursor.
146                 del self.obj
147
148         def __getattr__(self, name):
149                 return getattr(self.obj, name)
150
151 class fakedb:
152         def __init__(self, truedb, dbname):
153                 self.truedb = truedb
154                 self.dbname = dbname
155                 
156         def cursor(self):
157                 return fake_cursor(self.truedb, {}, self.dbname)
158
159 def decimalize(symb):
160         if symb is None: return None
161         if isinstance(symb, float):
162                 return decimal.Decimal('%f' % symb)
163         return decimal.Decimal(symb)
164
165 def db_connect(db_name):
166         host = tools.config['db_host'] and "host=%s" % tools.config['db_host'] or ''
167         port = tools.config['db_port'] and "port=%s" % tools.config['db_port'] or ''
168         name = "dbname=%s" % db_name
169         user = tools.config['db_user'] and "user=%s" % tools.config['db_user'] or ''
170         password = tools.config['db_password'] and "password=%s" % tools.config['db_password'] or ''
171         maxconn = int(tools.config['db_maxconn']) or 64
172         tdb = psycopg.connect('%s %s %s %s %s' % (host, port, name, user, password), serialize=0, maxconn=maxconn)
173         fdb = fakedb(tdb, db_name)
174         return fdb
175
176 def init():
177         #define DATEOID 1082, define TIMESTAMPOID 1114 see pgtypes.h
178         psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x))
179         psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x))
180         psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x))
181         #psycopg.register_type(psycopg.new_type((700, 701, 1700), 'decimal', decimalize))
182
183 psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x))
184 psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x))
185 psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x))
186