details:   https://code.tryton.org/tryton/commit/525198c97acd
branch:    default
user:      Cédric Krier <[email protected]>
date:      Wed Jun 24 22:07:52 2026 +0200
description:
        Define index using COALESCE for nullable Char fields

        Closes #14909
diffstat:

 modules/account/tax.py                         |   4 ++--
 modules/analytic_account/account.py            |   2 +-
 modules/party/country.py                       |   5 ++++-
 modules/product/product.py                     |  20 +++++++++++++-------
 modules/project/work.py                        |  11 ++++++++---
 modules/purchase/product.py                    |   2 +-
 modules/purchase/purchase.py                   |   3 ++-
 modules/purchase_blanket_agreement/purchase.py |   3 ++-
 modules/purchase_request_quotation/purchase.py |   4 ++--
 modules/quality/quality.py                     |   3 ++-
 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/pyproject.toml             |   2 +-
 modules/sale_rental/sale.py                    |   4 +++-
 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                  |   2 +-
 22 files changed, 64 insertions(+), 36 deletions(-)

diffs (428 lines):

diff -r 776fe202ed6f -r 525198c97acd modules/account/tax.py
--- a/modules/account/tax.py    Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/account/tax.py    Wed Jun 24 22:07:52 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
@@ -163,7 +163,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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 2026 +0200
@@ -98,7 +98,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 776fe202ed6f -r 525198c97acd modules/party/country.py
--- a/modules/party/country.py  Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/party/country.py  Wed Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd modules/product/product.py
--- a/modules/product/product.py        Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/product/product.py        Wed Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd modules/project/work.py
--- a/modules/project/work.py   Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/project/work.py   Wed Jun 24 22:07:52 2026 +0200
@@ -5,6 +5,7 @@
 from collections import defaultdict
 
 from sql import Null
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond.cache import Cache
@@ -257,9 +258,13 @@
                 'project.msg_work_number_unique'),
             ]
         cls._sql_indexes.update({
-                Index(t, (t.number, Index.Equality(cardinality='high'))),
-                Index(t, (t.number, Index.Similarity(cardinality='high'))),
-                Index(t, (t.path, Index.Similarity(begin=True))),
+                Index(t,
+                    (Coalesce(t.number, ''),
+                        Index.Equality(cardinality='high'))),
+                Index(t,
+                    (Coalesce(t.number, ''),
+                        Index.Similarity(cardinality='high'))),
+                Index(t, (Coalesce(t.path, ''), Index.Similarity(begin=True))),
                 })
 
     @classmethod
diff -r 776fe202ed6f -r 525198c97acd modules/purchase/product.py
--- a/modules/purchase/product.py       Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/purchase/product.py       Wed Jun 24 22:07:52 2026 +0200
@@ -335,7 +335,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 776fe202ed6f -r 525198c97acd modules/purchase/purchase.py
--- a/modules/purchase/purchase.py      Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/purchase/purchase.py      Wed Jun 24 22:07:52 2026 +0200
@@ -8,6 +8,7 @@
 
 from sql import Null
 from sql.aggregate import Count
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond import backend
@@ -269,7 +270,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 776fe202ed6f -r 525198c97acd 
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 Jun 24 22:07:52 
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 776fe202ed6f -r 525198c97acd 
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 Jun 24 22:07:52 
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 776fe202ed6f -r 525198c97acd modules/quality/quality.py
--- a/modules/quality/quality.py        Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/quality/quality.py        Wed Jun 24 22:07:52 2026 +0200
@@ -5,6 +5,7 @@
 from functools import wraps
 from random import Random
 
+from sql.conditionals import Coalesce
 from sql.functions import CharLength
 
 from trytond.i18n import gettext, lazy_gettext
@@ -412,7 +413,7 @@
         super().__setup__()
         t = cls.__table__()
         cls._sql_indexes.update({
-                Index(t, (t.reference, Index.Similarity())),
+                Index(t, (Coalesce(t.reference, ''), Index.Similarity())),
                 })
         cls._transitions |= {
             ('pending', 'passed'),
diff -r 776fe202ed6f -r 525198c97acd modules/sale/sale.py
--- a/modules/sale/sale.py      Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale/sale.py      Wed Jun 24 22:07:52 2026 +0200
@@ -338,7 +338,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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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 import backend
@@ -139,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')),
diff -r 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd modules/sale_rental/pyproject.toml
--- a/modules/sale_rental/pyproject.toml        Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/sale_rental/pyproject.toml        Wed Jun 24 22:07:52 2026 +0200
@@ -52,7 +52,7 @@
 "" = "trytond/modules/sale_rental"
 
 [tool.hatch.metadata.hooks.tryton]
-dependencies = []
+dependencies = ['python-sql']
 copyright = 'COPYRIGHT'
 readme = 'README.rst'
 
diff -r 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd modules/stock/location.py
--- a/modules/stock/location.py Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/stock/location.py Wed Jun 24 22:07:52 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
@@ -195,7 +196,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 776fe202ed6f -r 525198c97acd modules/stock/shipment.py
--- a/modules/stock/shipment.py Wed Jun 24 22:06:59 2026 +0200
+++ b/modules/stock/shipment.py Wed Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 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
 from sql.operators import Concat
 
@@ -121,9 +121,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')),
@@ -131,7 +133,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 776fe202ed6f -r 525198c97acd 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 Jun 24 22:07:52 2026 +0200
@@ -844,7 +844,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