Re: Re: Mapping output from a SEQUENCE into something non-repeating/colliding but random-looking?

From: Craig Ringer <craig(at)postnewspapers(dot)com(dot)au>
To: Daniel Verite <daniel(at)manitou-mail(dot)org>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: Re: Mapping output from a SEQUENCE into something non-repeating/colliding but random-looking?
Date: 2009-05-03 07:00:31
Message-ID: 49FD410F.3080108@postnewspapers.com.au
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Just to follow up on this with a look at check digit generation and checkin:

Luhn's algorithm should do for the check digit, I think. It need not be
anything complex given the chances for collision in the sample space.
Additionally, it's commonly used, easily implemented and widely
understood since it's used in credit card numbers among many other things.

For anyone who later needs it, here's a handy verifier for the Luhn's
Algorithm check digit, written as plain SQL functions with all
integer-based computation (no string decomposition), along with a
corresponding check digit generator and associated utility functions:

CREATE OR REPLACE FUNCTION luhn_verify(int8) RETURNS boolean AS $$
SELECT
-- Add the digits, doubling odd-numbered digits (counting left with
-- least significant as zero), and see if the sum is evenly
-- divisible by zero.
MOD(SUM(
-- Extract digit `n' counting left from least significant as zero
MOD( ( $1::int8 / (10^n)::int8 ), 10::int8)
-- Double odd-numbered digits
* (MOD(n,2) + 1)
), 10) = 0
FROM generate_series(0, ceil(log( $1 ))::integer - 1) AS n;
$$ LANGUAGE 'SQL'
IMMUTABLE
STRICT;

COMMENT ON FUNCTION luhn_verify(int8) IS 'Return true iff the last digit
of the input is a correct check digit for the rest of the input
according to Luhn''s algorithm.'

CREATE OR REPLACE FUNCTION luhn_generate_checkdigit(int8) RETURNS int8 AS $$
SELECT
-- Add the digits, doubling even-numbered digits (counting left
-- with least-significant as zero). Subtract the remainder of
-- dividing the sum by 10 from 10, and take the remainder
-- of dividing that by 10 in turn.
MOD(10 - MOD(SUM(
MOD( ($1::int8 / (10^n)::int8), 10::int8 )
* (2 - MOD(n,2)) -- double even digits
),10),10)::int8
FROM generate_series(0, ceil(log($1))::integer - 1) AS n;
$$ LANGUAGE 'SQL'
IMMUTABLE
STRICT;

COMMENT ON FUNCTION luhn_generate_checkdigit(int8) IS 'For the input
value, generate a check digit according to Luhn''s algorithm';

CREATE OR REPLACE FUNCTION luhn_generate(int8) RETURNS int8 AS $$
SELECT 10 * $1 + luhn_generate_checkdigit($1);
$$ LANGUAGE 'SQL'
IMMUTABLE
STRICT;

COMMENT ON FUNCTION luhn_generate(int8) IS 'Append a check digit
generated according to Luhn''s algorithm to the input value. The
input value must be no greater than (maxbigint/10).';

CREATE OR REPLACE FUNCTION luhn_strip(int8) RETURNS int8 AS $$
SELECT $1 / 10;
$$ LANGUAGE 'SQL'
IMMUTABLE
STRICT;

COMMENT ON FUNCTION luhn_strip(int8) IS 'Strip the least significant
digit from the input value. Intended for use when stripping the check
digit from a number including a Luhn''s algorithm check digit.';

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message garry 2009-05-03 11:32:46 windows service
Previous Message Craig Ringer 2009-05-03 05:13:02 Re: Re: Mapping output from a SEQUENCE into something non-repeating/colliding but random-looking?