From 14fec2c154cd3b1dad185072ce65a3c5889f8540 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Sun, 2 Aug 2026 20:16:14 +0530 Subject: [PATCH] test(postgres): probe whether MAX() over text agrees across engines DO NOT MERGE -- this exists to make CI answer a question. The parity effort wrapped many descriptive text columns in Max() to satisfy strict GROUP BY, justified as "Max() returns the value MariaDB picked arbitrarily". Where the column genuinely varies within its group that does not hold: Max() over text is a sort, and the engines sort text differently. MariaDB's utf8mb4 collations fold case but treat punctuation and spaces as significant. glibc's en_US.UTF-8 -- what the Linux CI Postgres runs -- ignores punctuation at the primary level, so max('ITEM-C', 'ITEMB') should be 'ITEMB' on MariaDB and 'ITEM-C' on Postgres. These assertions encode MariaDB's answers. They pass on macOS (BSD/ICU collation, which happens to agree). If the Linux Postgres job fails them, the Max()-over-varying-text sites are a live parity gap and not only a row-coherence one. --- erpnext/tests/test_text_collation_parity.py | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 erpnext/tests/test_text_collation_parity.py diff --git a/erpnext/tests/test_text_collation_parity.py b/erpnext/tests/test_text_collation_parity.py new file mode 100644 index 00000000000..f2d26cfb2c1 --- /dev/null +++ b/erpnext/tests/test_text_collation_parity.py @@ -0,0 +1,35 @@ +# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + +from erpnext.tests.utils import ERPNextTestSuite + + +def max_of(values): + rows = " UNION ALL ".join(f"SELECT {frappe.db.escape(value)} AS v" for value in values) + return frappe.db.sql(f"SELECT MAX(v) FROM ({rows}) t")[0][0] + + +class TestTextCollationParity(ERPNextTestSuite): + """Does MAX() over text pick the same value on MariaDB and PostgreSQL? + + The PostgreSQL parity effort wrapped many descriptive text columns in Max() to satisfy strict + GROUP BY, on the reasoning that Max() returns the value MariaDB picked arbitrarily. Where the + column genuinely varies within its group that reasoning does not hold: Max() over text is a + sort, and the two engines sort text by different rules. + + These expectations are MariaDB's (utf8mb4 case-insensitive collation: case folded, punctuation + and spaces significant). A failure on the PostgreSQL job means the Max()-over-varying-text + sites are a live parity gap, not only a row-coherence one. + """ + + def test_case_is_folded_not_byte_ordered(self): + self.assertEqual(max_of(["apple", "Banana", "cherry"]), "cherry") + self.assertEqual(max_of(["abc", "ABD"]), "ABD") + + def test_punctuation_and_space_are_significant(self): + # glibc en_US.UTF-8 ignores punctuation at the primary level and would answer "ITEM-C"; + # MariaDB compares '-' (0x2D) against 'B' (0x42) and answers "ITEMB" + self.assertEqual(max_of(["ITEM-C", "ITEMB"]), "ITEMB") + self.assertEqual(max_of(["Stores - TC", "StoresbTC"]), "StoresbTC")