create or replace function easter_sunday(year integer) returns date as $$
DECLARE
  a integer;
  b integer;
  c integer;
  d integer;
  e integer;
  month integer;
  day integer;
  easter text;
BEGIN
  a := year % 19;
  b := year % 4;
  c := year % 7;
  d := ((a*19)+24) % 30;
  e := ((b*2)+(c*4)+(d*6)+5) % 7;
  IF (d+e < 10) THEN
    month=3;
    day=d+e+22;
  ELSE
    month=4;
    day=d+e-9;
  END IF;
  easter := year || '-' || month || '-' || day;
  return easter::date;
END;
$$ LANGUAGE plpgsql;

create or replace function new_year(year integer) returns date as $$
DECLARE
  day integer;
  wdate text;
BEGIN
  wdate := year || '-01-01';
  select into day extract(DOW from wdate::date);
  IF (day = 0) THEN
    return (year || '-01-02')::date;
  END IF;
  IF (day = 6) THEN
    return (year || '-01-03')::date;
  END IF;
  return (year || '-01-01')::date;
END;
$$ LANGUAGE plpgsql;

create or replace function christmas(year integer) returns date as $$
DECLARE
  day integer;
  wdate text;
BEGIN
  wdate := year || '-12-25';
  select into day extract(DOW from wdate::date);
  IF (day = 0) THEN
    return (year || '-12-26')::date;
  END IF;
  IF (day = 6) THEN
    return (year || '-12-27')::date;
  END IF;
  return (year || '-12-25')::date;
END;
$$ LANGUAGE plpgsql;

create or replace function boxing_day(year integer) returns date as $$
DECLARE
  day integer;
  wdate text;
BEGIN
  wdate := year || '-12-25';
  select into day extract(DOW from wdate::date);
  IF (day = 0) THEN
    return (year || '-12-27')::date;
  END IF;
  IF (day > 4) THEN
    return (year || '-12-28')::date;
  END IF;
  return (year || '-12-26')::date;
END;
$$ LANGUAGE plpgsql;

create or replace function may_day(year integer) returns date as $$
DECLARE
  day integer;
  wdate text;
BEGIN
  wdate := year || '-05-01';
  select into day 9-extract(DOW from wdate::date);
  IF (day > 7) THEN
    day := day-7;
  END IF;
  return (year || '-05-' || day)::date;
END;
$$ LANGUAGE plpgsql;

create or replace function whitsun(year integer) returns date as $$
DECLARE
  day integer;
  wdate text;
BEGIN
  wdate := year || '-05-31';
  select into day extract(DOW from wdate::date);
  IF (day = 0) THEN
    day := 25;
  ELSE
    day := 32-day;
  END IF;
  return (year || '-05-' || day)::date;
END;
$$ LANGUAGE plpgsql;

create or replace function summer_bank(year integer) returns date as $$
DECLARE
  day integer;
  wdate text;
BEGIN
  wdate := year || '-08-31';
  select into day extract(DOW from wdate::date);
  IF (day = 0) THEN
    day := 25;
  ELSE
    day := 32-day;
  END IF;
  return (year || '-08-' || day)::date;
END;
$$ LANGUAGE plpgsql;

create or replace function bank_holidays(year integer) returns setof date as $$
DECLARE
  wdate date;
BEGIN
  select into wdate new_year(year);
  return next wdate;
  select into wdate easter_sunday(year)-'2 days'::interval;
  return next wdate;
  select into wdate easter_sunday(year)+'1 days'::interval;
  return next wdate;
  select into wdate may_day(year);
  return next wdate;
  select into wdate whitsun(year);
  return next wdate;
  select into wdate summer_bank(year);
  return next wdate;
  select into wdate christmas(year);
  return next wdate;
  select into wdate boxing_day(year);
  return next wdate;
  return;
END;
$$ LANGUAGE plpgsql;
