Domény

Z PostgreSQL
Skočit na navigaci Skočit na vyhledávání
CREATE OR REPLACE FUNCTION check_form_rodne_cislo(varchar, boolean)
RETURNS boolean AS $$
DECLARE
  str_parts varchar[];
  num_parts integer[];
  after_1953 boolean;
  birthday_str varchar;
BEGIN
  SELECT INTO str_parts regexp_matches
     FROM regexp_matches($1, E'^(\\d{2})(\\d{2})(\\d{2})(/)?(\\d{3,4})$');
  IF FOUND THEN
    -- Test existence lomitka v rodnem cisle rizeny druhym parametrem,                                                                  
    -- ve vyznamu NULL (nema vyznam), true - povinne, false - nepovinne.                                                                
    IF $2 <> (str_parts[4] IS NOT NULL) THEN
      RETURN false;
    END IF;
    -- Test modulo 11 se provadi pouze tehdy, pokud existuje                                                                            
    -- kontrolni cislice, tj. pocinaje rokem 1954.                                                                                      
    after_1953 := char_length(str_parts[5]) = 4;
    IF after_1953
       AND to_number($1, CASE WHEN str_parts[4] IS NULL
                              THEN '9999999999'
                              ELSE '999999/9999' END) % 11 <> 0 THEN
      RETURN false;
    END IF;
    -- Kontrola validniho datumu, po roce 2004 se mohou                                                                                 
    -- k mesici pricitat hodnoty 20 (pro muze) a 70 pro zeny.                                                                           
    num_parts := ARRAY[to_number(str_parts[1],'99'),
                       to_number(str_parts[2],'99'),
                       to_number(str_parts[3],'99')];
    num_parts := ARRAY[CASE WHEN NOT after_1953
                            THEN 1900 + num_parts[1]
                            WHEN after_1953 AND num_parts[1] >= 54
                            THEN 1900 + num_parts[1]
                            ELSE 2000 + num_parts[1] END,
                       CASE WHEN num_parts[2] > 70
                            THEN num_parts[2] - 70
                            WHEN num_parts[2] > 50
                            THEN num_parts[2] - 50
                            WHEN num_parts[2] > 20
                            THEN num_parts[2] - 20
                            ELSE num_parts[2] END,
                       num_parts[3]];
    birthday_str := replace(to_char(num_parts[1],'9999')
                            || to_char(num_parts[2],'09')
                            || to_char(num_parts[3],'09'),
                               ' ','');
    RETURN birthday_str = to_char(to_date(birthday_str, 'YYYYMMDD'),
                                  'YYYYMMDD');
  END IF;
  RETURN false;
END;
$$ LANGUAGE plpgsql;

-- Predpokladam validni vstup (overeny funkci check_form_rodne_cislo).                                                                  
-- Typ parametru varchar je zvolen proto, protoze je predkem domen rc,                                                                  
-- rc1 a rc2. Domeny se lisi vztahem vuci lomitku uvnitr rodneho cisla.                                                                 
CREATE OR REPLACE FUNCTION form_rodne_cislo_to_date(varchar)
RETURNS date AS $$
DECLARE
  str_parts varchar[];
  num_parts integer[];
  after_1953 boolean;
  birthday_str varchar;
BEGIN
  SELECT INTO str_parts regexp_matches
     FROM regexp_matches($1, E'^(\\d{2})(\\d{2})(\\d{2})(/)?(\\d{3,4})$');
  IF FOUND THEN
    after_1953 := char_length(str_parts[5]) = 4;
    -- Po roce 2004 se mohou k mesici pricitat                                                                                          
    -- hodnoty 20 (pro muze) a 70 pro zeny. Pred timto rokem                                                                            
    -- se vzdy pricita 50 pro zeny                                                                                                      
    num_parts := ARRAY[to_number(str_parts[1],'99'),
                       to_number(str_parts[2],'99'),
                       to_number(str_parts[3],'99')];
    num_parts := ARRAY[CASE WHEN NOT after_1953
                            THEN 1900 + num_parts[1]
                            WHEN after_1953 AND num_parts[1] >= 54
                            THEN 1900 + num_parts[1]
                            ELSE 2000 + num_parts[1] END,
                       CASE WHEN num_parts[2] > 70
                            THEN num_parts[2] - 70
                            WHEN num_parts[2] > 50
                            THEN num_parts[2] - 50
                            WHEN num_parts[2] > 20
                            THEN num_parts[2] - 20
                            ELSE num_parts[2] END,
                       num_parts[3]];
    RETURN to_date(
                   replace(to_char(num_parts[1],'9999')
                            || to_char(num_parts[2],'09')
                            || to_char(num_parts[3],'09'),
                               ' ',''),
                   'YYYYMMDD');
  END IF;
  RAISE NOTICE 'Incorrect format of type rodne cislo (value: %)', $1;
END;
$$ LANGUAGE plpgsql;

-- Predpokladam validni vstup (overeny funkci check_form_rodne_cislo).                                                                  
-- Typ parametru varchar je zvolen proto, protoze je predkem domen rc,                                                                  
-- rc1 a rc2. Domeny se lisi vztahem vuci lomitku uvnitr rodneho cisla.                                                                 
CREATE OR REPLACE FUNCTION form_rodne_cislo_to_bool(varchar)
RETURNS boolean AS $$
DECLARE
  str_part varchar[];
  birthday_mm integer;
BEGIN
  SELECT INTO str_part regexp_matches
     FROM regexp_matches($1, E'^\\d{2}(\\d{2})\\d{2}/?\\d{3,4}$');
  IF FOUND THEN
    birthday_mm := to_number(str_part[1],'09');
    RETURN CASE WHEN birthday_mm > 50
                THEN false
                ELSE true END;
  END IF;
  RAISE NOTICE 'Incorrect format of type rodne cislo (value: %)', $1;
END;
$$ LANGUAGE plpgsql;

-- Registrace domen                                                                                                                     
CREATE DOMAIN rc  VARCHAR CHECK (check_form_rodne_cislo(value, null::boolean));
CREATE DOMAIN rc1 VARCHAR CHECK (check_form_rodne_cislo(value, false));
CREATE DOMAIN rc2 VARCHAR CHECK (check_form_rodne_cislo(value, true));