33e4d1a3b1a19ae02ca187696551133323f6d4ac
[odoo/odoo.git] / bin / sql_db.py
1 ##############################################################################
2 #
3 # Copyright (c) 2004-2008 Tiny SPRL (http://tiny.be) All Rights Reserved.
4 #
5 # $Id$
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 import psycopg
30 import tools
31 import sys,os
32
33 #try:
34 #       import decimal
35 #except ImportError:
36 #       from tools import decimal
37
38
39 import re
40
41 from mx import DateTime as mdt
42 re_from = re.compile('.* from "?([a-zA-Z_0-9]+)"? .*$');
43 re_into = re.compile('.* into "?([a-zA-Z_0-9]+)"? .*$');
44
45 class fake_cursor:
46         nbr = 0
47         _tables = {}
48         sql_from_log = {}
49         sql_into_log = {}
50         sql_log = False
51         count = 0
52
53         def __init__(self, db, con, dbname):
54                 self.db = db
55                 self.obj = db.cursor()
56                 self.con = con
57                 self.dbname = dbname
58
59         def execute(self, sql, params=None):
60                 if not params:
61                         params=()
62                 def base_string(s):
63                         if isinstance(s, unicode):
64                                 return s.encode('utf-8')
65                         return s
66                 p=map(base_string, params)
67                 if isinstance(sql, unicode):
68                         sql = sql.encode('utf-8')
69                 if self.sql_log:
70                         now = mdt.now()
71                 if p:
72                         res = self.obj.execute(sql, p)
73                 else:
74                         res = self.obj.execute(sql)
75                 if self.sql_log:
76                         print "SQL LOG query:", sql
77                         print "SQL LOG params:", repr(p)
78                         self.count+=1
79                         res_from = re_from.match(sql.lower())
80                         if res_from:
81                                 self.sql_from_log.setdefault(res_from.group(1), [0, 0])
82                                 self.sql_from_log[res_from.group(1)][0] += 1
83                                 self.sql_from_log[res_from.group(1)][1] += mdt.now() - now
84                         res_into = re_into.match(sql.lower())
85                         if res_into:
86                                 self.sql_into_log.setdefault(res_into.group(1), [0, 0])
87                                 self.sql_into_log[res_into.group(1)][0] += 1
88                                 self.sql_into_log[res_into.group(1)][1] += mdt.now() - now
89                 return res
90
91         def print_log(self, type='from'):
92                 print "SQL LOG %s:" % (type,)
93                 if type == 'from':
94                         logs = self.sql_from_log.items()
95                 else:
96                         logs = self.sql_into_log.items()
97                 logs.sort(lambda x, y: cmp(x[1][1], y[1][1]))
98                 sum=0
99                 for r in logs:
100                         print "table:", r[0], ":", str(r[1][1]), "/", r[1][0]
101                         sum+= r[1][1]
102                 print "SUM:%s/%d"% (sum, self.count)
103
104         def close(self):
105                 if self.sql_log:
106                         self.print_log('from')
107                         self.print_log('into')
108                 self.obj.close()
109
110                 # This force the cursor to be freed, and thus, available again. It is 
111                 # important because otherwise we can overload the server very easily 
112                 # because of a cursor shortage (because cursors are not garbage
113                 # collected as fast as they should). The problem is probably due in 
114                 # part because browse records keep a reference to the cursor.
115                 del self.obj
116
117         def __getattr__(self, name):
118                 return getattr(self.obj, name)
119
120 class fakedb:
121         def __init__(self, truedb, dbname):
122                 self.truedb = truedb
123                 self.dbname = dbname
124                 
125         def cursor(self):
126                 return fake_cursor(self.truedb, {}, self.dbname)
127
128 def decimalize(symb):
129         if symb is None: return None
130         if isinstance(symb, float):
131                 return decimal.Decimal('%f' % symb)
132         return decimal.Decimal(symb)
133
134 def db_connect(db_name, serialize=0):
135         host = tools.config['db_host'] and "host=%s" % tools.config['db_host'] or ''
136         port = tools.config['db_port'] and "port=%s" % tools.config['db_port'] or ''
137         name = "dbname=%s" % db_name
138         user = tools.config['db_user'] and "user=%s" % tools.config['db_user'] or ''
139         password = tools.config['db_password'] and "password=%s" % tools.config['db_password'] or ''
140         maxconn = int(tools.config['db_maxconn']) or 64
141         tdb = psycopg.connect('%s %s %s %s %s' % (host, port, name, user, password),
142                         serialize=serialize, maxconn=maxconn)
143         fdb = fakedb(tdb, db_name)
144         return fdb
145
146 def init():
147         #define DATEOID 1082, define TIMESTAMPOID 1114 see pgtypes.h
148         psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x))
149         psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x))
150         psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x))
151         #psycopg.register_type(psycopg.new_type((700, 701, 1700), 'decimal', decimalize))
152
153 psycopg.register_type(psycopg.new_type((1082,), "date", lambda x:x))
154 psycopg.register_type(psycopg.new_type((1083,), "time", lambda x:x))
155 psycopg.register_type(psycopg.new_type((1114,), "datetime", lambda x:x))
156