Speed Improvement:

Nested Trees
	New Domains Bugfixes
	Compute multiple function fields at once (multi)

bzr revid: fp@tinyerp.com-20080817182829-dc60s4srja6ck0bw
This commit is contained in:
Fabien Pinckaers 2008-08-17 20:28:29 +02:00
parent 61d07d0771
commit d88fb99fe4
7 changed files with 145 additions and 92 deletions

View File

@ -270,25 +270,26 @@ def load_module_graph(cr, graph, status=None, **kwargs):
cr.execute('update ir_module_module set demo=%s where name=%s', (True, package.name))
package_todo.append(package.name)
cr.execute("update ir_module_module set state='installed' where state in ('to upgrade', 'to install') and name=%s", (package.name,))
# check if all model of the module have at least a access rule.
cr.execute(""" SELECT name
FROM ir_model m
WHERE EXISTS (SELECT 1
FROM ir_model_data
WHERE module = %s
AND model = m.name
)
AND NOT EXISTS (SELECT 1
FROM ir_model_access
WHERE model_id = m.id
)
""", (m,))
for (model,) in cr.fetchall():
logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon:%s:object %s has no access rules!' % (m,model,))
# check if all model of the module have at least a access rule.
# TODO: improve this query which is very slow !!!
cr.execute(""" SELECT name
FROM ir_model m
WHERE EXISTS (SELECT 1
FROM ir_model_data
WHERE module = %s
AND model = m.name
)
AND NOT EXISTS (SELECT 1
FROM ir_model_access
WHERE model_id = m.id
)
""", (m,))
cr.commit()
for (model,) in cr.fetchall():
logger.notifyChannel('init', netsvc.LOG_WARNING, 'addon:%s:object %s has no access rules!' % (m,model,))
cr.commit()
statusi+=1
pool = pooler.get_pool(cr.dbname)

View File

@ -17,12 +17,11 @@ class expression(object):
and element in ['&', '|', '!']
def _is_leaf(self, element):
return isinstance(element, tuple) \
return (isinstance(element, tuple) or isinstance(element, list)) \
and len(element) == 3 \
and element[1] in ('=', '!=', '<>', '<=', '<', '>', '>=', '=like', 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in', 'child_of')
and element[1] in ('=', '!=', '<>', '<=', '<', '>', '>=', '=like', 'like', 'not like', 'ilike', 'not ilike', 'in', 'not in', 'child_of', 'inselect')
def __execute_recursive_in(self, cr, s, f, w, ids):
#deprecated -> use _left and _right...
res = []
for i in range(0, len(ids), cr.IN_MAX):
subids = ids[i:i+cr.IN_MAX]
@ -50,23 +49,30 @@ class expression(object):
if not self.__exp:
return self
def _rec_get(ids, table, parent):
if table._parent_store:
def _rec_get(ids, table, parent, left='id', prefix=''):
if table._parent_store and (not table.pool._init):
# TODO: Improve where joins are implemented for many with '.', replace by:
# doms += ['&',(prefix+'.parent_left','<',o.parent_right),(prefix+'.parent_left','>=',o.parent_left)]
doms = []
for o in table.browse(cr, uid, ids, context=context):
if doms:
doms.insert(0,'|')
doms += ['&',('parent_left','<',o.parent_right),('parent_left','>=',o.parent_left)]
return table.search(cr, uid, doms, context=context)
if prefix:
return [(left, 'in', table.search(cr, uid, doms, context=context))]
return doms
else:
if not ids:
return []
ids2 = table.search(cr, uid, [(parent, 'in', ids)], context=context)
return ids + _rec_get(ids2, table, parent)
return [(prefix+left, 'in', ids2+ids)]
self.__main_table = table
for i, e in enumerate(self.__exp):
i = -1
while i+1<len(self.__exp):
i+=1
e = self.__exp[i]
if self._is_operator(e) or e == self.__DUMMY_LEAF:
continue
left, operator, right = e
@ -83,8 +89,8 @@ class expression(object):
field = working_table._columns.get(fargs[0], False)
if not field:
if left == 'id' and operator == 'child_of':
right += _rec_get(right, working_table, working_table._parent_name)
self.__exp[i] = ('id', 'in', right)
dom = _rec_get(right, working_table, working_table._parent_name)
self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
continue
field_obj = table.pool.get(field._obj)
@ -152,11 +158,10 @@ class expression(object):
self.__operator = 'in'
if field._obj != working_table._name:
right = ids2 + _rec_get(ids2, field_obj, working_table._parent_name)
dom = _rec_get(ids2, field_obj, working_table._parent_name, left=left, prefix=left+'.')
else:
right = ids2 + _rec_get(ids2, working_table, left)
left = 'id'
self.__exp[i] = (left, 'in', right)
dom = _rec_get(ids2, working_table, left)
self.__exp = self.__exp[:i] + dom + self.__exp[i+1:]
else:
if isinstance(right, basestring):
res_ids = field_obj.name_search(cr, uid, right, [], operator)

View File

@ -63,6 +63,7 @@ class _column(object):
_properties = False
_type = 'unknown'
_obj = None
_multi = False
_symbol_c = '%s'
_symbol_f = _symbol_set
_symbol_set = (_symbol_c, _symbol_f)
@ -553,13 +554,17 @@ class function(_column):
_type = 'function'
_properties = True
def __init__(self, fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type='float', fnct_search=None, obj=None, method=False, store=False, **args):
#
# multi: compute several fields in one call
#
def __init__(self, fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type='float', fnct_search=None, obj=None, method=False, store=False, multi=False, **args):
_column.__init__(self, **args)
self._obj = obj
self._method = method
self._fnct = fnct
self._fnct_inv = fnct_inv
self._arg = arg
self._multi = multi
if 'relation' in args:
self._obj = args['relation']
self._fnct_inv_arg = fnct_inv_arg
@ -585,12 +590,10 @@ class function(_column):
if not values:
values = {}
res = {}
table = obj._table
if self._method:
# TODO get HAS to receive uid for permissions !
return self._fnct(obj, cr, user, ids, name, self._arg, context)
else:
return self._fnct(cr, table, ids, name, self._arg, context)
return self._fnct(cr, obj._table, ids, name, self._arg, context)
def set(self, cr, obj, id, name, value, user=None, context=None):
if not context:

View File

@ -1257,7 +1257,7 @@ class orm(orm_template):
_log_access = True
_table = None
_protected = ['read','write','create','default_get','perm_read','unlink','fields_get','fields_view_get','search','name_get','distinct_field_get','name_search','copy','import_data','search_count']
def __parent_store_compute(self, cr):
def _parent_store_compute(self, cr):
logger = netsvc.Logger()
logger.notifyChannel('init', netsvc.LOG_INFO, 'Computing parent left and right for table %s...' % (self._table, ))
def browse_rec(root, pos=0):
@ -1375,7 +1375,7 @@ class orm(orm_template):
if not default:
cr.execute("UPDATE \"%s\" SET \"%s\"=NULL" % (self._table, k))
else:
cr.execute("UPDATE \"%s\" SET \"%s\"=%%s" % (self._table, k), (default,))
cr.execute("UPDATE \"%s\" SET \"%s\"='%s'" % (self._table, k, default))
if isinstance(f, fields.function):
cr.execute('select id from '+self._table)
ids_lst = map(lambda x: x[0], cr.fetchall())
@ -1513,7 +1513,7 @@ class orm(orm_template):
cr.execute(line2)
cr.commit()
if store_compute:
self.__parent_store_compute(cr)
self._parent_store_compute(cr)
def __init__(self, cr):
super(orm, self).__init__(cr)
@ -1758,11 +1758,33 @@ class orm(orm_template):
# all non inherited fields for which the attribute whose name is in load is False
fields_post = filter(lambda x: x in self._columns and not getattr(self._columns[x], load), fields)
# Compute POST fields
todo = {}
for f in fields_post:
# get the value of that field for all records/ids
res2 = self._columns[f].get(cr, self, ids, f, user, context=context, values=res)
for record in res:
record[f] = res2[record['id']]
todo.setdefault(self._columns[f]._multi, [])
todo[self._columns[f]._multi].append(f)
print 'TODO', todo
for key,val in todo.items():
if key:
print '* KEY', key
res2 = self._columns[val[0]].get(cr, self, ids, val, user, context=context, values=res)
print '* KEY RES', res2, val, ids
for pos in range(len(val)):
for record in res:
record[val[pos]] = res2[record['id']][pos]
else:
print 'KEY NOT', key
for f in val:
res2 = self._columns[f].get(cr, self, ids, f, user, context=context, values=res)
for record in res:
record[f] = res2[record['id']]
#for f in fields_post:
# # get the value of that field for all records/ids
# res2 = self._columns[f].get(cr, self, ids, f, user, context=context, values=res)
# for record in res:
# record[f] = res2[record['id']]
readonly = None
for vals in res:
@ -2052,47 +2074,50 @@ class orm(orm_template):
self._validate(cr, user, ids, context)
# TODO: use _order to set dest at the right position and not first node of parent
if self._parent_store and self._parent_name in vals:
cr.execute('select parent_left,parent_right from '+self._table+' where id=%d', (vals[self._parent_name],))
res = cr.fetchone()
if res:
pleft,pright = res
if self._parent_store and (self._parent_name in vals):
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
cr.execute('select max(parent_right),max(parent_right)+1 from '+self._table)
pleft,pright = cr.fetchone()
cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%d',ids))+')', ids)
dest = pleft + 1
for cleft,cright,cid in cr.fetchall():
if cleft > pleft:
treeshift = pleft - cleft + 1
leftbound = pleft+1
rightbound = cleft-1
cwidth = cright-cleft+1
leftrange = cright
rightrange = pleft
cr.execute('select parent_left,parent_right from '+self._table+' where id=%d', (vals[self._parent_name],))
res = cr.fetchone()
if res:
pleft,pright = res
else:
treeshift = pleft - cright
leftbound = cright + 1
rightbound = pleft
cwidth = cleft-cright-1
leftrange = pleft+1
rightrange = cleft
cr.execute('UPDATE '+self._table+'''
SET
parent_left = CASE
WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d
WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d
ELSE parent_left
END,
parent_right = CASE
WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d
WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d
ELSE parent_right
END
WHERE
parent_left<%d OR parent_right>%d;
''', (leftbound,rightbound,cwidth,cleft,cright,treeshift,leftbound,rightbound,
cwidth,cleft,cright,treeshift,leftrange,rightrange))
cr.execute('select max(parent_right),max(parent_right)+1 from '+self._table)
pleft,pright = cr.fetchone()
cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%d',ids))+')', ids)
dest = pleft + 1
for cleft,cright,cid in cr.fetchall():
if cleft > pleft:
treeshift = pleft - cleft + 1
leftbound = pleft+1
rightbound = cleft-1
cwidth = cright-cleft+1
leftrange = cright
rightrange = pleft
else:
treeshift = pleft - cright
leftbound = cright + 1
rightbound = pleft
cwidth = cleft-cright-1
leftrange = pleft+1
rightrange = cleft
cr.execute('UPDATE '+self._table+'''
SET
parent_left = CASE
WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d
WHEN parent_left BETWEEN %d AND %d THEN parent_left + %d
ELSE parent_left
END,
parent_right = CASE
WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d
WHEN parent_right BETWEEN %d AND %d THEN parent_right + %d
ELSE parent_right
END
WHERE
parent_left<%d OR parent_right>%d;
''', (leftbound,rightbound,cwidth,cleft,cright,treeshift,leftbound,rightbound,
cwidth,cleft,cright,treeshift,leftrange,rightrange))
if 'read_delta' in context:
del context['read_delta']
@ -2206,16 +2231,19 @@ class orm(orm_template):
self._validate(cr, user, [id_new], context)
if self._parent_store:
parent = vals.get(self._parent_name, False)
if parent:
cr.execute('select parent_left from '+self._table+' where id=%d', (parent,))
pleft = cr.fetchone()[0]
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
cr.execute('select max(parent_right) from '+self._table)
pleft = cr.fetchone()[0] or 0
cr.execute('update '+self._table+' set parent_left=%d,parent_right=%d', (pleft+1,pleft+2))
cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%d', (pleft,))
cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%d', (pleft,))
parent = vals.get(self._parent_name, False)
if parent:
cr.execute('select parent_left from '+self._table+' where id=%d', (parent,))
pleft = cr.fetchone()[0]
else:
cr.execute('select max(parent_right) from '+self._table)
pleft = cr.fetchone()[0] or 0
cr.execute('update '+self._table+' set parent_left=%d,parent_right=%d', (pleft+1,pleft+2))
cr.execute('update '+self._table+' set parent_left=parent_left+2 where parent_left>%d', (pleft,))
cr.execute('update '+self._table+' set parent_right=parent_right+2 where parent_right>%d', (pleft,))
wf_service = netsvc.LocalService("workflow")
wf_service.trg_create(user, self._name, id_new, cr)
@ -2281,7 +2309,7 @@ class orm(orm_template):
# records unless they were explicitely asked for
if 'active' in self._columns and (active_test and context.get('active_test', True)):
if args:
args = ['&', ('active', '=', 1)] + args
args.insert(0, ('active', '=', 1))
else:
args = [('active', '=', 1)]

View File

@ -60,6 +60,8 @@ class osv_pool(netsvc.Service):
self.created = []
self._sql_error = {}
self._store_function = {}
self._init = True
self._init_parent = {}
netsvc.Service.__init__(self, 'object_proxy', audience='')
self.joinGroup('web-services')
self.exportMethod(self.exportedMethods)
@ -68,6 +70,17 @@ class osv_pool(netsvc.Service):
self.exportMethod(self.execute)
self.exportMethod(self.execute_cr)
def init_set(self, cr, mode):
if mode<>self._init:
if mode:
self._init_parent={}
if not mode:
for o in self._init_parent:
self.get(o)._parent_store_compute(cr)
self._init = mode
return True
return False
def execute_cr(self, cr, uid, obj, method, *args, **kw):
try:
object = pooler.get_pool(cr.dbname).get(obj)

View File

@ -54,6 +54,10 @@ def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False)
pool = osv.osv.osv_pool()
pool_dic[db_name] = pool
addons.load_modules(db, force_demo, status, update_module)
cr = db.cursor()
pool.init_set(cr, False)
cr.commit()
cr.close()
if not update_module:
import report

View File

@ -59,7 +59,6 @@ class fake_cursor:
self.dbname = dbname
def execute(self, sql, params=None):
print sql, params
if not params:
params=()
def base_string(s):