patternsqlMinor
Why isn't it possible to cast to a timestamp in an index in PostgreSQL?
Viewed 0 times
postgresqlwhycastpossibletimestampindexisn
Problem
I am working with a JSON document which I receive from an external source. In this document, there is a
I want to use that
I am getting:
Why is this? I understood that casting to a
Is there still a way to cast my
I am working with PostgreSQL 12, as released a few days ago.
timestamp property which corresponds to the textual format of a timestamp PostgreSQL data type. So in other words, it can be casted to a timestamp type: (data->>'timestamp')::timestamp.I want to use that
timestamp property in an index. I tried the following:create table t
(
data jsonb
);
create index on t(((data->>'timestamp')::timestamp));I am getting:
ERROR: functions in index expression must be marked IMMUTABLEWhy is this? I understood that casting to a
timestamptz is not immutable, because of the localization configuration settings which are not static, but I can't apply that logic to a cast to timestamp.Is there still a way to cast my
timestamp property in the index here?I am working with PostgreSQL 12, as released a few days ago.
Solution
Casts from
The reason is that
If you know that your input is always an ISO timestamp and this cannot happen, define your own conversion function:
You can use that in your queries and indexes.
If you lack paranoia and are sure of your data quality, you can omit the test. That will improve performance, but you risk index corruption if somebody sneaks something like
text to timestamp without time zone are handled by calling the type input function timestamp_in, which is STABLE.The reason is that
timestamp_in supports some other formats too:SELECT 'now'::timestamp;
timestamp
----------------------------
2019-10-09 09:53:32.026673
(1 row)If you know that your input is always an ISO timestamp and this cannot happen, define your own conversion function:
CREATE FUNCTION text2ts(text) RETURNS timestamp without time zone
LANGUAGE sql IMMUTABLE AS
$SELECT CASE WHEN $1 ~ '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?
You can use that in your queries and indexes.
If you lack paranoia and are sure of your data quality, you can omit the test. That will improve performance, but you risk index corruption if somebody sneaks something like now into the data.
THEN CAST($1 AS timestamp without time zone)
END$;You can use that in your queries and indexes.
If you lack paranoia and are sure of your data quality, you can omit the test. That will improve performance, but you risk index corruption if somebody sneaks something like
now into the data.Code Snippets
SELECT 'now'::timestamp;
timestamp
----------------------------
2019-10-09 09:53:32.026673
(1 row)CREATE FUNCTION text2ts(text) RETURNS timestamp without time zone
LANGUAGE sql IMMUTABLE AS
$$SELECT CASE WHEN $1 ~ '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?$'
THEN CAST($1 AS timestamp without time zone)
END$$;Context
StackExchange Database Administrators Q#250627, answer score: 5
Revisions (0)
No revisions yet.