Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vQUBf-008mK7-1f for pgsql-bugs@arkaria.postgresql.org; Tue, 02 Dec 2025 17:29:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vQUBe-009FPw-18 for pgsql-bugs@arkaria.postgresql.org; Tue, 02 Dec 2025 17:29:14 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vQUBe-009FPm-0I for pgsql-bugs@lists.postgresql.org; Tue, 02 Dec 2025 17:29:14 +0000 Received: from lahtoruutu.iki.fi ([185.185.170.37]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vQUBb-002mfg-0h for pgsql-bugs@lists.postgresql.org; Tue, 02 Dec 2025 17:29:13 +0000 Received: from [10.0.2.15] (unknown [130.41.208.2]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: hlinnaka) by lahtoruutu.iki.fi (Postfix) with ESMTPSA id 4dLSS31YP0z49Pvd; Tue, 02 Dec 2025 19:29:07 +0200 (EET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=lahtoruutu; t=1764696547; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IykyI7aeJCsumD5vxS1HfbRYwgNXH6nHpkCkX6HZo+s=; b=srmTAZzNDHsXBOBZy6Pa2vx2k1IuvSSNlRQcdLdsx38JJIxO9lDgdcL9BK6bgmXuV4eCT5 yUPXueVnPGHXedOjNOTs/9NzDi6xGyrZClu3onnEK4BCn+KCOkXYu+7sFJUL5Kz3NVo7Xo 5JIMOyEpAUaFCSU/J3NHA0obY1oLo58qnXsXN6FOljpeACsVvkoOtC6eZHKlDx+0sgemk3 6cU8h5rv2Wlg/K5hLvG6goko8yL22BtZoOxD7i2zLTjLHY70b9mb+0xGyjWaU4EE6ZEPDT 1zfJcglxWLWZo/Gl4by7VaRWC+1re8ePInqsmibd9qgtQcLd0zGklvV6We+Img== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=iki.fi; s=lahtoruutu; t=1764696547; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IykyI7aeJCsumD5vxS1HfbRYwgNXH6nHpkCkX6HZo+s=; b=jJPOJvvrS25D2arR9tD3nGIqm2FisXFDIdGw628lMzRUVbozWEsuqzv84RWNwwU9l5YNsd jspJjXOJZnM9DVDfJqk+SdObNLW0KvVuZXmbs5vd3xJm+9r+jvyBzzjppqAVoCqwfXKcoI AJnQ9TXWi9dsssuLYf6rfKf0ku+AkPKn/5gkOMzrTWZwirfZKEK6/KuXk6b4va8+2MxPdZ ot2YxkPNRdxcd8SfyfBCbXOshpA7lJ38ZzlgsunOK2zVI9YYyIfcDo6FPu/GE01qMKF+JX IIkLQI7XAN49CONxhOP6N6EgT9BwVMZTBrj0pY0uZddUavx6rEhYmgCpXdMTMA== ARC-Authentication-Results: i=1; ORIGINATING; auth=pass smtp.auth=hlinnaka smtp.mailfrom=hlinnaka@iki.fi ARC-Seal: i=1; a=rsa-sha256; d=iki.fi; s=lahtoruutu; cv=none; t=1764696547; b=RC5F14KpkZlPj1mXfJIOdvp+B/BQ888PBNVlcm8lLpB9/iUcmMvG/Lp9VWG5jpBr/WpwtB MEmhlhcaSllvnKQTRzBTdwCGRKJLuF987iWz2saXn/S8Y+nLDD4WKRMGoljqow9ClObQm/ GwngEEv9rETFNDgaG1fzrm7YZDZQi8vyKGwBznb/to3JOukJED3mxSmBlEQH3CAjkikMf0 Jpv3iun2b7awfaZPqR/ycgbD8q2nzExgciRIUs6396p1WZEshlm1hSPFCPn/+wNtgr4+vt U6Nl48+I/rJ05o4Y14b4tIhZo1dHpj8l/3dTnou2I1zeGH3ONcyaJlPUYwOpqg== Message-ID: <6387cb3e-aec8-41a0-acef-bacdbfb435db@iki.fi> Date: Tue, 2 Dec 2025 19:29:06 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: BUG #19341: REPLACE() fails to match final character when using nondeterministic ICU collation From: Heikki Linnakangas To: Laurenz Albe , adam.warland@infor.com, pgsql-bugs@lists.postgresql.org References: <19341-1d9a22915edfec58@postgresql.org> <60b467ac47d5c6bbb9c21c3bdfecce8e5de60cda.camel@cybertec.at> <6935ea1e-cfb1-400b-9057-3d43b55d621a@iki.fi> Content-Language: en-US In-Reply-To: <6935ea1e-cfb1-400b-9057-3d43b55d621a@iki.fi> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 02/12/2025 18:36, Heikki Linnakangas wrote: > On 02/12/2025 18:24, Laurenz Albe wrote: >> On Tue, 2025-12-02 at 10:03 +0000, PG Bug reporting form wrote: >>> PostgreSQL version: 18.1 >>> >>> When using a nondeterministic ICU collation, the replace() function >>> fails to >>> replace a substring when that substring appears at the end of the input >>> string. >>> >>> Occurrences of the same substring earlier in the string are replaced >>> normally. >>> >>> Specific collation used: >>> create collation test_nondeterministic ( >>>      provider = icu, >>>      locale = 'und-u-ks-level2', >>>      deterministic = false >>> ) >>> >>> -- Replace final character under nondeterministic collation >>> SELECT replace( >>>      'testx' COLLATE "test_nondeterministic", >>>      'x'     COLLATE "test_nondeterministic", >>>      'y') AS res1; >> >> I can reproduce the problem, and the attached patch fixes it for me. > > +1, looks good to me. Let's also add a regression test for this. I added a simple test for this, and I think this is still not quite right. I added the following to collate.icu.utf test: CREATE TABLE test4nfd (a int, b text); INSERT INTO test4nfd VALUES (1, 'cote'), (2, 'côte'), (3, 'coté'), (4, 'côté'); UPDATE test4nfd SET b = normalize(b, nfd); -- This shows why replace should be greedy. Otherwise, in the NFD -- case, the match would stop before the decomposed accents, which -- would leave the accents in the results. SELECT a, b, replace(b COLLATE ignore_accents, 'co', 'ma') FROM test4; a | b | replace ---+------+--------- 1 | cote | mate 2 | côte | mate 3 | coté | maté 4 | côté | maté (4 rows) SELECT a, b, replace(b COLLATE ignore_accents, 'co', 'ma') FROM test4nfd; a | b | replace ---+------+--------- 1 | cote | mate 2 | côte | mate 3 | coté | maté 4 | côté | maté (4 rows) +-- Test for match at the end of the string. (We had a bug on that +-- once) +SELECT a, b, replace(b COLLATE ignore_accents, 'te', 'ma') FROM test4nfd; + a | b | replace +---+------+--------- + 1 | cote | coma + 2 | côte | coma + 3 | coté | coma + 4 | côté | coma +(4 rows) + In the added test query, the accents on the 'o' are stripped, which doesn't look correct. - Heikki