diff --git a/contrib/citext/Makefile b/contrib/citext/Makefile index e39d3eee61..563cd22dcc 100644 --- a/contrib/citext/Makefile +++ b/contrib/citext/Makefile @@ -3,7 +3,8 @@ MODULES = citext EXTENSION = citext -DATA = citext--1.3.sql citext--1.2--1.3.sql citext--1.1--1.2.sql \ +DATA = citext--1.4.sql citext--1.3--1.4.sql \ + citext--1.2--1.3.sql citext--1.1--1.2.sql \ citext--1.0--1.1.sql citext--unpackaged--1.0.sql PGFILEDESC = "citext - case-insensitive character string data type" diff --git a/contrib/citext/citext--1.3--1.4.sql b/contrib/citext/citext--1.3--1.4.sql new file mode 100644 index 0000000000..7b36651186 --- /dev/null +++ b/contrib/citext/citext--1.3--1.4.sql @@ -0,0 +1,12 @@ +/* contrib/citext/citext--1.3--1.4.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION citext UPDATE TO '1.4'" to load this file. \quit + +CREATE FUNCTION regexp_match( citext, citext ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, 'i' ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION regexp_match( citext, citext, text ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, CASE WHEN pg_catalog.strpos($3, 'c') = 0 THEN $3 || 'i' ELSE $3 END ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; diff --git a/contrib/citext/citext--1.3.sql b/contrib/citext/citext--1.4.sql similarity index 96% rename from contrib/citext/citext--1.3.sql rename to contrib/citext/citext--1.4.sql index c2d0c0ce9b..7b06198935 100644 --- a/contrib/citext/citext--1.3.sql +++ b/contrib/citext/citext--1.4.sql @@ -1,4 +1,4 @@ -/* contrib/citext/citext--1.2.sql */ +/* contrib/citext/citext--1.4.sql */ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION citext" to load this file. \quit @@ -444,6 +444,14 @@ CREATE OPERATOR !~~* ( -- XXX TODO Ideally these would be implemented in C. -- +CREATE FUNCTION regexp_match( citext, citext ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, 'i' ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + +CREATE FUNCTION regexp_match( citext, citext, text ) RETURNS TEXT[] AS $$ + SELECT pg_catalog.regexp_match( $1::pg_catalog.text, $2::pg_catalog.text, CASE WHEN pg_catalog.strpos($3, 'c') = 0 THEN $3 || 'i' ELSE $3 END ); +$$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE; + CREATE FUNCTION regexp_matches( citext, citext ) RETURNS SETOF TEXT[] AS $$ SELECT pg_catalog.regexp_matches( $1::pg_catalog.text, $2::pg_catalog.text, 'i' ); $$ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE ROWS 1; diff --git a/contrib/citext/citext.control b/contrib/citext/citext.control index 5f080df3ee..17fce4e887 100644 --- a/contrib/citext/citext.control +++ b/contrib/citext/citext.control @@ -1,5 +1,5 @@ # citext extension comment = 'data type for case-insensitive character strings' -default_version = '1.3' +default_version = '1.4' module_pathname = '$libdir/citext' relocatable = true diff --git a/contrib/citext/expected/citext.out b/contrib/citext/expected/citext.out index 6541b24b5f..1a1e6c82f7 100644 --- a/contrib/citext/expected/citext.out +++ b/contrib/citext/expected/citext.out @@ -1770,6 +1770,60 @@ SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t (4 rows) +SELECT regexp_match('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)', '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz', '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, ''::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +-- c forces case-sensitive +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, 'c'::citext) = ARRAY[ 'bar', 'beque' ] AS "no result"; + no result +----------- + +(1 row) + +-- g is not allowed +SELECT regexp_match('foobarbequebazmorebarbequetoo'::citext, '(BAR)(BEQUE)'::citext, 'g') AS "error"; +ERROR: regexp_match does not support the global option +HINT: Use the regexp_matches function instead. +CONTEXT: SQL function "regexp_match" statement 1 SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; t --- diff --git a/contrib/citext/expected/citext_1.out b/contrib/citext/expected/citext_1.out index 462d42a3bd..3331dbc255 100644 --- a/contrib/citext/expected/citext_1.out +++ b/contrib/citext/expected/citext_1.out @@ -1770,6 +1770,60 @@ SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t (4 rows) +SELECT regexp_match('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)', '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz', '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, ''::citext) = ARRAY[ 'bar', 'beque' ] AS t; + t +--- + t +(1 row) + +-- c forces case-sensitive +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, 'c'::citext) = ARRAY[ 'bar', 'beque' ] AS "no result"; + no result +----------- + +(1 row) + +-- g is not allowed +SELECT regexp_match('foobarbequebazmorebarbequetoo'::citext, '(BAR)(BEQUE)'::citext, 'g') AS "error"; +ERROR: regexp_match does not support the global option +HINT: Use the regexp_matches function instead. +CONTEXT: SQL function "regexp_match" statement 1 SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; t --- diff --git a/contrib/citext/sql/citext.sql b/contrib/citext/sql/citext.sql index 2df1b4aaf0..a802484663 100644 --- a/contrib/citext/sql/citext.sql +++ b/contrib/citext/sql/citext.sql @@ -592,6 +592,18 @@ SELECT md5( name ) = md5( name::text ) AS t FROM srt; SELECT quote_ident( name ) = quote_ident( name::text ) AS t FROM srt; SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; +SELECT regexp_match('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)', '') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz', '(BAR)(BEQUE)'::citext, '') = ARRAY[ 'bar', 'beque' ] AS t; +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, ''::citext) = ARRAY[ 'bar', 'beque' ] AS t; +-- c forces case-sensitive +SELECT regexp_match('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext, 'c'::citext) = ARRAY[ 'bar', 'beque' ] AS "no result"; +-- g is not allowed +SELECT regexp_match('foobarbequebazmorebarbequetoo'::citext, '(BAR)(BEQUE)'::citext, 'g') AS "error"; + SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; SELECT regexp_matches('foobarbequebaz'::citext, '(BAR)(BEQUE)') = ARRAY[ 'bar', 'beque' ] AS t; SELECT regexp_matches('foobarbequebaz'::citext, '(BAR)(BEQUE)'::citext) = ARRAY[ 'bar', 'beque' ] AS t; diff --git a/doc/src/sgml/citext.sgml b/doc/src/sgml/citext.sgml index 7fdf30252a..9b4c68f7d4 100644 --- a/doc/src/sgml/citext.sgml +++ b/doc/src/sgml/citext.sgml @@ -124,6 +124,11 @@ SELECT * FROM users WHERE nick = 'Larry'; + + + regexp_match() + + regexp_matches()