diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 65c6c10e42c..464b203b29d 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -761,6 +761,15 @@ class many2many(_column): return rel, id1, id2 = self._sql_names(model) obj = model.pool.get(self._obj) + + def link(ids): + # beware of duplicates when inserting + query = """ INSERT INTO {rel} ({id1}, {id2}) + (SELECT %s, unnest(%s)) EXCEPT (SELECT {id1}, {id2} FROM {rel} WHERE {id1}=%s) + """.format(rel=rel, id1=id1, id2=id2) + for sub_ids in cr.split_for_in_conditions(ids): + cr.execute(query, (id, list(sub_ids), id)) + for act in values: if not (isinstance(act, list) or isinstance(act, tuple)) or not act: continue @@ -774,10 +783,7 @@ class many2many(_column): elif act[0] == 3: cr.execute('delete from '+rel+' where ' + id1 + '=%s and '+ id2 + '=%s', (id, act[1])) elif act[0] == 4: - # following queries are in the same transaction - so should be relatively safe - cr.execute('SELECT 1 FROM '+rel+' WHERE '+id1+' = %s and '+id2+' = %s', (id, act[1])) - if not cr.fetchone(): - cr.execute('insert into '+rel+' ('+id1+','+id2+') values (%s,%s)', (id, act[1])) + link([act[1]]) elif act[0] == 5: cr.execute('delete from '+rel+' where ' + id1 + ' = %s', (id,)) elif act[0] == 6: @@ -789,8 +795,7 @@ class many2many(_column): d1 = '' cr.execute('delete from '+rel+' where '+id1+'=%s AND '+id2+' IN (SELECT '+rel+'.'+id2+' FROM '+rel+', '+','.join(tables)+' WHERE '+rel+'.'+id1+'=%s AND '+rel+'.'+id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2) - for act_nbr in act[2]: - cr.execute('insert into '+rel+' ('+id1+','+id2+') values (%s, %s)', (id, act_nbr)) + link(act[2]) # # TODO: use a name_search