I created an immutable function as below:
CREATE OR REPLACE FUNCTION GetCurrentDate()
RETURNS DATE
AS $p$
BEGIN
RETURN CURRENT_TIMESTAMP::DATE;
END;
$p$ LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER;
And I use this in a UNIQUE INDEX’s WHERE clause like:
CREATE UNIQUE INDEX PersonPhoness_UK_PhoneNo_CountryID
ON person_phones (phone_no, country_id)
WHERE GetCurrentDate()
BETWEEN effective_from_date AND effective_till_date;
This unique index sometimes does not catch duplicate when another row is added.
The effective_from_dt
for the newly added row is always CURRENT_DATE
. However, it works if I change the function to:
CREATE OR REPLACE FUNCTION GetCurrentDate()
RETURNS DATE
AS $p$
BEGIN
RETURN CURRENT_DATE;
END
$p$;
So I want to understand the difference.
3
Answers
First version is little bit slower:
CURRENT_TIMESTAMP
pseudo function, so it is useless. But although it is useless, it has an overhead. Maybe if the owner of function is same user as an application user, then the context is not changed. But this is bad configuration from security reasons.So both functions returns same result, but first does some useless operations, and then it should be little bit slower.
When you want to "rename" build in functions, then the best is using SQL language for functions instead. It is zero overhead. Starting PL/pgSQL runtime for any execution of any PL/pgSQL function has some overhead:
so
is better. It is inlined in query (not executed), so overhead of this is zero.
In PL/pgsql we CAST data two way.
Cast()
Function:CAST(value as cast_data_type)
::
) :value::cast_data_type
So, when you write anything like:
CURRENT_TIMESTAMP::DATE
It means,
cast(CURRENT_TIMESTAMP as DATE)
Now we know default
CURRENT_TIMESTAMP
format isYYYY-MM-DD hh:mm:ss.nnnnnn+/-tz
andCURRENT_DATE
format isYYYY-MM-DD
.So, you tell me what need more time ? @JitendraLoyal
For reference:
Pl/pgSQL TypeCast
Answer to question in the tile
CURRENT_TIMESTAMP::DATE
andCURRENT_DATE
do effectively exactly the same.CURRENT_TIMESTAMP::DATE
is a bit slower from first gettingtimestamptz
and then coercing it todate
– a pointless detour. Either expression is onlySTABLE
, notIMMUTABLE
, because either depends on thetimezone
setting of the executing session.About your index
The whole approach cannot work.
CURRENT_DATE
(or any function returning a point in time for that matter) makes no sense in an index definition. The way you have it, a row would enter into the partial index on one day, but not on another. Arbitrary consequences …Obviously, Postgres cannot allow that. The manual:
Bold emphasis mine. When trying to violate that rule,
CREATE INDEX
answers with:You forced the broken concept with an
IMMUTABLE
function wrapper. Only do that when it’s actually true. Or when you know exactly what you are doing with a white lie.Your lie isn’t white. Whenever a session operates with a different
timezone
setting, you (can) get a differentdate
for the same point in time and arbitrary things happen. This can go for a long time before you actually realize the broken functionality.So you have two levels of breakage. Luckily, it surfaced before too long. It’s pure coincidence that you saw errors with one function definition and not with the other. Either is bonkers. Pardon my French.
Start by defining your requirements exactly in plain English (or French, if you will). Then look for the proper tool(s) to implement …
Asides
SECURITY DEFINER
is completely useless for this. Only adds cost and possible security implications without any gain.Avoid mixed-case identifiers if at all possible. See:
The second function definition in your question is incomplete without language declaration. And without volatility label
IMMUTABLE
it wouldn’t be accepted byCREATE INDEX
to begin with.