Is there some kind of middle ground between VARIANT
and NOT VARIANT
for Informix 10.0 SPL functions?
I'm kind of new to Informix. I've got a SPL function get_timezone_offset
in Informix 10.0 that calculates whether a given timezone is in Daylight Savings Time or not and the resulting UTC offset (code posted below).
When using this function in the WHERE clause of a large table (>1M records) against a timestamp field it takes a few minutes to complete:
select count(*)
from Table
where Table.startDateTime >= current - (get_timezone_offset('et') units hour) - 1 units day
The same query without that function call is <1 second long:
select count(*)
from Table
where Table.startDateTime >= current - 1 units day
I believe the difference comes from the query optimizer being able to "simplify" current - 1 units day
into a constant; I can modify the get_timezone_offset
function with alter function get_timezone_offset with (add not variant)
and then the first query including the function call takes less than a second to complete. But my function is in fact going to change output twice a year for the same input, so it's not not variant
.
How can I get the optimizer to treat my function like a constant only for the duration of a query?
create procedure get_timezone_offset(timezone varchar(8))
returning decimal as "current timezone offset";
-- This SQL calculates the current timezone's offset from UTC based on whether
-- the given timezone is in Daylight Saving Time right now or not.
-- DST is assumed to begin at 2:00 AM (in the given timezone) on the second
-- Sunday of March, and to end at 2:00 AM (in the given timezone, accounting for
-- DST) on the first Sunday of November.
-- Specify the timezone by giving a string for timezone which will correspond
-- to what's in the timezone_offsets table.
define offset decimal;
select
"current timezone offset"
into offset
from (
select
"time (utc)",
"in daylight savings time",
"standard timezone offset",
-- When we're in DST then the timezone offset from UTC increases by one
case
when "in daylight savings time" then "standard timezone offset" + 1
else "standard timezone offset"
end as "current timezone offset"
from (
select
"time (utc)",
-- Knowing when we currently are in relation to when the DST
-- "triggers" are makes it easy to determine if we're in DST or not
case
when "time (utc)" >= "march trigger (utc)" and "time (utc)" < "november trigger (utc)" then 't'::boolean
else 'f'::boolean
end as "in daylight savings time",
"standard timezone offset"
from (
select
"time (utc)",
-- DST begins at 2:00AM on the second Sunday in March. For
-- Eastern Time, for example, that will be at 7:00 AM UTC
mdy(3, "second sunday in march", year("time (utc)"))::datetime year to hour + ((2 - "standard timezone offset") units hour) as "march trigger (utc)",
-- DST ends at 2:00AM on the first Sunday in November. For
-- Eastern Time, for example, that will be at 6:00 AM UTC
mdy(11, "first sunday in november", year("time (utc)"))::datetime year to hour + ((1 - "standard timezone offset") units hour) as "november trigger (utc)",
"standard timezone offset"
from (
select
"time (utc)",
"standard timezone offset",
-- Figure out when the second Sunday in March and the first
-- Sunday in November are in UTC time
mod((7 - weekday(mdy(3, 1, year("time (utc)")))), 7) + 8 as "second sunday in march",
mod((7 - weekday(mdy(11, 1, year("time (utc)")))), 7) + 1 as "first sunday in november"
from (
-- Get the timezone's UTC offset for when the timezone is in
-- standard time. Also get the current UTC time for later
-- calculations
select
"standard_utc_offset" as "standard timezone offset",
('1970-01-01 00:00:00'::datetime year to second) + ((dbinfo('utc_current') / (60)) units minute) as "time (utc)"
from timezone_offsets
where timezone_offsets.timezone = timezone
)
)
)
)
);
return offset;
end procedure