create function 
luhn_check_passed(possible_pan varchar)
returns boolean 
as
$body$
    declare
        i            integer;
        j            integer;
        check_digit  integer;
        last_digit   integer;
        c            char;
        even         boolean;
        sum_digits   integer;
        
    begin
        if possible_pan is null
        then
            return null;
        end if;
        i := length(possible_pan);
        c := substring(possible_pan from i for 1);
        begin
            last_digit := cast(c as integer);
        exception
            when others then return null;
        end;
        
        sum_digits := 0;
        even := true;
        i := i - 1;
        while i > 0 loop
            c := substring(possible_pan from i for 1);
            begin
                j := cast(c as integer);
            exception
                when others then return null;
            end;
            if even
            then
                j := j * 2;
                if j > 9
                then
                    j := 1 + j - 10;
                end if;
            end if;
            even := not even;            -- toggle true/false
            sum_digits := sum_digits + j;
            i := i - 1;
        end loop;
        
        if (sum_digits % 10) = 0
        then
            check_digit := 0;
        else
            check_digit := 10 - (sum_digits % 10);
        end if;
        
        if check_digit = last_digit
        then
            return true;
        else
            return false;
        end if;
    end;
$body$
language 'plpgsql' 
immutable
leakproof
strict
cost 100;
