diff --git a/addons/hr/models/res_users.py b/addons/hr/models/res_users.py index a00e9b1d134..d4fe54e74e2 100644 --- a/addons/hr/models/res_users.py +++ b/addons/hr/models/res_users.py @@ -198,13 +198,7 @@ class User(models.Model): user.employee_id = self.env['hr.employee'].search([('id', 'in', user.employee_ids.ids), ('company_id', '=', self.env.company.id)], limit=1) def _search_company_employee(self, operator, value): - employees = self.env['hr.employee'].search([ - ('name', operator, value), - '|', - ('company_id', '=', self.env.company.id), - ('company_id', '=', False) - ], order='company_id ASC') - return [('id', 'in', employees.mapped('user_id').ids)] + return [('employee_ids', operator, value)] def action_create_employee(self): self.ensure_one() diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index 078f8778799..1ffea697f4a 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -231,7 +231,7 @@ class TestMailAPIPerformance(BaseMailPerformance): #voip module read activity_type during create leading to one less query in enterprise on action_feedback category = activity.activity_type_id.category - with self.assertQueryCount(__system__=18, emp=22): + with self.assertQueryCount(__system__=16, emp=20): activity.action_feedback(feedback='Zizisse Done !') @users('__system__', 'emp') @@ -248,7 +248,7 @@ class TestMailAPIPerformance(BaseMailPerformance): record.write({'name': 'Dupe write'}) - with self.assertQueryCount(__system__=19, emp=22): + with self.assertQueryCount(__system__=17, emp=20): record.action_close('Dupe feedback') self.assertEqual(record.activity_ids, self.env['mail.activity']) @@ -290,7 +290,7 @@ class TestMailAPIPerformance(BaseMailPerformance): }).create({}) composer.onchange_template_id_wrapper() - with self.assertQueryCount(__system__=39, emp=42): + with self.assertQueryCount(__system__=37, emp=40): composer.send_mail() # remove created partner to ensure tests are the same each run @@ -302,7 +302,7 @@ class TestMailAPIPerformance(BaseMailPerformance): def test_message_assignation_email(self): self.user_test.write({'notification_type': 'email'}) record = self.env['mail.test.track'].create({'name': 'Test'}) - with self.assertQueryCount(__system__=39, emp=40): + with self.assertQueryCount(__system__=37, emp=38): record.write({ 'user_id': self.user_test.id, }) @@ -355,7 +355,7 @@ class TestMailAPIPerformance(BaseMailPerformance): def test_message_post_one_email_notification(self): record = self.env['mail.test.simple'].create({'name': 'Test'}) - with self.assertQueryCount(__system__=32, emp=33): + with self.assertQueryCount(__system__=30, emp=31): record.message_post( body='

Test Post Performances with an email ping

', partner_ids=self.customer.ids, @@ -494,7 +494,7 @@ class TestMailComplexPerformance(BaseMailPerformance): self.container.message_subscribe(self.user_portal.partner_id.ids) record = self.container.with_user(self.env.user) - with self.assertQueryCount(__system__=68, emp=69): + with self.assertQueryCount(__system__=63, emp=64): record.message_post( body='

Test Post Performances

', message_type='comment', @@ -511,7 +511,7 @@ class TestMailComplexPerformance(BaseMailPerformance): record = self.container.with_user(self.env.user) template_id = self.env.ref('test_mail.mail_test_container_tpl').id - with self.assertQueryCount(__system__=78, emp=80): + with self.assertQueryCount(__system__=73, emp=75): record.message_post_with_template(template_id, message_type='comment', composition_mode='comment') self.assertEqual(record.message_ids[0].body, '

Adding stuff on %s

' % record.name) @@ -582,7 +582,7 @@ class TestMailComplexPerformance(BaseMailPerformance): }) rec1 = rec.with_context(active_test=False) # to see inactive records self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id) - with self.assertQueryCount(__system__=39, emp=40): + with self.assertQueryCount(__system__=37, emp=38): rec.write({'user_id': self.user_portal.id}) self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id) # write tracking message @@ -602,7 +602,7 @@ class TestMailComplexPerformance(BaseMailPerformance): customer_id = self.customer.id user_id = self.user_portal.id - with self.assertQueryCount(__system__=116, emp=117): + with self.assertQueryCount(__system__=109, emp=110): rec = self.env['mail.test.ticket'].create({ 'name': 'Test', 'container_id': container_id, @@ -631,7 +631,7 @@ class TestMailComplexPerformance(BaseMailPerformance): rec1 = rec.with_context(active_test=False) # to see inactive records self.assertEqual(rec1.message_partner_ids, self.user_portal.partner_id | self.env.user.partner_id) self.assertEqual(len(rec1.message_ids), 1) - with self.assertQueryCount(__system__=82, emp=82): + with self.assertQueryCount(__system__=77, emp=77): rec.write({ 'name': 'Test2', 'container_id': self.container.id, @@ -668,7 +668,7 @@ class TestMailComplexPerformance(BaseMailPerformance): rec1 = rec.with_context(active_test=False) # to see inactive records self.assertEqual(rec1.message_partner_ids, self.user_portal.partner_id | self.env.user.partner_id) - with self.assertQueryCount(__system__=90, emp=90): + with self.assertQueryCount(__system__=85, emp=85): rec.write({ 'name': 'Test2', 'container_id': container_id, @@ -701,7 +701,7 @@ class TestMailComplexPerformance(BaseMailPerformance): rec1 = rec.with_context(active_test=False) # to see inactive records self.assertEqual(rec1.message_partner_ids, self.partners | self.env.user.partner_id | self.user_portal.partner_id) - with self.assertQueryCount(__system__=32, emp=33): + with self.assertQueryCount(__system__=29, emp=30): rec.write({ 'name': 'Test2', 'customer_id': customer_id, @@ -951,7 +951,7 @@ class TestMailHeavyPerformancePost(BaseMailPerformance): ] self.attachements = self.env['ir.attachment'].with_user(self.env.user).create(self.vals) attachement_ids = self.attachements.ids - with self.assertQueryCount(emp=85): + with self.assertQueryCount(emp=81): self.cr.sql_log = self.warm and self.cr.sql_log_count record.with_context({}).message_post( body='

Test body

', diff --git a/addons/test_mail_full/tests/test_sms_performance.py b/addons/test_mail_full/tests/test_sms_performance.py index 42b6763e30c..8acdf795b6a 100644 --- a/addons/test_mail_full/tests/test_sms_performance.py +++ b/addons/test_mail_full/tests/test_sms_performance.py @@ -51,7 +51,7 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase): def test_message_sms_record_1_partner(self): record = self.test_record.with_user(self.env.user) pids = self.customer.ids - with self.mockSMSGateway(), self.assertQueryCount(employee=25): # test_mail_enterprise: 25 + with self.mockSMSGateway(), self.assertQueryCount(employee=23): # test_mail_enterprise: 25 messages = record._message_sms( body='Performance Test', partner_ids=pids, @@ -66,7 +66,7 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase): def test_message_sms_record_10_partners(self): record = self.test_record.with_user(self.env.user) pids = self.partners.ids - with self.mockSMSGateway(), self.assertQueryCount(employee=43): # test_mail_enterprise: 43 + with self.mockSMSGateway(), self.assertQueryCount(employee=41): # test_mail_enterprise: 43 messages = record._message_sms( body='Performance Test', partner_ids=pids, @@ -80,7 +80,7 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase): @warmup def test_message_sms_record_default(self): record = self.test_record.with_user(self.env.user) - with self.mockSMSGateway(), self.assertQueryCount(employee=28): # test_mail_enterprise: 28 + with self.mockSMSGateway(), self.assertQueryCount(employee=26): # test_mail_enterprise: 28 messages = record._message_sms( body='Performance Test', ) diff --git a/addons/test_mass_mailing/tests/test_performance.py b/addons/test_mass_mailing/tests/test_performance.py index b6d784f1723..5ae91d52aa6 100644 --- a/addons/test_mass_mailing/tests/test_performance.py +++ b/addons/test_mass_mailing/tests/test_performance.py @@ -51,7 +51,7 @@ class TestMassMailPerformance(TestMassMailPerformanceBase): }) # runbot needs +50 compared to local - with self.assertQueryCount(__system__=1914, marketing=1915): + with self.assertQueryCount(__system__=1714, marketing=1715): mailing.action_send_mail() self.assertEqual(mailing.sent, 50) @@ -91,7 +91,7 @@ class TestMassMailBlPerformance(TestMassMailPerformanceBase): }) # runbot needs +62 compared to local - with self.assertQueryCount(__system__=2241, marketing=2242): + with self.assertQueryCount(__system__=1993, marketing=1994): mailing.action_send_mail() self.assertEqual(mailing.sent, 50) diff --git a/odoo/addons/base/tests/test_expression.py b/odoo/addons/base/tests/test_expression.py index 4e1c6197b10..9cacf15ac5b 100644 --- a/odoo/addons/base/tests/test_expression.py +++ b/odoo/addons/base/tests/test_expression.py @@ -1130,14 +1130,14 @@ class TestMany2one(TransactionCase): self.Partner.search([('company_id', '=', self.company.id)]) with self.assertQueries([''' - SELECT "res_company".id - FROM "res_company" - WHERE ("res_company"."name"::text LIKE %s) - ORDER BY "res_company"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" - WHERE ("res_partner"."company_id" IN (%s)) + WHERE ("res_partner"."company_id" IN ( + SELECT "res_company".id + FROM "res_company" + WHERE ("res_company"."name"::text like %s) + ORDER BY "res_company"."id" + )) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([('company_id.name', 'like', self.company.name)]) @@ -1145,35 +1145,35 @@ class TestMany2one(TransactionCase): with self.assertQueries([''' SELECT "res_partner".id FROM "res_partner" - WHERE ("res_partner"."name"::text LIKE %s) - ORDER BY "res_partner"."id" - ''', ''' - SELECT "res_company".id - FROM "res_company" - WHERE ("res_company"."partner_id" IN (%s)) - ORDER BY "res_company"."id" - ''', ''' - SELECT "res_partner".id - FROM "res_partner" - WHERE ("res_partner"."company_id" IN (%s)) + WHERE ("res_partner"."company_id" IN ( + SELECT "res_company".id + FROM "res_company" + WHERE ("res_company"."partner_id" IN ( + SELECT "res_partner".id + FROM "res_partner" + WHERE ("res_partner"."name"::text LIKE %s) + ORDER BY "res_partner"."id" + )) + ORDER BY "res_company"."id" + )) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)]) with self.assertQueries([''' - SELECT "res_country".id - FROM "res_country" - WHERE ("res_country"."code"::text LIKE %s) - ORDER BY "res_country"."id" - ''', ''' - SELECT "res_company".id - FROM "res_company" - WHERE ("res_company"."name"::text LIKE %s) - ORDER BY "res_company"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" - WHERE (("res_partner"."company_id" IN (%s)) OR ("res_partner"."country_id" IN (%s))) + WHERE (("res_partner"."company_id" IN ( + SELECT "res_company".id + FROM "res_company" + WHERE ("res_company"."name"::text LIKE %s) + ORDER BY "res_company"."id" + )) OR ("res_partner"."country_id" IN ( + SELECT "res_country".id + FROM "res_country" + WHERE ("res_country"."code"::text LIKE %s) + ORDER BY "res_country"."id" + ))) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([ @@ -1182,6 +1182,23 @@ class TestMany2one(TransactionCase): ('country_id.code', 'like', 'BE'), ]) + def test_explicit_subquery(self): + self.Partner.search([('company_id.name', 'like', self.company.name)]) + + with self.assertQueries([''' + SELECT "res_partner".id + FROM "res_partner" + WHERE ("res_partner"."company_id" IN ( + SELECT "res_company".id + FROM "res_company" + WHERE ("res_company"."name"::text like %s) + ORDER BY "res_company"."id" + )) + ORDER BY "res_partner"."display_name" + ''']): + company_ids = self.company._search([('name', 'like', self.company.name)], order='id') + self.Partner.search([('company_id', 'in', company_ids)]) + def test_autojoin(self): # auto_join on the first many2one self.patch(self.Partner._fields['company_id'], 'auto_join', True) @@ -1199,16 +1216,16 @@ class TestMany2one(TransactionCase): self.Partner.search([('company_id.name', 'like', self.company.name)]) with self.assertQueries([''' - SELECT "res_partner".id - FROM "res_partner" - WHERE ("res_partner"."name"::text LIKE %s) - ORDER BY "res_partner"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" LEFT JOIN "res_company" AS "res_partner__company_id" ON ("res_partner"."company_id" = "res_partner__company_id"."id") - WHERE ("res_partner__company_id"."partner_id" IN (%s)) + WHERE ("res_partner__company_id"."partner_id" IN ( + SELECT "res_partner".id + FROM "res_partner" + WHERE ("res_partner"."name"::text LIKE %s) + ORDER BY "res_partner"."id" + )) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)]) @@ -1219,16 +1236,16 @@ class TestMany2one(TransactionCase): self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)]) with self.assertQueries([''' - SELECT "res_company".id - FROM "res_company" - LEFT JOIN "res_partner" AS "res_company__partner_id" ON - ("res_company"."partner_id" = "res_company__partner_id"."id") - WHERE ("res_company__partner_id"."name"::text LIKE %s) - ORDER BY "res_company"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" - WHERE ("res_partner"."company_id" IN (%s)) + WHERE ("res_partner"."company_id" IN ( + SELECT "res_company".id + FROM "res_company" + LEFT JOIN "res_partner" AS "res_company__partner_id" ON + ("res_company"."partner_id" = "res_company__partner_id"."id") + WHERE ("res_company__partner_id"."name"::text LIKE %s) + ORDER BY "res_company"."id" + )) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([('company_id.partner_id.name', 'like', self.company.name)]) @@ -1280,14 +1297,14 @@ class TestMany2one(TransactionCase): self.Partner.search([('company_id', 'like', self.company.name)]) with self.assertQueries([''' - SELECT "res_company".id - FROM "res_company" - WHERE ("res_company"."name"::text LIKE %s) - ORDER BY "res_company"."sequence", "res_company"."name" - ''', ''' SELECT "res_partner".id FROM "res_partner" - WHERE ("res_partner"."company_id" IN (%s)) + WHERE ("res_partner"."company_id" IN ( + SELECT "res_company".id + FROM "res_company" + WHERE ("res_company"."name"::text LIKE %s) + ORDER BY "res_company"."sequence", "res_company"."name" + )) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([('company_id', 'like', self.company.name)]) @@ -1322,37 +1339,31 @@ class TestOne2many(TransactionCase): self.Partner.search([('bank_ids', 'in', self.partner.bank_ids.ids)]) with self.assertQueries([''' - SELECT "res_partner_bank".id - FROM "res_partner_bank" - WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s) - ORDER BY "res_partner_bank"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" WHERE ("res_partner"."id" IN ( - SELECT "partner_id" FROM "res_partner_bank" WHERE "id" IN %s + SELECT "res_partner_bank"."partner_id" + FROM "res_partner_bank" + WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s) + ORDER BY "res_partner_bank"."id" )) ORDER BY "res_partner"."display_name" ''']): self.Partner.search([('bank_ids.sanitized_acc_number', 'like', '12')]) with self.assertQueries([''' - SELECT "res_partner_bank".id - FROM "res_partner_bank" - WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s) - ORDER BY "res_partner_bank"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" WHERE ("res_partner"."id" IN ( - SELECT "partner_id" FROM "res_partner_bank" WHERE "id" IN %s - )) - ORDER BY "res_partner"."id" - ''', ''' - SELECT "res_partner".id - FROM "res_partner" - WHERE ("res_partner"."id" IN ( - SELECT "parent_id" FROM "res_partner" WHERE "id" IN %s + SELECT "res_partner"."parent_id" + FROM "res_partner" + WHERE ("res_partner"."id" IN ( + SELECT "res_partner_bank"."partner_id" + FROM "res_partner_bank" + WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s) + ORDER BY "res_partner_bank"."id" + )) + ORDER BY "res_partner"."id" )) ORDER BY "res_partner"."display_name" ''']): @@ -1482,15 +1493,13 @@ class TestOne2many(TransactionCase): self.Partner.search([('bank_ids', 'like', '12')]) with self.assertQueries([''' - SELECT "res_partner_bank".id - FROM "res_partner_bank" - WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s) - ORDER BY "res_partner_bank"."sequence", "res_partner_bank"."id" - ''', ''' SELECT "res_partner".id FROM "res_partner" WHERE ("res_partner"."id" IN ( - SELECT "partner_id" FROM "res_partner_bank" WHERE "id" IN %s + SELECT "res_partner_bank"."partner_id" + FROM "res_partner_bank" + WHERE ("res_partner_bank"."sanitized_acc_number"::text LIKE %s) + ORDER BY "res_partner_bank"."sequence", "res_partner_bank"."id" )) ORDER BY "res_partner"."display_name" ''']): @@ -1522,37 +1531,37 @@ class TestMany2many(TransactionCase): self.User.search([('groups_id', 'in', group.ids)], order='id') with self.assertQueries([''' - SELECT "res_groups".id - FROM "res_groups" - WHERE ("res_groups"."color" = %s) - ORDER BY "res_groups"."id" - ''', ''' SELECT "res_users".id FROM "res_users" WHERE ("res_users"."id" IN ( - SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN %s + SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN ( + SELECT "res_groups".id + FROM "res_groups" + WHERE ("res_groups"."color" = %s) + ORDER BY "res_groups"."id" + ) )) ORDER BY "res_users"."id" ''']): self.User.search([('groups_id.color', '=', group.color)], order='id') with self.assertQueries([''' - SELECT "ir_rule".id - FROM "ir_rule" - WHERE ("ir_rule"."name"::text LIKE %s) - ORDER BY "ir_rule"."id" - ''', ''' - SELECT "res_groups".id - FROM "res_groups" - WHERE ("res_groups"."id" IN ( - SELECT "group_id" FROM "rule_group_rel" WHERE "rule_group_id" IN %s - )) - ORDER BY "res_groups"."id" - ''', ''' SELECT "res_users".id FROM "res_users" WHERE ("res_users"."id" IN ( - SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN %s + SELECT "uid" FROM "res_groups_users_rel" WHERE "gid" IN ( + SELECT "res_groups".id + FROM "res_groups" + WHERE ("res_groups"."id" IN ( + SELECT "group_id" FROM "rule_group_rel" WHERE "rule_group_id" IN ( + SELECT "ir_rule".id + FROM "ir_rule" + WHERE ("ir_rule"."name"::text LIKE %s) + ORDER BY "ir_rule"."id" + ) + )) + ORDER BY "res_groups"."id" + ) )) ORDER BY "res_users"."id" ''']): @@ -1567,15 +1576,15 @@ class TestMany2many(TransactionCase): self.User.search([('company_ids', 'like', self.company.name)], order='id') with self.assertQueries([''' - SELECT "res_company".id - FROM "res_company" - WHERE ("res_company"."name"::text LIKE %s) - ORDER BY "res_company"."sequence", "res_company"."name" - ''', ''' SELECT "res_users".id FROM "res_users" WHERE ("res_users"."id" IN ( - SELECT "user_id" FROM "res_company_users_rel" WHERE "cid" IN %s + SELECT "user_id" FROM "res_company_users_rel" WHERE "cid" IN ( + SELECT "res_company".id + FROM "res_company" + WHERE ("res_company"."name"::text LIKE %s) + ORDER BY "res_company"."sequence", "res_company"."name" + ) )) ORDER BY "res_users"."id" ''']): diff --git a/odoo/addons/test_performance/tests/test_performance.py b/odoo/addons/test_performance/tests/test_performance.py index 1a34881707c..4e14f6f9f9a 100644 --- a/odoo/addons/test_performance/tests/test_performance.py +++ b/odoo/addons/test_performance/tests/test_performance.py @@ -136,12 +136,12 @@ class TestPerformance(SavepointCaseWithUserDemo): # delete N lines: O(1) queries rec1.invalidate_cache() - with self.assertQueryCount(__system__=16, demo=16): + with self.assertQueryCount(__system__=14, demo=14): rec1.write({'line_ids': [(2, line.id) for line in lines[0]]}) self.assertEqual(rec1.line_ids, lines[1:]) rec1.invalidate_cache() - with self.assertQueryCount(__system__=14, demo=14): + with self.assertQueryCount(__system__=12, demo=12): rec1.write({'line_ids': [(2, line.id) for line in lines[1:]]}) self.assertFalse(rec1.line_ids) self.assertFalse(lines.exists()) @@ -151,12 +151,12 @@ class TestPerformance(SavepointCaseWithUserDemo): # unlink N lines: O(1) queries rec1.invalidate_cache() - with self.assertQueryCount(__system__=13, demo=13): + with self.assertQueryCount(__system__=11, demo=11): rec1.write({'line_ids': [(3, line.id) for line in lines[0]]}) self.assertEqual(rec1.line_ids, lines[1:]) rec1.invalidate_cache() - with self.assertQueryCount(__system__=14, demo=14): + with self.assertQueryCount(__system__=12, demo=12): rec1.write({'line_ids': [(3, line.id) for line in lines[1:]]}) self.assertFalse(rec1.line_ids) self.assertFalse(lines.exists()) @@ -190,7 +190,7 @@ class TestPerformance(SavepointCaseWithUserDemo): # empty N lines in rec2: O(1) queries rec1.invalidate_cache() - with self.assertQueryCount(__system__=15, demo=15): + with self.assertQueryCount(__system__=13, demo=13): rec2.write({'line_ids': [(5,)]}) self.assertFalse(rec2.line_ids) @@ -262,12 +262,12 @@ class TestPerformance(SavepointCaseWithUserDemo): # delete N tags: O(1) queries rec1.invalidate_cache() - with self.assertQueryCount(__system__=10, demo=10): + with self.assertQueryCount(__system__=8, demo=8): rec1.write({'tag_ids': [(2, tag.id) for tag in tags[0]]}) self.assertEqual(rec1.tag_ids, tags[1:]) rec1.invalidate_cache() - with self.assertQueryCount(__system__=10, demo=10): + with self.assertQueryCount(__system__=8, demo=8): rec1.write({'tag_ids': [(2, tag.id) for tag in tags[1:]]}) self.assertFalse(rec1.tag_ids) self.assertFalse(tags.exists()) diff --git a/odoo/models.py b/odoo/models.py index 5eb58b7aad4..f7e54cd4750 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -4397,14 +4397,11 @@ Fields: res = self._cr.fetchone() return res[0] - order_by = self._generate_order_by(order, query) - from_clause, where_clause, where_clause_params = query.get_sql() - where_str = where_clause and (" WHERE %s" % where_clause) or '' - limit_str = limit and ' limit %d' % limit or '' - offset_str = offset and ' offset %d' % offset or '' - query_str = 'SELECT "%s".id FROM ' % self._table + from_clause + where_str + order_by + limit_str + offset_str - self._cr.execute(query_str, where_clause_params) - return [row[0] for row in self._cr.fetchall()] + query.order = self._generate_order_by(order, query).replace('ORDER BY ', '') + query.limit = limit + query.offset = offset + + return query @api.returns(None, lambda value: value[0]) def copy_data(self, default=None): diff --git a/odoo/osv/expression.py b/odoo/osv/expression.py index e5733164567..87208bba372 100644 --- a/odoo/osv/expression.py +++ b/odoo/osv/expression.py @@ -225,9 +225,9 @@ def is_false(model, domain): stack.append(+1) elif token == FALSE_LEAF: stack.append(-1) - elif token[1] == 'in' and not token[2]: + elif token[1] == 'in' and not (isinstance(token[2], Query) or token[2]): stack.append(-1) - elif token[1] == 'not in' and not token[2]: + elif token[1] == 'not in' and not (isinstance(token[2], Query) or token[2]): stack.append(+1) else: stack.append(0) @@ -740,10 +740,14 @@ class expression(object): ids2 = right else: ids2 = [right] - if ids2 and inverse_is_int and domain: + if inverse_is_int and domain: ids2 = comodel._search([('id', 'in', ids2)] + domain, order='id') - if ids2 and comodel._fields[field.inverse_name].store: + if isinstance(ids2, Query) and comodel._fields[field.inverse_name].store: + op1 = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect' + subquery, subparams = ids2.select('"%s"."%s"' % (comodel._table, field.inverse_name)) + push(('id', op1, (subquery, subparams)), model, alias, internal=True) + elif ids2 and comodel._fields[field.inverse_name].store: op1 = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect' subquery = 'SELECT "%s" FROM "%s" WHERE "id" IN %%s' % (field.inverse_name, comodel._table) subparams = [tuple(ids2)] @@ -801,11 +805,18 @@ class expression(object): else: ids2 = [right] - # rewrite condition in terms of ids2 - subop = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect' - subquery = 'SELECT "%s" FROM "%s" WHERE "%s" IN %%s' % (rel_id1, rel_table, rel_id2) - ids2 = tuple(it for it in ids2 if it) or (None,) - push(('id', subop, (subquery, [ids2])), model, alias, internal=True) + if isinstance(ids2, Query): + # rewrite condition in terms of ids2 + subop = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect' + subquery, subparams = ids2.select() + query = 'SELECT "%s" FROM "%s" WHERE "%s" IN (%s)' % (rel_id1, rel_table, rel_id2, subquery) + push(('id', subop, (query, subparams)), model, alias, internal=True) + else: + # rewrite condition in terms of ids2 + subop = 'not inselect' if operator in NEGATIVE_TERM_OPERATORS else 'inselect' + subquery = 'SELECT "%s" FROM "%s" WHERE "%s" IN %%s' % (rel_id1, rel_table, rel_id2) + ids2 = tuple(it for it in ids2 if it) or (None,) + push(('id', subop, (subquery, [ids2])), model, alias, internal=True) else: # rewrite condition to match records with/without relations @@ -836,11 +847,11 @@ class expression(object): operator = dict_op[operator] res_ids = comodel.with_context(active_test=False)._name_search(right, [], operator, limit=None) if operator in NEGATIVE_TERM_OPERATORS: - res_ids.append(False) # TODO this should not be appended if False was in 'right' + res_ids = list(res_ids) + [False] # TODO this should not be appended if False was in 'right' return left, 'in', res_ids # resolve string-based m2o criterion into IDs if isinstance(right, str) or \ - right and isinstance(right, (tuple, list)) and all(isinstance(item, str) for item in right): + isinstance(right, (tuple, list)) and right and all(isinstance(item, str) for item in right): push(_get_expression(comodel, left, right, operator), model, alias) else: # right == [] or right == False and all other cases are handled by __leaf_to_sql() @@ -954,6 +965,10 @@ class expression(object): else: query = '(%s."%s" IS NULL)' % (table_alias, left) params = [] + elif isinstance(right, Query): + subquery, subparams = right.select() + query = '(%s."%s" %s (%s))' % (table_alias, left, operator, subquery) + params = subparams elif isinstance(right, (list, tuple)): if model._fields[left].type == "boolean": params = [it for it in (True, False) if it in right]