Skip to content

Instantly share code, notes, and snippets.

@vpavic
Created April 25, 2016 21:26
Show Gist options
  • Save vpavic/d68e45e6f62b94c62295bcebba4186d2 to your computer and use it in GitHub Desktop.
Save vpavic/d68e45e6f62b94c62295bcebba4186d2 to your computer and use it in GitHub Desktop.
PostgreSQL functions for Croatian Personal Identification Number (OIB)
-- PostgreSQL functions for Croatian Personal Identification Number (OIB)
--
-- Reference:
-- https://en.wikipedia.org/wiki/Personal_identification_number_(Croatia)
-- http://www.regos.hr/UserDocsImages/KONTROLA%20OIB-a.pdf
CREATE OR REPLACE FUNCTION hr_pin_control_number(pin_base TEXT) RETURNS INTEGER AS $$
DECLARE
pin_digit INTEGER;
control INTEGER;
BEGIN
IF length(pin_base) != 10 THEN
RAISE EXCEPTION 'Invalid input ''%''', pin_base
USING HINT = 'Input must be exactly 10 digits long';
END IF;
IF NOT textregexeq(pin_base, '^[[:digit:]]+$') THEN
RAISE EXCEPTION 'Invalid input ''%''', pin_base
USING HINT = 'Input must contain only digits';
END IF;
FOR i IN 1..10 LOOP
pin_digit := substr(pin_base, i, 1)::INTEGER;
IF i = 1 THEN
control := pin_digit + 10;
ELSE
control := pin_digit + control;
END IF;
control := control % 10;
IF control = 0 THEN
control := 10;
END IF;
control := control * 2;
control := control % 11;
END LOOP;
control := 11 - control;
control := control % 10;
RETURN control;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION hr_pin_is_valid(pin TEXT) RETURNS BOOLEAN AS $$
DECLARE
control INTEGER;
BEGIN
IF length(pin) != 11 THEN
RAISE EXCEPTION 'Invalid input ''%''', pin
USING HINT = 'Input must be exactly 11 digits long';
END IF;
IF NOT textregexeq(pin, '^[[:digit:]]+$') THEN
RAISE EXCEPTION 'Invalid input ''%''', pin
USING HINT = 'Input must contain only digits';
END IF;
control := hr_pin_control_number(substr(pin, 1, 10));
RETURN control = substr(pin, 11, 1)::INTEGER;
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION hr_pin_generate_random() RETURNS TEXT AS $$
DECLARE
pin_digits INTEGER[];
pin_base TEXT;
control INTEGER;
BEGIN
FOR i IN 1..10 LOOP
pin_digits[i] := floor(random() * 10);
END LOOP;
pin_base = array_to_string(pin_digits, '');
control := hr_pin_control_number(pin_base);
RETURN concat(pin_base, control);
END;
$$ LANGUAGE plpgsql;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment