details:   https://code.tryton.org/tryton/commit/96a32b2dc8be
branch:    7.8
user:      Cédric Krier <[email protected]>
date:      Wed Jul 15 00:26:03 2026 +0200
description:
        Define index using COALESCE for nullable Char fields

        Closes #14909
        (grafted from 525198c97acdd19820d581411b3af0f5bb6e4237)
diffstat:

 modules/account/tax.py                         |   4 ++--
 modules/analytic_account/account.py            |   2 +-
 modules/party/country.py                       |   5 ++++-
 modules/product/product.py                     |  20 +++++++++++++-------
 modules/purchase/product.py                    |   3 ++-
 modules/purchase/purchase.py                   |   3 ++-
 modules/purchase_blanket_agreement/purchase.py |   3 ++-
 modules/purchase_request_quotation/purchase.py |   4 ++--
 modules/sale/sale.py                           |   2 +-
 modules/sale_blanket_agreement/sale.py         |   3 ++-
 modules/sale_complaint/complaint.py            |   3 ++-
 modules/sale_opportunity/opportunity.py        |   3 ++-
 modules/sale_rental/sale.py                    |   4 +++-
 modules/sale_rental/setup.py                   |   2 +-
 modules/sale_subscription/subscription.py      |   2 +-
 modules/stock/location.py                      |   3 ++-
 modules/stock/shipment.py                      |   2 +-
 modules/web_user/user.py                       |   6 ++++--
 trytond/trytond/ir/translation.py              |  11 +++++++----
 trytond/trytond/ir/ui/view.py                  |   3 ++-
 20 files changed, 56 insertions(+), 32 deletions(-)

diffs (396 lines):

diff -r d778a7e8b04c -r 96a32b2dc8be modules/account/tax.py
--- a/modules/account/tax.py    Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/account/tax.py    Wed Jul 15 00:26:03 2026 +0200
@@ -8,7 +8,7 @@
 
 from sql import Literal
 from sql.aggregate import Sum
-from sql.conditionals import Case
+from sql.conditionals import Case, Coalesce
 
 from trytond import backend
 from trytond.i18n import gettext
@@ -164,7 +164,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.add(
-            Index(t, (t.code, Index.Similarity())))
+            Index(t, (Coalesce(t.code, ''), Index.Similarity())))
         for date in [cls.start_date, cls.end_date]:
             date.states = {
                 'readonly': (Bool(Eval('template', -1))
diff -r d778a7e8b04c -r 96a32b2dc8be modules/analytic_account/account.py
--- a/modules/analytic_account/account.py       Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/analytic_account/account.py       Wed Jul 15 00:26:03 2026 +0200
@@ -99,7 +99,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.add(
-            Index(t, (t.code, Index.Similarity())))
+            Index(t, (Coalesce(t.code, ''), Index.Similarity())))
         cls._order.insert(0, ('code', 'ASC'))
         cls._order.insert(1, ('name', 'ASC'))
 
diff -r d778a7e8b04c -r 96a32b2dc8be modules/party/country.py
--- a/modules/party/country.py  Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/party/country.py  Wed Jul 15 00:26:03 2026 +0200
@@ -1,6 +1,8 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
 
+from sql.conditionals import Coalesce
+
 from trytond.model import Index
 from trytond.pool import PoolMeta
 
@@ -15,7 +17,8 @@
         cls._sql_indexes.update({
                 Index(
                     t,
-                    (Index.Unaccent(t.city), Index.Similarity()),
+                    (Index.Unaccent(Coalesce(t.city, '')),
+                        Index.Similarity()),
                     (t.country, Index.Range()),
                     (t.subdivision, Index.Range())),
                 })
diff -r d778a7e8b04c -r 96a32b2dc8be modules/product/product.py
--- a/modules/product/product.py        Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/product/product.py        Wed Jul 15 00:26:03 2026 +0200
@@ -201,7 +201,8 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.code, Index.Similarity())),
+                Index(t, (Coalesce(t.code, ''), Index.Equality())),
+                Index(t, (Coalesce(t.code, ''), Index.Similarity())),
                 })
         cls._order.insert(0, ('rec_name', 'ASC'))
 
@@ -587,12 +588,17 @@
                     & (t.code != '')),
                 'product.msg_product_code_unique'),
             ]
-        cls._sql_indexes.add(
-            Index(t, (t.code, Index.Similarity(cardinality='high'))))
-        cls._sql_indexes.add(
-            Index(t,
-                (t.position, Index.Range(order='ASC NULLS FIRST')),
-                (t.id, Index.Range(order='ASC'))))
+        cls._sql_indexes.update({
+                Index(t,
+                    (Coalesce(t.code, ''),
+                        Index.Equality(cardinality='high'))),
+                Index(t,
+                    (Coalesce(t.code, ''),
+                        Index.Similarity(cardinality='high'))),
+                Index(t,
+                    (t.position, Index.Range(order='ASC NULLS FIRST')),
+                    (t.id, Index.Range(order='ASC'))),
+                })
 
         for attr in dir(Template):
             tfield = getattr(Template, attr)
diff -r d778a7e8b04c -r 96a32b2dc8be modules/purchase/product.py
--- a/modules/purchase/product.py       Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/purchase/product.py       Wed Jul 15 00:26:03 2026 +0200
@@ -5,6 +5,7 @@
 
 from sql import Literal
 from sql.aggregate import Count, Max
+from sql.conditionals import Coalesce
 
 from trytond.i18n import gettext
 from trytond.model import (
@@ -378,7 +379,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.code, Index.Similarity())),
+                Index(t, (Coalesce(t.code, ''), Index.Similarity())),
                 })
 
     @staticmethod
diff -r d778a7e8b04c -r 96a32b2dc8be modules/purchase/purchase.py
--- a/modules/purchase/purchase.py      Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/purchase/purchase.py      Wed Jul 15 00:26:03 2026 +0200
@@ -8,6 +8,7 @@
 
 from sql import Literal, Null
 from sql.aggregate import Count
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond import backend
@@ -267,7 +268,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(t, (t.party, Index.Range())),
                 Index(
                     t,
diff -r d778a7e8b04c -r 96a32b2dc8be 
modules/purchase_blanket_agreement/purchase.py
--- a/modules/purchase_blanket_agreement/purchase.py    Wed Jun 24 22:06:59 
2026 +0200
+++ b/modules/purchase_blanket_agreement/purchase.py    Wed Jul 15 00:26:03 
2026 +0200
@@ -6,6 +6,7 @@
 from itertools import groupby
 
 from sql import Null
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond.i18n import gettext
@@ -192,7 +193,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(
                     t, (t.state, Index.Equality(cardinality='low')),
                     where=t.state.in_(['draft', 'running'])),
diff -r d778a7e8b04c -r 96a32b2dc8be 
modules/purchase_request_quotation/purchase.py
--- a/modules/purchase_request_quotation/purchase.py    Wed Jun 24 22:06:59 
2026 +0200
+++ b/modules/purchase_request_quotation/purchase.py    Wed Jul 15 00:26:03 
2026 +0200
@@ -5,7 +5,7 @@
 from itertools import groupby
 
 from sql import Null
-from sql.conditionals import Case
+from sql.conditionals import Case, Coalesce
 from sql.functions import CharLength
 
 from trytond.i18n import gettext
@@ -140,7 +140,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(
                     t, (t.state, Index.Equality(cardinality='low')),
                     where=t.state.in_(['draft', 'sent'])),
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale/sale.py
--- a/modules/sale/sale.py      Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale/sale.py      Wed Jul 15 00:26:03 2026 +0200
@@ -336,7 +336,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(t, (t.party, Index.Range())),
                 Index(
                     t,
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale_blanket_agreement/sale.py
--- a/modules/sale_blanket_agreement/sale.py    Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_blanket_agreement/sale.py    Wed Jul 15 00:26:03 2026 +0200
@@ -6,6 +6,7 @@
 from itertools import groupby
 
 from sql import Null
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond.i18n import gettext
@@ -192,7 +193,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(
                     t, (t.state, Index.Equality(cardinality='low')),
                     where=t.state.in_(['draft', 'running'])),
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale_complaint/complaint.py
--- a/modules/sale_complaint/complaint.py       Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_complaint/complaint.py       Wed Jul 15 00:26:03 2026 +0200
@@ -6,6 +6,7 @@
 from decimal import Decimal
 
 from sql import Null
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond.i18n import gettext
@@ -138,7 +139,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(
                     t,
                     (t.state, Index.Equality(cardinality='low')),
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale_opportunity/opportunity.py
--- a/modules/sale_opportunity/opportunity.py   Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_opportunity/opportunity.py   Wed Jul 15 00:26:03 2026 +0200
@@ -4,6 +4,7 @@
 import datetime
 from itertools import groupby
 
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond.i18n import gettext
@@ -154,7 +155,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(t, (t.party, Index.Range())),
                 Index(
                     t,
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale_rental/sale.py
--- a/modules/sale_rental/sale.py       Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_rental/sale.py       Wed Jul 15 00:26:03 2026 +0200
@@ -5,6 +5,8 @@
 from decimal import Decimal
 from functools import partial
 
+from sql.conditionals import Coalesce
+
 from trytond.i18n import gettext
 from trytond.ir.attachment import AttachmentCopyMixin
 from trytond.ir.note import NoteCopyMixin
@@ -277,7 +279,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(t, (t.party, Index.Equality())),
                 Index(
                     t,
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale_rental/setup.py
--- a/modules/sale_rental/setup.py      Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_rental/setup.py      Wed Jul 15 00:26:03 2026 +0200
@@ -44,7 +44,7 @@
     download_url = 'http://downloads.tryton.org/%s.%s/' % (
         major_version, minor_version)
 
-requires = []
+requires = ['python-sql']
 for dep in info.get('depends', []):
     if not re.match(r'(ir|res)(\W|$)', dep):
         requires.append(get_require_version('trytond_%s' % dep))
diff -r d778a7e8b04c -r 96a32b2dc8be modules/sale_subscription/subscription.py
--- a/modules/sale_subscription/subscription.py Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_subscription/subscription.py Wed Jul 15 00:26:03 2026 +0200
@@ -172,7 +172,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 Index(
                     t,
                     (t.state, Index.Equality(cardinality='low')),
diff -r d778a7e8b04c -r 96a32b2dc8be modules/stock/location.py
--- a/modules/stock/location.py Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/stock/location.py Wed Jul 15 00:26:03 2026 +0200
@@ -5,6 +5,7 @@
 from decimal import Decimal
 
 from sql import Column
+from sql.conditionals import Coalesce
 
 from trytond.cache import Cache
 from trytond.i18n import gettext
@@ -198,7 +199,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.code, Index.Similarity())),
+                Index(t, (Coalesce(t.code, ''), Index.Similarity())),
                 Index(
                     t,
                     (t.left, Index.Range(cardinality='high')),
diff -r d778a7e8b04c -r 96a32b2dc8be modules/stock/shipment.py
--- a/modules/stock/shipment.py Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/stock/shipment.py Wed Jul 15 00:26:03 2026 +0200
@@ -66,7 +66,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 })
         cls._order = [
             ('effective_date', 'ASC NULLS LAST'),
diff -r d778a7e8b04c -r 96a32b2dc8be modules/web_user/user.py
--- a/modules/web_user/user.py  Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/web_user/user.py  Wed Jul 15 00:26:03 2026 +0200
@@ -89,10 +89,12 @@
             ]
         cls._sql_indexes.update({
                 Index(
-                    table, (table.email, Index.Equality(cardinality='high'))),
+                    table, (Coalesce(table.email, ''),
+                        Index.Equality(cardinality='high'))),
                 Index(
                     table,
-                    (table.email_token, Index.Equality(cardinality='high')),
+                    (Coalesce(table.email_token, ''),
+                        Index.Equality(cardinality='high')),
                     where=table.email_token != Null),
                 })
         cls._buttons.update({
diff -r d778a7e8b04c -r 96a32b2dc8be trytond/trytond/ir/translation.py
--- a/trytond/trytond/ir/translation.py Wed Jun 24 22:06:59 2026 +0200
+++ b/trytond/trytond/ir/translation.py Wed Jul 15 00:26:03 2026 +0200
@@ -12,7 +12,7 @@
 from relatorio.templates.opendocument import get_zip_file
 from sql import Column, Literal, Null
 from sql.aggregate import Max
-from sql.conditionals import Case
+from sql.conditionals import Case, Coalesce
 from sql.functions import CharLength, Position, Substring
 
 import trytond.config as config
@@ -112,9 +112,11 @@
 
         cls._sql_indexes.update({
                 Index(
-                    table, (Index.Unaccent(table.src), Index.Similarity())),
+                    table, (Index.Unaccent(Coalesce(table.src, '')),
+                        Index.Similarity())),
                 Index(
-                    table, (Index.Unaccent(table.value), Index.Similarity())),
+                    table, (Index.Unaccent(Coalesce(table.value, '')),
+                        Index.Similarity())),
                 Index(
                     table,
                     (table.type, Index.Equality(cardinality='low')),
@@ -122,7 +124,8 @@
                     (table.lang, Index.Equality(cardinality='low')),
                     (table.res_id, Index.Range()),
                     (table.fuzzy, Index.Equality(cardinality='low')),
-                    (Index.Unaccent(table.value), Index.Similarity())),
+                    (Index.Unaccent(Coalesce(table.value, '')),
+                        Index.Similarity())),
                 Index(
                     table,
                     (table.type, Index.Equality(cardinality='low')),
diff -r d778a7e8b04c -r 96a32b2dc8be trytond/trytond/ir/ui/view.py
--- a/trytond/trytond/ir/ui/view.py     Wed Jun 24 22:06:59 2026 +0200
+++ b/trytond/trytond/ir/ui/view.py     Wed Jul 15 00:26:03 2026 +0200
@@ -5,6 +5,7 @@
 
 from lxml import etree
 from sql import Literal, Null
+from sql.conditionals import Coalesce
 
 from trytond.cache import Cache, MemoryCache
 from trytond.i18n import gettext
@@ -726,7 +727,7 @@
                 table,
                 (table.user, Index.Range()),
                 (table.model, Index.Equality()),
-                (table.child_name, Index.Equality()),
+                (Coalesce(table.child_name, ''), Index.Equality()),
                 (table.domain, Index.Equality())))
 
     @staticmethod

Reply via email to