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.94.2) (envelope-from ) id 1uS5Oo-0037pw-L5 for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Jun 2025 02:53:11 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1uS5Om-006v7Y-J8 for pgsql-hackers@arkaria.postgresql.org; Thu, 19 Jun 2025 02:53:09 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uS5Om-006v7P-2G for pgsql-hackers@lists.postgresql.org; Thu, 19 Jun 2025 02:53:08 +0000 Received: from mail-pj1-x102d.google.com ([2607:f8b0:4864:20::102d]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1uS5Ok-002rr4-0G for pgsql-hackers@postgresql.org; Thu, 19 Jun 2025 02:53:08 +0000 Received: by mail-pj1-x102d.google.com with SMTP id 98e67ed59e1d1-31393526d0dso156271a91.0 for ; Wed, 18 Jun 2025 19:53:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=j-davis-com.20230601.gappssmtp.com; s=20230601; t=1750301583; x=1750906383; darn=postgresql.org; h=mime-version:user-agent:references:in-reply-to:date:cc:to:from :subject:message-id:from:to:cc:subject:date:message-id:reply-to; bh=zpB4+ONW1v6oH75Ykqyqz4k+G4gDufE8QkhEOPhH4CU=; b=wghouq/O0TvVEL6Lb07/g+OnTqEaIXiu09EpaxnptAUfDP1ak9uVi87gMgIyQn8/ca EcHnILzf4lCQ1/KQ6fRjndH2o0Gv4OoxJlBojET4OJgUYhBLfXtwqfub3p1ZgYUhIGxK qAZ4eLvp/n81J4wnfntRxaQ37gH0rXRLSOc21KMoBrA1XS0DtdTKTqZwlWp3SxzCfCtB WdBL0gOcR2Mv/43tH7/l1lOseuX7VehPb7ZrCUUMGqzFNePkkuZqEPK/qLjfmhv151h+ M7B0snvUc2xYEnAjg3FgnPYJNK6zHZ66WCp1s/WkjAHG5ymQD3pCpYshZwsFUX9GFtoW sh6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750301583; x=1750906383; h=mime-version:user-agent:references:in-reply-to:date:cc:to:from :subject:message-id:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=zpB4+ONW1v6oH75Ykqyqz4k+G4gDufE8QkhEOPhH4CU=; b=nzCofIvhj4XseApvwLZwvsRER6j4try48ncIAPT7ljJEmlp7UqPm4dqBcoLdOQwWhk bxBcX6uqd+nlQ62AcJQG9fMNssCyg7YxbfjKkj/c0p10yg4E3+UwrMUdBDnApoZzRpWE chfpjz1iKPoUxFW4fccnZwpOlT2UlYmF39mBdvOtDn3v8Cvmq98moOyyIfdkpm9mVimP lzpl2eOdqxevWobjIyrKQW3LBSwbOYeNzlhLulChGDqQGk5fjoq2IO2R9B74TOXRyuwJ TipeSpuF20BCmJenDIIKW4yuZvMPqK7LRtJ+CLfwYBtMLcig98u3wC0gbzzvrGMg4c6Q l9YQ== X-Gm-Message-State: AOJu0YyBxNjQuEFz3ZzGwjyeZl9SWE1wgjzvh0W8VGE9nDF1mnC9XIXM CQWUhbgtQ5PVO36XlYvPtoaA+7ZCbZDqxvY5ysvaAnjCHuZfzW8bShb0iWAf3jNhKw== X-Gm-Gg: ASbGnctpHSSb9p5e7wyPvATEz6NwfBEa0edzb+ywBQbLP1fAcsGvQ0HvULY/PR16kFw bbe5k9AUFk0iHO4IZFBeaODnCYp9eMDwGZ1KabisSTqO8EakH5c9BBqwnau079tFxgO/eLBYTOt jBusP4W4E+GNcgfKdu7oNPyf1fiND3TQNjjFZ0VqLBenEdBRqrjgdfu+wyZubHd5hCQ/jqLPsU8 PJ33S1NxQgNKg/+AuvPgE8iqd6LOrPNoSUgENPX54szLMxtqXb+4prK8EuL9k3XIGNaP7RTtb3P Fovvhn/nz4PJU3OjPKL+hFIW0RsRWcw19EvfQa9w3TKoZ84vXfn8yC2D2Ai3jU+AR/LPV7+tqXZ aEih7rXOIU0tzXaNIcv3M+Ez3TpLYQWaGvnz/letWqQg= X-Google-Smtp-Source: AGHT+IG2bd4LNQkpjna5mlgqqaCZMo6SMVgdHHFawix2wpZcFK+FbfBhxbVETyxZNdClrRoj4z0/GQ== X-Received: by 2002:a17:90b:3e4d:b0:311:ea13:2e6e with SMTP id 98e67ed59e1d1-313f1db9fd3mr29633922a91.28.1750301583306; Wed, 18 Jun 2025 19:53:03 -0700 (PDT) Received: from jeff-ws-bridge.lan (c-76-102-242-158.hsd1.ca.comcast.net. [76.102.242.158]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2365d8a190esm108654345ad.69.2025.06.18.19.53.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jun 2025 19:53:02 -0700 (PDT) Message-ID: Subject: Re: Add CASEFOLD() function. From: Jeff Davis To: Vik Fearing , Joe Conway , Ian Lawrence Barwick Cc: pgsql-hackers@postgresql.org, Peter Eisentraut Date: Wed, 18 Jun 2025 19:53:01 -0700 In-Reply-To: <692d28a2-d5f8-4db5-a3ad-c7db9bab522f@postgresfriends.org> References: <47716a78-eb0b-4728-8991-fc0d958a01c9@joeconway.com> <36f69fa9-db3f-44a1-8c8a-95ff09704a9c@postgresfriends.org> <692d28a2-d5f8-4db5-a3ad-c7db9bab522f@postgresfriends.org> Content-Type: multipart/mixed; boundary="=-2QF67nnUwCl0vN9qpsfO" User-Agent: Evolution 3.52.3-0ubuntu1 MIME-Version: 1.0 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --=-2QF67nnUwCl0vN9qpsfO Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, 2025-06-18 at 19:09 +0200, Vik Fearing wrote: > I don't know.=C2=A0 I am just pointing out what the Standard says.=C2=A0 = I > think=20 > we should either comply, or say that we don't do it for LOWER and > UPPER=20 > so let's keep things implementation-consistent. For the standard, I see two potential philosophies: I. CASEFOLD() is another variant of LOWER()/UPPER(), and it should preserve NFC in the same way. II. CASEFOLD() is not like LOWER()/UPPER(); it returns a semi-opaque text value that is useful for caseless matching, but should not ordinarily be used for display or sent to the application (those things would be allowed, just not encouraged). For normalization, either: (A) Follow Unicode Default Caseless Matching (16.0 3.13.5 D144), and don't require any kind of normalization; or (B) Follow Unicode Canonical Caseless Matching (D145), and require that the input and output are normalized appropriately, but leave the precise normal form as implementation-defined. The current implementation could either be seen as philosophy (I) where we've chosen to ignore the normalization part for the sake of consistency with LOWER()/UPPER(); or it could be seen as philosophy (II)(A). > How much does it cost to check for NFC?=C2=A0 I honestly don't know the= =20 > answer to that question, but that is the only case where we need to=20 > maintain normalization. I attached a very rough patch and ran a very simple test on strings averaging 36 bytes in length, all already in NFC and the result is also NFC. Before the patch, doing a CASEFOLD() on 10M tuples took about 3 seconds, afterward about 8. There's a patch to optimize some of the normalization paths, which I haven't had a chance to review yet. So those numbers might come down.=20 >=20 > It's not unconditionally, it's only if the input was NFC. Optimizing the case where the input is _not_ NFC seems strange to me. If we are normalizing the output, I'd say we should just make the output always NFC.=C2=A0Being more strict, this seems likely to comply with the eventual standard. Additionally, if we are normalizing the output, then we should also do the input fixup for U+0345, which would make the result usable for Canonical Caseless Matching. Again, this seems likely to comply with the eventual standard. >=20 So I only see two reasonable implementations: 1. The current CASEFOLD() implementation. 2. Do the input fixup for U+0345 and unconditionally normalize the output in NFC. If there's a case to be made for both implementations, we could also consider having two functions, say, CASEFOLD() for #1 and NCASEFOLD() for #2. I'm not sure whether we'd want to standardize one or both of those functions. And if you think there's likely to be a collision with the standard that's hard to anticipate and fix now, then we should consider reverting CASEFOLD() for 18 and wait for more progress on the standardization. What's the likelihood that the name changes or something like that? Regards, Jeff Davis --=-2QF67nnUwCl0vN9qpsfO Content-Disposition: attachment; filename="casefold_normalize.diff" Content-Type: text/x-patch; name="casefold_normalize.diff"; charset="UTF-8" Content-Transfer-Encoding: base64 ZGlmZiAtLWdpdCBhL3NyYy9iYWNrZW5kL3V0aWxzL2FkdC9mb3JtYXR0aW5nLmMgYi9zcmMvYmFj a2VuZC91dGlscy9hZHQvZm9ybWF0dGluZy5jCmluZGV4IDViZDFlMDFmN2U0Li4xMmU2ODhhY2Vj NiAxMDA2NDQKLS0tIGEvc3JjL2JhY2tlbmQvdXRpbHMvYWR0L2Zvcm1hdHRpbmcuYworKysgYi9z cmMvYmFja2VuZC91dGlscy9hZHQvZm9ybWF0dGluZy5jCkBAIC03OSw2ICs3OSw3IEBACiAjaW5j bHVkZSAiY29tbW9uL2ludC5oIgogI2luY2x1ZGUgImNvbW1vbi91bmljb2RlX2Nhc2UuaCIKICNp bmNsdWRlICJjb21tb24vdW5pY29kZV9jYXRlZ29yeS5oIgorI2luY2x1ZGUgImNvbW1vbi91bmlj b2RlX25vcm0uaCIKICNpbmNsdWRlICJtYi9wZ193Y2hhci5oIgogI2luY2x1ZGUgIm5vZGVzL21p c2Nub2Rlcy5oIgogI2luY2x1ZGUgInBhcnNlci9zY2Fuc3VwLmgiCkBAIC0xODY2LDYgKzE4Njcs OSBAQCBzdHJfY2FzZWZvbGQoY29uc3QgY2hhciAqYnVmZiwgc2l6ZV90IG5ieXRlcywgT2lkIGNv bGxpZCkKIAkJc2l6ZV90CQlkc3RzaXplOwogCQljaGFyCSAgICpkc3Q7CiAJCXNpemVfdAkJbmVl ZGVkOworCQlpbnQgbWJsZW4sIGk7CisJCXVuc2lnbmVkIGNoYXIgKnA7CisJCXBnX3djaGFyICAg KmRlY29kZWQ7CiAKIAkJLyogZmlyc3QgdHJ5IGJ1ZmZlciBvZiBlcXVhbCBzaXplIHBsdXMgdGVy bWluYXRpbmcgTlVMICovCiAJCWRzdHNpemUgPSBzcmNsZW4gKyAxOwpAQCAtMTg4Miw3ICsxODg2 LDU0IEBAIHN0cl9jYXNlZm9sZChjb25zdCBjaGFyICpidWZmLCBzaXplX3QgbmJ5dGVzLCBPaWQg Y29sbGlkKQogCQl9CiAKIAkJQXNzZXJ0KGRzdFtuZWVkZWRdID09ICdcMCcpOwotCQlyZXN1bHQg PSBkc3Q7CisKKwkJLyogY29udmVydCB0byBwZ193Y2hhciAqLworCQltYmxlbiA9IHBnX21ic3Ry bGVuX3dpdGhfbGVuKGRzdCwgbmVlZGVkKTsKKwkJZGVjb2RlZCA9IHBhbGxvYygobWJsZW4gKyAx KSAqIHNpemVvZihwZ193Y2hhcikpOworCQlwID0gKHVuc2lnbmVkIGNoYXIgKikgZHN0OworCQlm b3IgKGkgPSAwOyBpIDwgbWJsZW47IGkrKykKKwkJeworCQkJZGVjb2RlZFtpXSA9IHV0ZjhfdG9f dW5pY29kZShwKTsKKwkJCXAgKz0gcGdfdXRmX21ibGVuKHApOworCQl9CisJCWRlY29kZWRbaV0g PSAocGdfd2NoYXIpICdcMCc7CisKKwkJaWYgKHVuaWNvZGVfaXNfbm9ybWFsaXplZF9xdWlja2No ZWNrKFVOSUNPREVfTkZDLCBkZWNvZGVkKSA9PSBVTklDT0RFX05PUk1fUUNfWUVTKQorCQl7CisJ CQlwZnJlZShkZWNvZGVkKTsKKwkJCXJlc3VsdCA9IGRzdDsKKwkJfQorCQllbHNlCisJCXsKKwkJ CXBnX3djaGFyICpub3JtYWxpemVkOworCQkJdW5zaWduZWQgY2hhciAqbm9ybWFsaXplZF91dGY4 OworCisJCQlub3JtYWxpemVkID0gdW5pY29kZV9ub3JtYWxpemUoVU5JQ09ERV9ORkMsIGRlY29k ZWQpOworCQkJcGZyZWUoZGVjb2RlZCk7CisKKwkJCS8qIGNvbnZlcnQgYmFjayB0byBVVEYtOCBz dHJpbmcgKi8KKwkJCW1ibGVuID0gMDsKKwkJCWZvciAocGdfd2NoYXIgKndwID0gbm9ybWFsaXpl ZDsgKndwOyB3cCsrKQorCQkJeworCQkJCXVuc2lnbmVkIGNoYXIgYnVmWzRdOworCisJCQkJdW5p Y29kZV90b191dGY4KCp3cCwgYnVmKTsKKwkJCQltYmxlbiArPSBwZ191dGZfbWJsZW4oYnVmKTsK KwkJCX0KKworCQkJbm9ybWFsaXplZF91dGY4ID0gcGFsbG9jKG1ibGVuICsgMSk7CisKKwkJCXAg PSBub3JtYWxpemVkX3V0Zjg7CisJCQlmb3IgKHBnX3djaGFyICp3cCA9IG5vcm1hbGl6ZWQ7ICp3 cDsgd3ArKykKKwkJCXsKKwkJCQl1bmljb2RlX3RvX3V0ZjgoKndwLCBwKTsKKwkJCQlwICs9IHBn X3V0Zl9tYmxlbihwKTsKKwkJCX0KKwkJCSpwID0gJ1wwJzsKKwkJCXBmcmVlKG5vcm1hbGl6ZWQp OworCisJCQlyZXN1bHQgPSAoY2hhciAqKSBub3JtYWxpemVkX3V0Zjg7CisJCX0KIAl9CiAKIAly ZXR1cm4gcmVzdWx0Owo= --=-2QF67nnUwCl0vN9qpsfO--