From ff66899b3d7495a2d41b12c638c1a5c41ffeaa63 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Mon, 19 Oct 2026 22:14:34 -0400 Subject: [PATCH v2 2/2] Add regression test for ILIKE prefix with libc UTF8 collations Compare an index scan with a seq scan, since C libraries differ in which characters they case-map. The test needs the en_US libc collation in a UTF8 database and is skipped otherwise. On macOS it fails without the previous commit. --- .../regress/expected/collate.libc.utf8.out | 39 ++++++++++++++++++ .../regress/expected/collate.libc.utf8_1.out | 9 ++++ src/test/regress/parallel_schedule | 2 +- src/test/regress/sql/collate.libc.utf8.sql | 41 +++++++++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/test/regress/expected/collate.libc.utf8.out create mode 100644 src/test/regress/expected/collate.libc.utf8_1.out create mode 100644 src/test/regress/sql/collate.libc.utf8.sql diff --git a/src/test/regress/expected/collate.libc.utf8.out b/src/test/regress/expected/collate.libc.utf8.out new file mode 100644 index 00000000000..c432937cf72 --- /dev/null +++ b/src/test/regress/expected/collate.libc.utf8.out @@ -0,0 +1,39 @@ +/* + * This test is for libc collations in a UTF8 database. It needs the + * en_US libc collation, and is skipped otherwise. + */ +SELECT getdatabaseencoding() <> 'UTF8' OR + (SELECT count(*) FROM pg_collation WHERE collname = 'en_US' AND collprovider = 'c' AND collencoding = pg_char_to_encoding('UTF8')) <> 1 + AS skip_test \gset +\if :skip_test +\quit +\endif +SET client_encoding TO UTF8; +-- ILIKE with an index scan must return the same rows as a seq scan. +-- C libraries differ in which of these characters they case-map, so +-- compare the two scans instead of listing the rows. +CREATE TABLE libc_ilike (x text COLLATE "en_US"); +INSERT INTO libc_ilike VALUES + (U&'\2160q'), (U&'\2170q'), -- ROMAN NUMERAL ONE, SMALL ROMAN NUMERAL ONE + (U&'\1E9Eq'), (U&'\00DFq'); -- CAPITAL SHARP S, SHARP S +CREATE INDEX ON libc_ilike (x text_pattern_ops); +SET enable_seqscan = off; +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS i1 FROM libc_ilike WHERE x ILIKE U&'\2160q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS i2 FROM libc_ilike WHERE x ILIKE U&'\2170q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS i3 FROM libc_ilike WHERE x ILIKE U&'\00DFq%' \gset +RESET enable_seqscan; +SET enable_indexscan = off; +SET enable_bitmapscan = off; +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS s1 FROM libc_ilike WHERE x ILIKE U&'\2160q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS s2 FROM libc_ilike WHERE x ILIKE U&'\2170q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS s3 FROM libc_ilike WHERE x ILIKE U&'\00DFq%' \gset +RESET enable_indexscan; +RESET enable_bitmapscan; +SELECT :'i1' = :'s1' AS roman_upper, :'i2' = :'s2' AS roman_lower, + :'i3' = :'s3' AS sharp_s; + roman_upper | roman_lower | sharp_s +-------------+-------------+--------- + t | t | t +(1 row) + +DROP TABLE libc_ilike; diff --git a/src/test/regress/expected/collate.libc.utf8_1.out b/src/test/regress/expected/collate.libc.utf8_1.out new file mode 100644 index 00000000000..85f9a46c4c8 --- /dev/null +++ b/src/test/regress/expected/collate.libc.utf8_1.out @@ -0,0 +1,9 @@ +/* + * This test is for libc collations in a UTF8 database. It needs the + * en_US libc collation, and is skipped otherwise. + */ +SELECT getdatabaseencoding() <> 'UTF8' OR + (SELECT count(*) FROM pg_collation WHERE collname = 'en_US' AND collprovider = 'c' AND collencoding = pg_char_to_encoding('UTF8')) <> 1 + AS skip_test \gset +\if :skip_test +\quit diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 75063f87a4a..17bcb0a020d 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -81,7 +81,7 @@ test: create_table_like alter_generic alter_operator misc async dbsize merge mis # collate.linux.utf8 and collate.icu.utf8 tests cannot be run in parallel with each other # psql depends on create_am # amutils depends on geometry, create_index_spgist, hash_index, brin -test: rules psql psql_crosstab psql_pipeline amutils stats_ext collate.linux.utf8 collate.windows.win1252 +test: rules psql psql_crosstab psql_pipeline amutils stats_ext collate.linux.utf8 collate.windows.win1252 collate.libc.utf8 # ---------- # Run these alone so they don't run out of parallel workers diff --git a/src/test/regress/sql/collate.libc.utf8.sql b/src/test/regress/sql/collate.libc.utf8.sql new file mode 100644 index 00000000000..4d30b05d9d8 --- /dev/null +++ b/src/test/regress/sql/collate.libc.utf8.sql @@ -0,0 +1,41 @@ +/* + * This test is for libc collations in a UTF8 database. It needs the + * en_US libc collation, and is skipped otherwise. + */ + +SELECT getdatabaseencoding() <> 'UTF8' OR + (SELECT count(*) FROM pg_collation WHERE collname = 'en_US' AND collprovider = 'c' AND collencoding = pg_char_to_encoding('UTF8')) <> 1 + AS skip_test \gset +\if :skip_test +\quit +\endif + +SET client_encoding TO UTF8; + +-- ILIKE with an index scan must return the same rows as a seq scan. +-- C libraries differ in which of these characters they case-map, so +-- compare the two scans instead of listing the rows. +CREATE TABLE libc_ilike (x text COLLATE "en_US"); +INSERT INTO libc_ilike VALUES + (U&'\2160q'), (U&'\2170q'), -- ROMAN NUMERAL ONE, SMALL ROMAN NUMERAL ONE + (U&'\1E9Eq'), (U&'\00DFq'); -- CAPITAL SHARP S, SHARP S +CREATE INDEX ON libc_ilike (x text_pattern_ops); + +SET enable_seqscan = off; +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS i1 FROM libc_ilike WHERE x ILIKE U&'\2160q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS i2 FROM libc_ilike WHERE x ILIKE U&'\2170q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS i3 FROM libc_ilike WHERE x ILIKE U&'\00DFq%' \gset +RESET enable_seqscan; + +SET enable_indexscan = off; +SET enable_bitmapscan = off; +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS s1 FROM libc_ilike WHERE x ILIKE U&'\2160q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS s2 FROM libc_ilike WHERE x ILIKE U&'\2170q%' \gset +SELECT coalesce(string_agg(x, ' ' ORDER BY x), '') AS s3 FROM libc_ilike WHERE x ILIKE U&'\00DFq%' \gset +RESET enable_indexscan; +RESET enable_bitmapscan; + +SELECT :'i1' = :'s1' AS roman_upper, :'i2' = :'s2' AS roman_lower, + :'i3' = :'s3' AS sharp_s; + +DROP TABLE libc_ilike; -- 2.37.1 (Apple Git-137.1)