In PostgreSQL the function concat_ws accepts only character, character varying, and text data types. Why is it not immutable?
An older documentation has the note that the string functions previously accepted other data types converting them to string. In such a scenario it's clear that the function cannot be marked immutable because e.g. date conversion will differ on settings. But now it's only string data types.
I also found this old post which should no longer apply. Could it be a backwards compability reason?
The function not being immutable means I can for example not use it in a generated column.
concat() and concat_ws() still accept "any" argument type according to the current documentation. This includes dates.
Since datestyle can be changed, and this affects the conversion to string done during the concat, this makes the functions stable but not immutable.
Demo:
postgres=# select concat_ws(' ', '2025-05-01'::date);
concat_ws
------------
2025-05-01
(1 row)
postgres=# set datestyle='SQL';
SET
postgres=# select concat_ws(' ', '2025-05-01'::date);
concat_ws
------------
05/01/2025
(1 row)
An example of a cheat you can use:
CREATE OR REPLACE FUNCTION public.concat_imm(sep varchar, a varchar, b varchar, c varchar)
RETURNS character varying
LANGUAGE sql
IMMUTABLE
AS $function$
select a || sep || b || sep || c;
$function$
;
create table
concat_test (fld_1 varchar,
fld_2 varchar,
fld_3 varchar,
concat_fld varchar
generated always as (concat_imm('|', fld_1, fld_2, fld_3)) stored);
insert into concat_test values ('cat', 'dog', 'fish');
insert into concat_test values ('1', '2', '07/13/25'::date::varchar)
set datestyle='SQL';
insert into concat_test values ('yes', 'no', '07/13/25'::date::varchar);
select * from concat_test ;
fld_1 | fld_2 | fld_3 | concat_fld
-------+-------+------------+----------------
cat | dog | fish | cat|dog|fish
1 | 2 | 2025-07-13 | 1|2|2025-07-13
yes | no | 07/13/2025 | yes|no|07/13/2025
Since you are only working with strings create an immutable function that does the same thing as concat_ws. Then use that in the generated always clause of the column in the table. The caveat is that for the date case I show the output will change depending on the datestyle. That is why the native concat_ws fails as it cannot promise consistent results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With