mirror of https://github.com/postgres/postgres
remove the old isbn_issn module which is about to be obsoleted by EAN13. contrib/isn is by Germán Méndez Bravo. Our thanks to Garrett A. Wollman for having written the original isbn_issn module.REL8_2_STABLE
parent
42c17a6bb0
commit
dff84dc762
@ -1,16 +0,0 @@ |
|||||||
# $PostgreSQL: pgsql/contrib/isbn_issn/Makefile,v 1.15 2006/02/27 12:54:39 petere Exp $
|
|
||||||
|
|
||||||
MODULES = isbn_issn
|
|
||||||
DATA_built = isbn_issn.sql
|
|
||||||
DATA = uninstall_isbn_issn.sql
|
|
||||||
DOCS = README.isbn_issn
|
|
||||||
|
|
||||||
ifdef USE_PGXS |
|
||||||
PGXS := $(shell pg_config --pgxs)
|
|
||||||
include $(PGXS) |
|
||||||
else |
|
||||||
subdir = contrib/isbn_issn
|
|
||||||
top_builddir = ../..
|
|
||||||
include $(top_builddir)/src/Makefile.global |
|
||||||
include $(top_srcdir)/contrib/contrib-global.mk |
|
||||||
endif |
|
@ -1,22 +0,0 @@ |
|||||||
|
|
||||||
ISBN (books) and ISSN (serials) |
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
||||||
|
|
||||||
This directory contains definitions for a couple of PostgreSQL |
|
||||||
external types, for a couple of international-standard namespaces: |
|
||||||
ISBN (books) and ISSN (serials). Rather than just using a char() |
|
||||||
member of the appropriate length, I wanted my database to include |
|
||||||
the validity-checking that both these numbering systems were designed |
|
||||||
to encompass. A little bit of research revealed the formulae |
|
||||||
for computing the check digits, and I also included some validity |
|
||||||
constraints on the number of hyphens. |
|
||||||
|
|
||||||
The internal representation of these types is intended to be |
|
||||||
compatible with `char16', in the (perhaps vain) hope that |
|
||||||
this will make it possible to create indices of these types |
|
||||||
using char16_ops. |
|
||||||
|
|
||||||
These are based on Tom Ivar Helbekkmo's IP address type definition, |
|
||||||
from which I have copied the entire form of the implementation. |
|
||||||
|
|
||||||
Garrett A. Wollman, August 1998 |
|
@ -1,378 +0,0 @@ |
|||||||
/*
|
|
||||||
* PostgreSQL type definitions for ISBNs. |
|
||||||
* |
|
||||||
* $PostgreSQL: pgsql/contrib/isbn_issn/isbn_issn.c,v 1.9 2006/05/30 22:12:13 tgl Exp $ |
|
||||||
*/ |
|
||||||
|
|
||||||
#include "postgres.h" |
|
||||||
|
|
||||||
#include "fmgr.h" |
|
||||||
|
|
||||||
|
|
||||||
PG_MODULE_MAGIC; |
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the internal storage format for ISBNs. |
|
||||||
* NB: This is an intentional type pun with builtin type `char16'. |
|
||||||
*/ |
|
||||||
|
|
||||||
typedef struct isbn |
|
||||||
{ |
|
||||||
char num[13]; |
|
||||||
char pad[3]; |
|
||||||
} isbn; |
|
||||||
|
|
||||||
/*
|
|
||||||
* Various forward declarations: |
|
||||||
*/ |
|
||||||
|
|
||||||
isbn *isbn_in(char *str); |
|
||||||
char *isbn_out(isbn * addr); |
|
||||||
|
|
||||||
bool isbn_lt(isbn * a1, isbn * a2); |
|
||||||
bool isbn_le(isbn * a1, isbn * a2); |
|
||||||
bool isbn_eq(isbn * a1, isbn * a2); |
|
||||||
bool isbn_ge(isbn * a1, isbn * a2); |
|
||||||
bool isbn_gt(isbn * a1, isbn * a2); |
|
||||||
|
|
||||||
bool isbn_ne(isbn * a1, isbn * a2); |
|
||||||
|
|
||||||
int4 isbn_cmp(isbn * a1, isbn * a2); |
|
||||||
|
|
||||||
int4 isbn_sum(char *str); |
|
||||||
|
|
||||||
/*
|
|
||||||
* ISBN reader. |
|
||||||
*/ |
|
||||||
|
|
||||||
isbn * |
|
||||||
isbn_in(char *str) |
|
||||||
{ |
|
||||||
isbn *result; |
|
||||||
int len; |
|
||||||
|
|
||||||
len = strlen(str); |
|
||||||
if (len != 13) |
|
||||||
ereport(ERROR, |
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
|
||||||
errmsg("invalid ISBN: \"%s\"", str), |
|
||||||
errdetail("ISBNs must be 13 characters in length."))); |
|
||||||
|
|
||||||
if (isbn_sum(str) != 0) |
|
||||||
ereport(ERROR, |
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
|
||||||
errmsg("invalid ISBN: \"%s\"", str), |
|
||||||
errdetail("ISBN failed checksum."))); |
|
||||||
|
|
||||||
result = (isbn *) palloc(sizeof(isbn)); |
|
||||||
memcpy(result->num, str, len); |
|
||||||
memset(result->pad, ' ', 3); |
|
||||||
return (result); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* The ISBN checksum is defined as follows: |
|
||||||
* |
|
||||||
* Number the digits from 1 to 9 (call this N). |
|
||||||
* Compute the sum, S, of N * D_N. |
|
||||||
* The check digit, C, is the value which satisfies the equation |
|
||||||
* S + 10*C === 0 (mod 11) |
|
||||||
* The value 10 for C is written as `X'. |
|
||||||
* |
|
||||||
* For our purposes, we want the complete sum including the check |
|
||||||
* digit; if this is zero, then the checksum passed. We also check |
|
||||||
* the syntactic validity if the provided string, and return 12 |
|
||||||
* if any errors are found. |
|
||||||
*/ |
|
||||||
int4 |
|
||||||
isbn_sum(char *str) |
|
||||||
{ |
|
||||||
int4 sum = 0, |
|
||||||
dashes = 0, |
|
||||||
val; |
|
||||||
int i; |
|
||||||
|
|
||||||
for (i = 0; str[i] && i < 13; i++) |
|
||||||
{ |
|
||||||
switch (str[i]) |
|
||||||
{ |
|
||||||
case '-': |
|
||||||
if (++dashes > 3) |
|
||||||
return 12; |
|
||||||
continue; |
|
||||||
|
|
||||||
case '0': |
|
||||||
case '1': |
|
||||||
case '2': |
|
||||||
case '3': |
|
||||||
case '4': |
|
||||||
case '5': |
|
||||||
case '6': |
|
||||||
case '7': |
|
||||||
case '8': |
|
||||||
case '9': |
|
||||||
val = str[i] - '0'; |
|
||||||
break; |
|
||||||
|
|
||||||
case 'X': |
|
||||||
case 'x': |
|
||||||
val = 10; |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
return 12; |
|
||||||
} |
|
||||||
|
|
||||||
sum += val * (i + 1 - dashes); |
|
||||||
} |
|
||||||
return (sum % 11); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* ISBN output function. |
|
||||||
*/ |
|
||||||
|
|
||||||
char * |
|
||||||
isbn_out(isbn * num) |
|
||||||
{ |
|
||||||
char *result; |
|
||||||
|
|
||||||
if (num == NULL) |
|
||||||
return (NULL); |
|
||||||
|
|
||||||
result = (char *) palloc(14); |
|
||||||
|
|
||||||
result[0] = '\0'; |
|
||||||
strncat(result, num->num, 13); |
|
||||||
return (result); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* Boolean tests for magnitude. |
|
||||||
*/ |
|
||||||
|
|
||||||
bool |
|
||||||
isbn_lt(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13) < 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
isbn_le(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13) <= 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
isbn_eq(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13) == 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
isbn_ge(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13) >= 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
isbn_gt(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13) > 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
isbn_ne(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13) != 0); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* Comparison function for sorting: |
|
||||||
*/ |
|
||||||
|
|
||||||
int4 |
|
||||||
isbn_cmp(isbn * a1, isbn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 13)); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------- ISSN --------------------------- */ |
|
||||||
|
|
||||||
/*
|
|
||||||
* This is the internal storage format for ISSNs. |
|
||||||
* NB: This is an intentional type pun with builtin type `char16'. |
|
||||||
*/ |
|
||||||
|
|
||||||
typedef struct issn |
|
||||||
{ |
|
||||||
char num[9]; |
|
||||||
char pad[7]; |
|
||||||
} issn; |
|
||||||
|
|
||||||
/*
|
|
||||||
* Various forward declarations: |
|
||||||
*/ |
|
||||||
|
|
||||||
issn *issn_in(char *str); |
|
||||||
char *issn_out(issn * addr); |
|
||||||
|
|
||||||
bool issn_lt(issn * a1, issn * a2); |
|
||||||
bool issn_le(issn * a1, issn * a2); |
|
||||||
bool issn_eq(issn * a1, issn * a2); |
|
||||||
bool issn_ge(issn * a1, issn * a2); |
|
||||||
bool issn_gt(issn * a1, issn * a2); |
|
||||||
|
|
||||||
bool issn_ne(issn * a1, issn * a2); |
|
||||||
|
|
||||||
int4 issn_cmp(issn * a1, issn * a2); |
|
||||||
|
|
||||||
int4 issn_sum(char *str); |
|
||||||
|
|
||||||
/*
|
|
||||||
* ISSN reader. |
|
||||||
*/ |
|
||||||
|
|
||||||
issn * |
|
||||||
issn_in(char *str) |
|
||||||
{ |
|
||||||
issn *result; |
|
||||||
int len; |
|
||||||
|
|
||||||
len = strlen(str); |
|
||||||
if (len != 9) |
|
||||||
ereport(ERROR, |
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
|
||||||
errmsg("invalid ISSN: \"%s\"", str), |
|
||||||
errdetail("ISSNs must be 9 characters in length."))); |
|
||||||
|
|
||||||
if (issn_sum(str) != 0) |
|
||||||
ereport(ERROR, |
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
|
||||||
errmsg("invalid ISSN: \"%s\"", str), |
|
||||||
errdetail("ISSN failed checksum."))); |
|
||||||
|
|
||||||
result = (issn *) palloc(sizeof(issn)); |
|
||||||
memcpy(result->num, str, len); |
|
||||||
memset(result->pad, ' ', 7); |
|
||||||
return (result); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* The ISSN checksum works just like the ISBN sum, only different |
|
||||||
* (of course!). |
|
||||||
* Here, the weights start at 8 and decrease. |
|
||||||
*/ |
|
||||||
int4 |
|
||||||
issn_sum(char *str) |
|
||||||
{ |
|
||||||
int4 sum = 0, |
|
||||||
dashes = 0, |
|
||||||
val; |
|
||||||
int i; |
|
||||||
|
|
||||||
for (i = 0; str[i] && i < 9; i++) |
|
||||||
{ |
|
||||||
switch (str[i]) |
|
||||||
{ |
|
||||||
case '-': |
|
||||||
if (++dashes > 1) |
|
||||||
return 12; |
|
||||||
continue; |
|
||||||
|
|
||||||
case '0': |
|
||||||
case '1': |
|
||||||
case '2': |
|
||||||
case '3': |
|
||||||
case '4': |
|
||||||
case '5': |
|
||||||
case '6': |
|
||||||
case '7': |
|
||||||
case '8': |
|
||||||
case '9': |
|
||||||
val = str[i] - '0'; |
|
||||||
break; |
|
||||||
|
|
||||||
case 'X': |
|
||||||
case 'x': |
|
||||||
val = 10; |
|
||||||
break; |
|
||||||
|
|
||||||
default: |
|
||||||
return 12; |
|
||||||
} |
|
||||||
|
|
||||||
sum += val * (8 - (i - dashes)); |
|
||||||
} |
|
||||||
return (sum % 11); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* ISSN output function. |
|
||||||
*/ |
|
||||||
|
|
||||||
char * |
|
||||||
issn_out(issn * num) |
|
||||||
{ |
|
||||||
char *result; |
|
||||||
|
|
||||||
if (num == NULL) |
|
||||||
return (NULL); |
|
||||||
|
|
||||||
result = (char *) palloc(14); |
|
||||||
|
|
||||||
result[0] = '\0'; |
|
||||||
strncat(result, num->num, 9); |
|
||||||
return (result); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* Boolean tests for magnitude. |
|
||||||
*/ |
|
||||||
|
|
||||||
bool |
|
||||||
issn_lt(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9) < 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
issn_le(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9) <= 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
issn_eq(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9) == 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
issn_ge(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9) >= 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
issn_gt(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9) > 0); |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
issn_ne(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9) != 0); |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* Comparison function for sorting: |
|
||||||
*/ |
|
||||||
|
|
||||||
int4 |
|
||||||
issn_cmp(issn * a1, issn * a2) |
|
||||||
{ |
|
||||||
return (strncmp(a1->num, a2->num, 9)); |
|
||||||
} |
|
@ -1,269 +0,0 @@ |
|||||||
-- |
|
||||||
-- PostgreSQL code for ISSNs. |
|
||||||
-- |
|
||||||
-- $PostgreSQL: pgsql/contrib/isbn_issn/isbn_issn.sql.in,v 1.12 2006/02/27 16:09:48 petere Exp $ |
|
||||||
-- |
|
||||||
|
|
||||||
-- Adjust this setting to control where the objects get created. |
|
||||||
SET search_path = public; |
|
||||||
|
|
||||||
-- |
|
||||||
-- Input and output functions and the type itself: |
|
||||||
-- |
|
||||||
|
|
||||||
CREATE FUNCTION issn_in(cstring) |
|
||||||
RETURNS issn |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION issn_out(issn) |
|
||||||
RETURNS cstring |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE TYPE issn ( |
|
||||||
INTERNALLENGTH = 16, |
|
||||||
EXTERNALLENGTH = 9, |
|
||||||
INPUT = issn_in, |
|
||||||
OUTPUT = issn_out |
|
||||||
); |
|
||||||
|
|
||||||
COMMENT ON TYPE issn |
|
||||||
is 'International Standard Serial Number'; |
|
||||||
|
|
||||||
|
|
||||||
-- |
|
||||||
-- The various boolean tests: |
|
||||||
-- |
|
||||||
|
|
||||||
CREATE FUNCTION issn_lt(issn, issn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION issn_le(issn, issn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION issn_eq(issn, issn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION issn_ge(issn, issn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION issn_gt(issn, issn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION issn_ne(issn, issn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
-- |
|
||||||
-- Now the operators. Note how some of the parameters to some |
|
||||||
-- of the 'create operator' commands are commented out. This |
|
||||||
-- is because they reference as yet undefined operators, and |
|
||||||
-- will be implicitly defined when those are, further down. |
|
||||||
-- |
|
||||||
|
|
||||||
CREATE OPERATOR < ( |
|
||||||
LEFTARG = issn, |
|
||||||
RIGHTARG = issn, |
|
||||||
-- NEGATOR = >=, |
|
||||||
PROCEDURE = issn_lt |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR <= ( |
|
||||||
LEFTARG = issn, |
|
||||||
RIGHTARG = issn, |
|
||||||
-- NEGATOR = >, |
|
||||||
PROCEDURE = issn_le |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR = ( |
|
||||||
LEFTARG = issn, |
|
||||||
RIGHTARG = issn, |
|
||||||
COMMUTATOR = =, |
|
||||||
-- NEGATOR = <>, |
|
||||||
PROCEDURE = issn_eq |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR >= ( |
|
||||||
LEFTARG = issn, |
|
||||||
RIGHTARG = issn, |
|
||||||
NEGATOR = <, |
|
||||||
PROCEDURE = issn_ge |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR > ( |
|
||||||
LEFTARG = issn, |
|
||||||
RIGHTARG = issn, |
|
||||||
NEGATOR = <=, |
|
||||||
PROCEDURE = issn_gt |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR <> ( |
|
||||||
LEFTARG = issn, |
|
||||||
RIGHTARG = issn, |
|
||||||
NEGATOR = =, |
|
||||||
PROCEDURE = issn_ne |
|
||||||
); |
|
||||||
|
|
||||||
-- Register 'issn' comparison function |
|
||||||
CREATE FUNCTION issn_cmp(issn, issn) |
|
||||||
RETURNS integer |
|
||||||
AS '$libdir/isbn_issn' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
-- Create default operator class for 'issn' -- |
|
||||||
-- Needed to create index or primary key -- |
|
||||||
|
|
||||||
CREATE OPERATOR CLASS issn_ops |
|
||||||
DEFAULT FOR TYPE issn USING btree |
|
||||||
AS |
|
||||||
OPERATOR 1 < , |
|
||||||
OPERATOR 2 <= , |
|
||||||
OPERATOR 3 = , |
|
||||||
OPERATOR 4 >= , |
|
||||||
OPERATOR 5 > , |
|
||||||
FUNCTION 1 issn_cmp(issn, issn); |
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------ |
|
||||||
|
|
||||||
-- |
|
||||||
-- Same code for ISBN |
|
||||||
-- |
|
||||||
-- Input and output functions and the type itself: |
|
||||||
-- |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_in(cstring) |
|
||||||
RETURNS isbn |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_out(isbn) |
|
||||||
RETURNS cstring |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE TYPE isbn ( |
|
||||||
INTERNALLENGTH = 16, |
|
||||||
EXTERNALLENGTH = 13, |
|
||||||
INPUT = isbn_in, |
|
||||||
OUTPUT = isbn_out |
|
||||||
); |
|
||||||
|
|
||||||
COMMENT ON TYPE isbn IS 'International Standard Book Number'; |
|
||||||
|
|
||||||
|
|
||||||
-- |
|
||||||
-- The various boolean tests: |
|
||||||
-- |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_lt(isbn, isbn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_le(isbn, isbn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_eq(isbn, isbn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_ge(isbn, isbn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_gt(isbn, isbn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
CREATE FUNCTION isbn_ne(isbn, isbn) |
|
||||||
RETURNS bool |
|
||||||
AS 'MODULE_PATHNAME' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
-- |
|
||||||
-- Now the operators. Note how some of the parameters to some |
|
||||||
-- of the 'create operator' commands are commented out. This |
|
||||||
-- is because they reference as yet undefined operators, and |
|
||||||
-- will be implicitly defined when those are, further down. |
|
||||||
-- |
|
||||||
|
|
||||||
CREATE OPERATOR < ( |
|
||||||
LEFTARG = isbn, |
|
||||||
RIGHTARG = isbn, |
|
||||||
-- NEGATOR = >=, |
|
||||||
PROCEDURE = isbn_lt |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR <= ( |
|
||||||
LEFTARG = isbn, |
|
||||||
RIGHTARG = isbn, |
|
||||||
-- NEGATOR = >, |
|
||||||
PROCEDURE = isbn_le |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR = ( |
|
||||||
LEFTARG = isbn, |
|
||||||
RIGHTARG = isbn, |
|
||||||
COMMUTATOR = =, |
|
||||||
-- NEGATOR = <>, |
|
||||||
PROCEDURE = isbn_eq |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR >= ( |
|
||||||
LEFTARG = isbn, |
|
||||||
RIGHTARG = isbn, |
|
||||||
NEGATOR = <, |
|
||||||
PROCEDURE = isbn_ge |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR > ( |
|
||||||
LEFTARG = isbn, |
|
||||||
RIGHTARG = isbn, |
|
||||||
NEGATOR = <=, |
|
||||||
PROCEDURE = isbn_gt |
|
||||||
); |
|
||||||
|
|
||||||
CREATE OPERATOR <> ( |
|
||||||
LEFTARG = isbn, |
|
||||||
RIGHTARG = isbn, |
|
||||||
NEGATOR = =, |
|
||||||
PROCEDURE = isbn_ne |
|
||||||
); |
|
||||||
|
|
||||||
|
|
||||||
-- Register 'isbn' comparison function |
|
||||||
CREATE FUNCTION isbn_cmp(isbn, isbn) |
|
||||||
RETURNS integer |
|
||||||
AS '$libdir/isbn_issn' |
|
||||||
LANGUAGE C STRICT; |
|
||||||
|
|
||||||
-- Create default operator class for 'isbn' -- |
|
||||||
-- Needed to create index or primary key -- |
|
||||||
|
|
||||||
CREATE OPERATOR CLASS isbn_ops |
|
||||||
DEFAULT FOR TYPE isbn USING btree |
|
||||||
AS |
|
||||||
OPERATOR 1 < , |
|
||||||
OPERATOR 2 <= , |
|
||||||
OPERATOR 3 = , |
|
||||||
OPERATOR 4 >= , |
|
||||||
OPERATOR 5 > , |
|
||||||
FUNCTION 1 isbn_cmp(isbn, isbn); |
|
@ -1,61 +0,0 @@ |
|||||||
SET search_path = public; |
|
||||||
|
|
||||||
DROP OPERATOR CLASS isbn_ops USING btree; |
|
||||||
|
|
||||||
DROP FUNCTION isbn_cmp(isbn, isbn); |
|
||||||
|
|
||||||
DROP OPERATOR <> (isbn, isbn); |
|
||||||
|
|
||||||
DROP OPERATOR > (isbn, isbn); |
|
||||||
|
|
||||||
DROP OPERATOR >= (isbn, isbn); |
|
||||||
|
|
||||||
DROP OPERATOR = (isbn, isbn); |
|
||||||
|
|
||||||
DROP OPERATOR <= (isbn, isbn); |
|
||||||
|
|
||||||
DROP OPERATOR < (isbn, isbn); |
|
||||||
|
|
||||||
DROP FUNCTION isbn_ne(isbn, isbn); |
|
||||||
|
|
||||||
DROP FUNCTION isbn_gt(isbn, isbn); |
|
||||||
|
|
||||||
DROP FUNCTION isbn_ge(isbn, isbn); |
|
||||||
|
|
||||||
DROP FUNCTION isbn_eq(isbn, isbn); |
|
||||||
|
|
||||||
DROP FUNCTION isbn_le(isbn, isbn); |
|
||||||
|
|
||||||
DROP FUNCTION isbn_lt(isbn, isbn); |
|
||||||
|
|
||||||
DROP TYPE isbn CASCADE; |
|
||||||
|
|
||||||
DROP OPERATOR CLASS issn_ops USING btree; |
|
||||||
|
|
||||||
DROP FUNCTION issn_cmp(issn, issn); |
|
||||||
|
|
||||||
DROP OPERATOR <> (issn, issn); |
|
||||||
|
|
||||||
DROP OPERATOR > (issn, issn); |
|
||||||
|
|
||||||
DROP OPERATOR >= (issn, issn); |
|
||||||
|
|
||||||
DROP OPERATOR = (issn, issn); |
|
||||||
|
|
||||||
DROP OPERATOR <= (issn, issn); |
|
||||||
|
|
||||||
DROP OPERATOR < (issn, issn); |
|
||||||
|
|
||||||
DROP FUNCTION issn_ne(issn, issn); |
|
||||||
|
|
||||||
DROP FUNCTION issn_gt(issn, issn); |
|
||||||
|
|
||||||
DROP FUNCTION issn_ge(issn, issn); |
|
||||||
|
|
||||||
DROP FUNCTION issn_eq(issn, issn); |
|
||||||
|
|
||||||
DROP FUNCTION issn_le(issn, issn); |
|
||||||
|
|
||||||
DROP FUNCTION issn_lt(issn, issn); |
|
||||||
|
|
||||||
DROP TYPE issn CASCADE; |
|
@ -0,0 +1,147 @@ |
|||||||
|
/*
|
||||||
|
* EAN13.h |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* Information recompiled by Kronuz on August 23, 2006 |
||||||
|
* http://www.gs1.org/productssolutions/idkeys/support/prefix_list.html
|
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/EAN13.h,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/* where the digit set begins, and how many of them are in the table */ |
||||||
|
const unsigned EAN13_index[10][2] = { |
||||||
|
{0, 6}, |
||||||
|
{6, 1}, |
||||||
|
{7, 1}, |
||||||
|
{8, 5}, |
||||||
|
{13, 20}, |
||||||
|
{33, 15}, |
||||||
|
{48, 19}, |
||||||
|
{67, 23}, |
||||||
|
{90, 17}, |
||||||
|
{107, 12}, |
||||||
|
}; |
||||||
|
const char *EAN13_range[][2] = { |
||||||
|
{"000", "019"}, /* GS1 US */ |
||||||
|
{"020", "029"}, /* Restricted distribution (MO defined) */ |
||||||
|
{"030", "039"}, /* GS1 US */ |
||||||
|
{"040", "049"}, /* Restricted distribution (MO defined) */ |
||||||
|
{"050", "059"}, /* Coupons */ |
||||||
|
{"060", "099"}, /* GS1 US */ |
||||||
|
{"100", "139"}, /* GS1 US */ |
||||||
|
{"200", "299"}, /* Restricted distribution (MO defined) */ |
||||||
|
{"300", "379"}, /* GS1 France */ |
||||||
|
{"380", "380"}, /* GS1 Bulgaria */ |
||||||
|
{"383", "383"}, /* GS1 Slovenija */ |
||||||
|
{"385", "385"}, /* GS1 Croatia */ |
||||||
|
{"387", "387"}, /* GS1 BIH (Bosnia-Herzegovina) */ |
||||||
|
{"400", "440"}, /* GS1 Germany */ |
||||||
|
{"450", "459"}, /* GS1 Japan */ |
||||||
|
{"460", "469"}, /* GS1 Russia */ |
||||||
|
{"470", "470"}, /* GS1 Kyrgyzstan */ |
||||||
|
{"471", "471"}, /* GS1 Taiwan */ |
||||||
|
{"474", "474"}, /* GS1 Estonia */ |
||||||
|
{"475", "475"}, /* GS1 Latvia */ |
||||||
|
{"476", "476"}, /* GS1 Azerbaijan */ |
||||||
|
{"477", "477"}, /* GS1 Lithuania */ |
||||||
|
{"478", "478"}, /* GS1 Uzbekistan */ |
||||||
|
{"479", "479"}, /* GS1 Sri Lanka */ |
||||||
|
{"480", "480"}, /* GS1 Philippines */ |
||||||
|
{"481", "481"}, /* GS1 Belarus */ |
||||||
|
{"482", "482"}, /* GS1 Ukraine */ |
||||||
|
{"484", "484"}, /* GS1 Moldova */ |
||||||
|
{"485", "485"}, /* GS1 Armenia */ |
||||||
|
{"486", "486"}, /* GS1 Georgia */ |
||||||
|
{"487", "487"}, /* GS1 Kazakstan */ |
||||||
|
{"489", "489"}, /* GS1 Hong Kong */ |
||||||
|
{"490", "499"}, /* GS1 Japan */ |
||||||
|
{"500", "509"}, /* GS1 UK */ |
||||||
|
{"520", "520"}, /* GS1 Greece */ |
||||||
|
{"528", "528"}, /* GS1 Lebanon */ |
||||||
|
{"529", "529"}, /* GS1 Cyprus */ |
||||||
|
{"530", "530"}, /* GS1 Albania */ |
||||||
|
{"531", "531"}, /* GS1 MAC (FYR Macedonia) */ |
||||||
|
{"535", "535"}, /* GS1 Malta */ |
||||||
|
{"539", "539"}, /* GS1 Ireland */ |
||||||
|
{"540", "549"}, /* GS1 Belgium & Luxembourg */ |
||||||
|
{"560", "560"}, /* GS1 Portugal */ |
||||||
|
{"569", "569"}, /* GS1 Iceland */ |
||||||
|
{"570", "579"}, /* GS1 Denmark */ |
||||||
|
{"590", "590"}, /* GS1 Poland */ |
||||||
|
{"594", "594"}, /* GS1 Romania */ |
||||||
|
{"599", "599"}, /* GS1 Hungary */ |
||||||
|
{"600", "601"}, /* GS1 South Africa */ |
||||||
|
{"603", "603"}, /* GS1 Ghana */ |
||||||
|
{"608", "608"}, /* GS1 Bahrain */ |
||||||
|
{"609", "609"}, /* GS1 Mauritius */ |
||||||
|
{"611", "611"}, /* GS1 Morocco */ |
||||||
|
{"613", "613"}, /* GS1 Algeria */ |
||||||
|
{"616", "616"}, /* GS1 Kenya */ |
||||||
|
{"618", "618"}, /* GS1 Ivory Coast */ |
||||||
|
{"619", "619"}, /* GS1 Tunisia */ |
||||||
|
{"621", "621"}, /* GS1 Syria */ |
||||||
|
{"622", "622"}, /* GS1 Egypt */ |
||||||
|
{"624", "624"}, /* GS1 Libya */ |
||||||
|
{"625", "625"}, /* GS1 Jordan */ |
||||||
|
{"626", "626"}, /* GS1 Iran */ |
||||||
|
{"627", "627"}, /* GS1 Kuwait */ |
||||||
|
{"628", "628"}, /* GS1 Saudi Arabia */ |
||||||
|
{"629", "629"}, /* GS1 Emirates */ |
||||||
|
{"640", "649"}, /* GS1 Finland */ |
||||||
|
{"690", "695"}, /* GS1 China */ |
||||||
|
{"700", "709"}, /* GS1 Norway */ |
||||||
|
{"729", "729"}, /* GS1 Israel */ |
||||||
|
{"730", "739"}, /* GS1 Sweden */ |
||||||
|
{"740", "740"}, /* GS1 Guatemala */ |
||||||
|
{"741", "741"}, /* GS1 El Salvador */ |
||||||
|
{"742", "742"}, /* GS1 Honduras */ |
||||||
|
{"743", "743"}, /* GS1 Nicaragua */ |
||||||
|
{"744", "744"}, /* GS1 Costa Rica */ |
||||||
|
{"745", "745"}, /* GS1 Panama */ |
||||||
|
{"746", "746"}, /* GS1 Republica Dominicana */ |
||||||
|
{"750", "750"}, /* GS1 Mexico */ |
||||||
|
{"754", "755"}, /* GS1 Canada */ |
||||||
|
{"759", "759"}, /* GS1 Venezuela */ |
||||||
|
{"760", "769"}, /* GS1 Schweiz, Suisse, Svizzera */ |
||||||
|
{"770", "770"}, /* GS1 Colombia */ |
||||||
|
{"773", "773"}, /* GS1 Uruguay */ |
||||||
|
{"775", "775"}, /* GS1 Peru */ |
||||||
|
{"777", "777"}, /* GS1 Bolivia */ |
||||||
|
{"779", "779"}, /* GS1 Argentina */ |
||||||
|
{"780", "780"}, /* GS1 Chile */ |
||||||
|
{"784", "784"}, /* GS1 Paraguay */ |
||||||
|
{"786", "786"}, /* GS1 Ecuador */ |
||||||
|
{"789", "790"}, /* GS1 Brasil */ |
||||||
|
{"800", "839"}, /* GS1 Italy */ |
||||||
|
{"840", "849"}, /* GS1 Spain */ |
||||||
|
{"850", "850"}, /* GS1 Cuba */ |
||||||
|
{"858", "858"}, /* GS1 Slovakia */ |
||||||
|
{"859", "859"}, /* GS1 Czech */ |
||||||
|
{"860", "860"}, /* GS1 YU (Serbia & Montenegro) */ |
||||||
|
{"865", "865"}, /* GS1 Mongolia */ |
||||||
|
{"867", "867"}, /* GS1 North Korea */ |
||||||
|
{"869", "869"}, /* GS1 Turkey */ |
||||||
|
{"870", "879"}, /* GS1 Netherlands */ |
||||||
|
{"880", "880"}, /* GS1 South Korea */ |
||||||
|
{"884", "884"}, /* GS1 Cambodia */ |
||||||
|
{"885", "885"}, /* GS1 Thailand */ |
||||||
|
{"888", "888"}, /* GS1 Singapore */ |
||||||
|
{"890", "890"}, /* GS1 India */ |
||||||
|
{"893", "893"}, /* GS1 Vietnam */ |
||||||
|
{"899", "899"}, /* GS1 Indonesia */ |
||||||
|
{"900", "919"}, /* GS1 Austria */ |
||||||
|
{"930", "939"}, /* GS1 Australia */ |
||||||
|
{"940", "949"}, /* GS1 New Zealand */ |
||||||
|
{"950", "950"}, /* GS1 Head Office */ |
||||||
|
{"955", "955"}, /* GS1 Malaysia */ |
||||||
|
{"958", "958"}, /* GS1 Macau */ |
||||||
|
{"977", "977"}, /* Serial publications (ISSN) */ |
||||||
|
{"978", "978"}, /* Bookland (ISBN) */ |
||||||
|
{"979", "979"}, /* International Standard Music Number (ISMN) and ISBN contingent */ |
||||||
|
{"980", "980"}, /* Refund receipts */ |
||||||
|
{"981", "982"}, /* Common Currency Coupons */ |
||||||
|
{"990", "999"}, /* Coupons */ |
||||||
|
{NULL, NULL} |
||||||
|
}; |
@ -0,0 +1,732 @@ |
|||||||
|
/*
|
||||||
|
* ISBN.h |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* Information recompiled by Kronuz on June 20, 2006 |
||||||
|
* http://www.isbn-international.org/
|
||||||
|
* http://www.isbn.org/
|
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/ISBN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
* 0-393-04002-X => 039304002(X) <=> 039304002 <=> (978)039304002 <=> 978039304002(9) <=> 978-0-393-04002-9 |
||||||
|
* |
||||||
|
* |
||||||
|
* ISBN 0 3 9 3 0 4 0 0 2 |
||||||
|
* Weight 10 9 8 7 6 5 4 3 2 |
||||||
|
* Product 0 + 27 + 72 + 21 + 0 + 20 + 0 + 0 + 4 = 144 |
||||||
|
* 144 / 11 = 13 remainder 1 |
||||||
|
* Check digit 11 - 1 = 10 = X |
||||||
|
* => 0-393-04002-X |
||||||
|
* |
||||||
|
* ISBN 9 7 8 0 3 9 3 0 4 0 0 2 |
||||||
|
* Weight 1 3 1 3 1 3 1 3 1 3 1 3 |
||||||
|
* Product 9 + 21 + 8 + 0 + 3 + 27 + 3 + 0 + 4 + 0 + 0 + 6 = 81 |
||||||
|
* 81 / 10 = 8 remainder 1 |
||||||
|
* Check digit 10 - 1 = 9 |
||||||
|
* => 978-0-393-04002-9 |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/* where the digit set begins, and how many of them are in the table */ |
||||||
|
const unsigned ISBN_index[10][2] = { |
||||||
|
{0, 6}, |
||||||
|
{6, 6}, |
||||||
|
{12, 8}, |
||||||
|
{20, 10}, |
||||||
|
{30, 6}, |
||||||
|
{36, 12}, |
||||||
|
{48, 0}, |
||||||
|
{48, 5}, |
||||||
|
{53, 59}, |
||||||
|
{112, 573}, |
||||||
|
}; |
||||||
|
|
||||||
|
const char *ISBN_range[][2] = { |
||||||
|
{"0-00", "0-19"}, |
||||||
|
{"0-200", "0-699"}, |
||||||
|
{"0-7000", "0-8499"}, |
||||||
|
{"0-85000", "0-89999"}, |
||||||
|
{"0-900000", "0-949999"}, |
||||||
|
{"0-9500000", "0-9999999"}, |
||||||
|
{"1-00", "1-09"}, |
||||||
|
{"1-100", "1-399"}, |
||||||
|
{"1-4000", "1-5499"}, |
||||||
|
{"1-55000", "1-86979"}, |
||||||
|
{"1-869800", "1-998999"}, |
||||||
|
{"1-9990000", "1-9999999"}, |
||||||
|
{"2-00", "2-19"}, |
||||||
|
{"2-200", "2-349"}, |
||||||
|
{"2-35000", "2-39999"}, |
||||||
|
{"2-400", "2-699"}, |
||||||
|
{"2-7000", "2-8399"}, |
||||||
|
{"2-84000", "2-89999"}, |
||||||
|
{"2-900000", "2-949999"}, |
||||||
|
{"2-9500000", "2-9999999"}, |
||||||
|
{"3-00", "3-02"}, |
||||||
|
{"3-030", "3-033"}, |
||||||
|
{"3-0340", "3-0369"}, |
||||||
|
{"3-03700", "3-03999"}, |
||||||
|
{"3-04", "3-19"}, |
||||||
|
{"3-200", "3-699"}, |
||||||
|
{"3-7000", "3-8499"}, |
||||||
|
{"3-85000", "3-89999"}, |
||||||
|
{"3-900000", "3-949999"}, |
||||||
|
{"3-9500000", "3-9999999"}, |
||||||
|
{"4-00", "4-19"}, |
||||||
|
{"4-200", "4-699"}, |
||||||
|
{"4-7000", "4-8499"}, |
||||||
|
{"4-85000", "4-89999"}, |
||||||
|
{"4-900000", "4-949999"}, |
||||||
|
{"4-9500000", "4-9999999"}, |
||||||
|
{"5-00", "5-19"}, |
||||||
|
{"5-200", "5-699"}, |
||||||
|
{"5-7000", "5-8499"}, |
||||||
|
{"5-85000", "5-89999"}, |
||||||
|
{"5-900000", "5-909999"}, |
||||||
|
{"5-91000", "5-91999"}, |
||||||
|
{"5-9200", "5-9299"}, |
||||||
|
{"5-93000", "5-94999"}, |
||||||
|
{"5-9500", "5-9799"}, |
||||||
|
{"5-98000", "5-98999"}, |
||||||
|
{"5-9900000", "5-9909999"}, |
||||||
|
{"5-9910", "5-9999"}, |
||||||
|
{"7-00", "7-09"}, |
||||||
|
{"7-100", "7-499"}, |
||||||
|
{"7-5000", "7-7999"}, |
||||||
|
{"7-80000", "7-89999"}, |
||||||
|
{"7-900000", "7-999999"}, |
||||||
|
{"80-00", "80-19"}, |
||||||
|
{"80-200", "80-699"}, |
||||||
|
{"80-7000", "80-8499"}, |
||||||
|
{"80-85000", "80-89999"}, |
||||||
|
{"80-900000", "80-999999"}, |
||||||
|
{"81-00", "81-19"}, |
||||||
|
{"81-200", "81-699"}, |
||||||
|
{"81-7000", "81-8499"}, |
||||||
|
{"81-85000", "81-89999"}, |
||||||
|
{"81-900000", "81-999999"}, |
||||||
|
{"82-00", "82-19"}, |
||||||
|
{"82-200", "82-699"}, |
||||||
|
{"82-7000", "82-8999"}, |
||||||
|
{"82-90000", "82-98999"}, |
||||||
|
{"82-990000", "82-999999"}, |
||||||
|
{"83-00", "83-19"}, |
||||||
|
{"83-200", "83-599"}, |
||||||
|
{"83-60000", "83-69999"}, |
||||||
|
{"83-7000", "83-8499"}, |
||||||
|
{"83-85000", "83-89999"}, |
||||||
|
{"83-900000", "83-999999"}, |
||||||
|
{"84-00", "84-19"}, |
||||||
|
{"84-200", "84-699"}, |
||||||
|
{"84-7000", "84-8499"}, |
||||||
|
{"84-85000", "84-89999"}, |
||||||
|
{"84-9000", "84-9199"}, |
||||||
|
{"84-920000", "84-923999"}, |
||||||
|
{"84-92400", "84-92999"}, |
||||||
|
{"84-930000", "84-949999"}, |
||||||
|
{"84-95000", "84-96999"}, |
||||||
|
{"84-9700", "84-9999"}, |
||||||
|
{"85-00", "85-19"}, |
||||||
|
{"85-200", "85-599"}, |
||||||
|
{"85-60000", "85-69999"}, |
||||||
|
{"85-7000", "85-8499"}, |
||||||
|
{"85-85000", "85-89999"}, |
||||||
|
{"85-900000", "85-979999"}, |
||||||
|
{"85-98000", "85-99999"}, |
||||||
|
{"86-00", "86-29"}, |
||||||
|
{"86-300", "86-699"}, |
||||||
|
{"86-7000", "86-7999"}, |
||||||
|
{"86-80000", "86-89999"}, |
||||||
|
{"86-900000", "86-999999"}, |
||||||
|
{"87-00", "87-29"}, |
||||||
|
{"87-400", "87-649"}, |
||||||
|
{"87-7000", "87-7999"}, |
||||||
|
{"87-85000", "87-94999"}, |
||||||
|
{"87-970000", "87-999999"}, |
||||||
|
{"88-00", "88-19"}, |
||||||
|
{"88-200", "88-599"}, |
||||||
|
{"88-6000", "88-8499"}, |
||||||
|
{"88-85000", "88-89999"}, |
||||||
|
{"88-900000", "88-949999"}, |
||||||
|
{"88-95000", "88-99999"}, |
||||||
|
{"89-00", "89-24"}, |
||||||
|
{"89-250", "89-549"}, |
||||||
|
{"89-5500", "89-8499"}, |
||||||
|
{"89-85000", "89-94999"}, |
||||||
|
{"89-950000", "89-999999"}, |
||||||
|
{"90-00", "90-19"}, |
||||||
|
{"90-200", "90-499"}, |
||||||
|
{"90-5000", "90-6999"}, |
||||||
|
{"90-70000", "90-79999"}, |
||||||
|
{"90-800000", "90-849999"}, |
||||||
|
{"90-8500", "90-8999"}, |
||||||
|
{"90-900000", "90-909999"}, |
||||||
|
{"90-940000", "90-949999"}, |
||||||
|
{"91-0", "91-1"}, |
||||||
|
{"91-20", "91-49"}, |
||||||
|
{"91-500", "91-649"}, |
||||||
|
{"91-7000", "91-7999"}, |
||||||
|
{"91-85000", "91-94999"}, |
||||||
|
{"91-970000", "91-999999"}, |
||||||
|
{"92-0", "92-5"}, |
||||||
|
{"92-60", "92-79"}, |
||||||
|
{"92-800", "92-899"}, |
||||||
|
{"92-9000", "92-9499"}, |
||||||
|
{"92-95000", "92-98999"}, |
||||||
|
{"92-990000", "92-999999"}, |
||||||
|
{"950-00", "950-49"}, |
||||||
|
{"950-500", "950-899"}, |
||||||
|
{"950-9000", "950-9899"}, |
||||||
|
{"950-99000", "950-99999"}, |
||||||
|
{"951-0", "951-1"}, |
||||||
|
{"951-20", "951-54"}, |
||||||
|
{"951-550", "951-889"}, |
||||||
|
{"951-8900", "951-9499"}, |
||||||
|
{"951-95000", "951-99999"}, |
||||||
|
{"952-00", "952-19"}, |
||||||
|
{"952-200", "952-499"}, |
||||||
|
{"952-5000", "952-5999"}, |
||||||
|
{"952-60", "952-65"}, |
||||||
|
{"952-6600", "952-6699"}, |
||||||
|
{"952-67000", "952-69999"}, |
||||||
|
{"952-7000", "952-7999"}, |
||||||
|
{"952-89", "952-94"}, |
||||||
|
{"952-9500", "952-9899"}, |
||||||
|
{"952-99000", "952-99999"}, |
||||||
|
{"953-0", "953-0"}, |
||||||
|
{"953-10", "953-14"}, |
||||||
|
{"953-150", "953-599"}, |
||||||
|
{"953-6000", "953-9499"}, |
||||||
|
{"953-95000", "953-99999"}, |
||||||
|
{"954-00", "954-29"}, |
||||||
|
{"954-300", "954-799"}, |
||||||
|
{"954-8000", "954-8999"}, |
||||||
|
{"954-90000", "954-92999"}, |
||||||
|
{"954-9300", "954-9999"}, |
||||||
|
{"955-0", "955-0"}, |
||||||
|
{"955-1000", "955-1999"}, |
||||||
|
{"955-20", "955-54"}, |
||||||
|
{"955-550", "955-799"}, |
||||||
|
{"955-8000", "955-9499"}, |
||||||
|
{"955-95000", "955-99999"}, |
||||||
|
{"956-00", "956-19"}, |
||||||
|
{"956-200", "956-699"}, |
||||||
|
{"956-7000", "956-9999"}, |
||||||
|
{"957-00", "957-02"}, |
||||||
|
{"957-0300", "957-0499"}, |
||||||
|
{"957-05", "957-19"}, |
||||||
|
{"957-2000", "957-2099"}, |
||||||
|
{"957-21", "957-27"}, |
||||||
|
{"957-28000", "957-30999"}, |
||||||
|
{"957-31", "957-43"}, |
||||||
|
{"957-440", "957-819"}, |
||||||
|
{"957-8200", "957-9699"}, |
||||||
|
{"957-97000", "957-99999"}, |
||||||
|
{"958-00", "958-59"}, |
||||||
|
{"958-600", "958-799"}, |
||||||
|
{"958-8000", "958-9499"}, |
||||||
|
{"958-95000", "958-99999"}, |
||||||
|
{"959-00", "959-19"}, |
||||||
|
{"959-200", "959-699"}, |
||||||
|
{"959-7000", "959-8499"}, |
||||||
|
{"960-00", "960-19"}, |
||||||
|
{"960-200", "960-659"}, |
||||||
|
{"960-6600", "960-6899"}, |
||||||
|
{"960-690", "960-699"}, |
||||||
|
{"960-7000", "960-8499"}, |
||||||
|
{"960-85000", "960-99999"}, |
||||||
|
{"961-00", "961-19"}, |
||||||
|
{"961-200", "961-599"}, |
||||||
|
{"961-6000", "961-8999"}, |
||||||
|
{"961-90000", "961-94999"}, |
||||||
|
{"962-00", "962-19"}, |
||||||
|
{"962-200", "962-699"}, |
||||||
|
{"962-7000", "962-8499"}, |
||||||
|
{"962-85000", "962-86999"}, |
||||||
|
{"962-8700", "962-8999"}, |
||||||
|
{"962-900", "962-999"}, |
||||||
|
{"963-00", "963-19"}, |
||||||
|
{"963-200", "963-699"}, |
||||||
|
{"963-7000", "963-8499"}, |
||||||
|
{"963-85000", "963-89999"}, |
||||||
|
{"963-9000", "963-9999"}, |
||||||
|
{"964-00", "964-14"}, |
||||||
|
{"964-150", "964-249"}, |
||||||
|
{"964-2500", "964-2999"}, |
||||||
|
{"964-300", "964-549"}, |
||||||
|
{"964-5500", "964-8999"}, |
||||||
|
{"964-90000", "964-96999"}, |
||||||
|
{"964-970", "964-989"}, |
||||||
|
{"964-9900", "964-9999"}, |
||||||
|
{"965-00", "965-19"}, |
||||||
|
{"965-200", "965-599"}, |
||||||
|
{"965-7000", "965-7999"}, |
||||||
|
{"965-90000", "965-99999"}, |
||||||
|
{"966-00", "966-28"}, |
||||||
|
{"966-2900", "966-2999"}, |
||||||
|
{"966-300", "966-699"}, |
||||||
|
{"966-7000", "966-8999"}, |
||||||
|
{"966-90000", "966-99999"}, |
||||||
|
{"967-0", "967-5"}, |
||||||
|
{"967-60", "967-89"}, |
||||||
|
{"967-900", "967-989"}, |
||||||
|
{"967-9900", "967-9989"}, |
||||||
|
{"967-99900", "967-99999"}, |
||||||
|
{"968-01", "968-39"}, |
||||||
|
{"968-400", "968-499"}, |
||||||
|
{"968-5000", "968-7999"}, |
||||||
|
{"968-800", "968-899"}, |
||||||
|
{"968-9000", "968-9999"}, |
||||||
|
{"969-0", "969-1"}, |
||||||
|
{"969-20", "969-39"}, |
||||||
|
{"969-400", "969-799"}, |
||||||
|
{"969-8000", "969-9999"}, |
||||||
|
{"970-01", "970-59"}, |
||||||
|
{"970-600", "970-899"}, |
||||||
|
{"970-9000", "970-9099"}, |
||||||
|
{"970-91000", "970-96999"}, |
||||||
|
{"970-9700", "970-9999"}, |
||||||
|
{"971-000", "971-019"}, |
||||||
|
{"971-02", "971-02"}, |
||||||
|
{"971-0300", "971-0599"}, |
||||||
|
{"971-06", "971-09"}, |
||||||
|
{"971-10", "971-49"}, |
||||||
|
{"971-500", "971-849"}, |
||||||
|
{"971-8500", "971-9099"}, |
||||||
|
{"971-91000", "971-99999"}, |
||||||
|
{"972-0", "972-1"}, |
||||||
|
{"972-20", "972-54"}, |
||||||
|
{"972-550", "972-799"}, |
||||||
|
{"972-8000", "972-9499"}, |
||||||
|
{"972-95000", "972-99999"}, |
||||||
|
{"973-0", "973-0"}, |
||||||
|
{"973-100", "973-199"}, |
||||||
|
{"973-20", "973-54"}, |
||||||
|
{"973-550", "973-759"}, |
||||||
|
{"973-7600", "973-8499"}, |
||||||
|
{"973-85000", "973-88999"}, |
||||||
|
{"973-8900", "973-9499"}, |
||||||
|
{"973-95000", "973-99999"}, |
||||||
|
{"974-00", "974-19"}, |
||||||
|
{"974-200", "974-699"}, |
||||||
|
{"974-7000", "974-8499"}, |
||||||
|
{"974-85000", "974-89999"}, |
||||||
|
{"974-90000", "974-94999"}, |
||||||
|
{"974-9500", "974-9999"}, |
||||||
|
{"975-00000", "975-00999"}, |
||||||
|
{"975-01", "975-24"}, |
||||||
|
{"975-250", "975-599"}, |
||||||
|
{"975-6000", "975-9199"}, |
||||||
|
{"975-92000", "975-98999"}, |
||||||
|
{"975-990", "975-999"}, |
||||||
|
{"976-0", "976-3"}, |
||||||
|
{"976-40", "976-59"}, |
||||||
|
{"976-600", "976-799"}, |
||||||
|
{"976-8000", "976-9499"}, |
||||||
|
{"976-95000", "976-99999"}, |
||||||
|
{"977-00", "977-19"}, |
||||||
|
{"977-200", "977-499"}, |
||||||
|
{"977-5000", "977-6999"}, |
||||||
|
{"977-700", "977-999"}, |
||||||
|
{"978-000", "978-199"}, |
||||||
|
{"978-2000", "978-2999"}, |
||||||
|
{"978-30000", "978-79999"}, |
||||||
|
{"978-8000", "978-8999"}, |
||||||
|
{"978-900", "978-999"}, |
||||||
|
{"979-000", "979-099"}, |
||||||
|
{"979-1000", "979-1499"}, |
||||||
|
{"979-15000", "979-19999"}, |
||||||
|
{"979-20", "979-29"}, |
||||||
|
{"979-3000", "979-3999"}, |
||||||
|
{"979-400", "979-799"}, |
||||||
|
{"979-8000", "979-9499"}, |
||||||
|
{"979-95000", "979-99999"}, |
||||||
|
{"980-00", "980-19"}, |
||||||
|
{"980-200", "980-599"}, |
||||||
|
{"980-6000", "980-9999"}, |
||||||
|
{"981-00", "981-19"}, |
||||||
|
{"981-200", "981-299"}, |
||||||
|
{"981-3000", "981-9999"}, |
||||||
|
{"982-00", "982-09"}, |
||||||
|
{"982-100", "982-699"}, |
||||||
|
{"982-70", "982-89"}, |
||||||
|
{"982-9000", "982-9999"}, |
||||||
|
{"983-00", "983-01"}, |
||||||
|
{"983-020", "983-199"}, |
||||||
|
{"983-2000", "983-3999"}, |
||||||
|
{"983-40000", "983-49999"}, |
||||||
|
{"983-50", "983-79"}, |
||||||
|
{"983-800", "983-899"}, |
||||||
|
{"983-9000", "983-9899"}, |
||||||
|
{"983-99000", "983-99999"}, |
||||||
|
{"984-00", "984-39"}, |
||||||
|
{"984-400", "984-799"}, |
||||||
|
{"984-8000", "984-8999"}, |
||||||
|
{"984-90000", "984-99999"}, |
||||||
|
{"985-00", "985-39"}, |
||||||
|
{"985-400", "985-599"}, |
||||||
|
{"985-6000", "985-8999"}, |
||||||
|
{"985-90000", "985-99999"}, |
||||||
|
{"986-00", "986-11"}, |
||||||
|
{"986-120", "986-559"}, |
||||||
|
{"986-5600", "986-7999"}, |
||||||
|
{"986-80000", "986-99999"}, |
||||||
|
{"987-00", "987-09"}, |
||||||
|
{"987-1000", "987-1999"}, |
||||||
|
{"987-20000", "987-29999"}, |
||||||
|
{"987-30", "987-49"}, |
||||||
|
{"987-500", "987-899"}, |
||||||
|
{"987-9000", "987-9499"}, |
||||||
|
{"987-95000", "987-99999"}, |
||||||
|
{"988-00", "988-19"}, |
||||||
|
{"988-200", "988-799"}, |
||||||
|
{"988-8000", "988-9699"}, |
||||||
|
{"988-97000", "988-99999"}, |
||||||
|
{"989-0", "989-1"}, |
||||||
|
{"989-20", "989-54"}, |
||||||
|
{"989-550", "989-799"}, |
||||||
|
{"989-8000", "989-9499"}, |
||||||
|
{"989-95000", "989-99999"}, |
||||||
|
{"9944-0", "9944-2"}, |
||||||
|
{"9944-300", "9944-499"}, |
||||||
|
{"9944-5000", "9944-5999"}, |
||||||
|
{"9944-60", "9944-89"}, |
||||||
|
{"9944-900", "9944-999"}, |
||||||
|
{"9945-00", "9945-39"}, |
||||||
|
{"9945-400", "9945-849"}, |
||||||
|
{"9945-8500", "9945-9999"}, |
||||||
|
{"9946-0", "9946-1"}, |
||||||
|
{"9946-20", "9946-39"}, |
||||||
|
{"9946-400", "9946-899"}, |
||||||
|
{"9946-9000", "9946-9999"}, |
||||||
|
{"9947-0", "9947-1"}, |
||||||
|
{"9947-20", "9947-79"}, |
||||||
|
{"9947-800", "9947-999"}, |
||||||
|
{"9948-00", "9948-39"}, |
||||||
|
{"9948-400", "9948-849"}, |
||||||
|
{"9948-8500", "9948-9999"}, |
||||||
|
{"9949-0", "9949-0"}, |
||||||
|
{"9949-10", "9949-39"}, |
||||||
|
{"9949-400", "9949-899"}, |
||||||
|
{"9949-9000", "9949-9999"}, |
||||||
|
{"9950-00", "9950-29"}, |
||||||
|
{"9950-300", "9950-849"}, |
||||||
|
{"9950-8500", "9950-9999"}, |
||||||
|
{"9951-00", "9951-39"}, |
||||||
|
{"9951-400", "9951-849"}, |
||||||
|
{"9951-8500", "9951-9999"}, |
||||||
|
{"9952-0", "9952-1"}, |
||||||
|
{"9952-20", "9952-39"}, |
||||||
|
{"9952-400", "9952-799"}, |
||||||
|
{"9952-8000", "9952-9999"}, |
||||||
|
{"9953-0", "9953-0"}, |
||||||
|
{"9953-10", "9953-39"}, |
||||||
|
{"9953-400", "9953-599"}, |
||||||
|
{"9953-60", "9953-89"}, |
||||||
|
{"9953-9000", "9953-9999"}, |
||||||
|
{"9954-0", "9954-1"}, |
||||||
|
{"9954-20", "9954-39"}, |
||||||
|
{"9954-400", "9954-799"}, |
||||||
|
{"9954-8000", "9954-9999"}, |
||||||
|
{"9955-00", "9955-39"}, |
||||||
|
{"9955-400", "9955-929"}, |
||||||
|
{"9955-9300", "9955-9999"}, |
||||||
|
{"9956-0", "9956-0"}, |
||||||
|
{"9956-10", "9956-39"}, |
||||||
|
{"9956-400", "9956-899"}, |
||||||
|
{"9956-9000", "9956-9999"}, |
||||||
|
{"9957-00", "9957-39"}, |
||||||
|
{"9957-400", "9957-849"}, |
||||||
|
{"9957-8500", "9957-9999"}, |
||||||
|
{"9958-0", "9958-0"}, |
||||||
|
{"9958-10", "9958-49"}, |
||||||
|
{"9958-500", "9958-899"}, |
||||||
|
{"9958-9000", "9958-9999"}, |
||||||
|
{"9959-0", "9959-1"}, |
||||||
|
{"9959-20", "9959-79"}, |
||||||
|
{"9959-800", "9959-949"}, |
||||||
|
{"9959-9500", "9959-9999"}, |
||||||
|
{"9960-00", "9960-59"}, |
||||||
|
{"9960-600", "9960-899"}, |
||||||
|
{"9960-9000", "9960-9999"}, |
||||||
|
{"9961-0", "9961-2"}, |
||||||
|
{"9961-30", "9961-69"}, |
||||||
|
{"9961-700", "9961-949"}, |
||||||
|
{"9961-9500", "9961-9999"}, |
||||||
|
{"9962-00", "9962-54"}, |
||||||
|
{"9962-5500", "9962-5599"}, |
||||||
|
{"9962-56", "9962-59"}, |
||||||
|
{"9962-600", "9962-849"}, |
||||||
|
{"9962-8500", "9962-9999"}, |
||||||
|
{"9963-0", "9963-2"}, |
||||||
|
{"9963-30", "9963-54"}, |
||||||
|
{"9963-550", "9963-749"}, |
||||||
|
{"9963-7500", "9963-9999"}, |
||||||
|
{"9964-0", "9964-6"}, |
||||||
|
{"9964-70", "9964-94"}, |
||||||
|
{"9964-950", "9964-999"}, |
||||||
|
{"9965-00", "9965-39"}, |
||||||
|
{"9965-400", "9965-899"}, |
||||||
|
{"9965-9000", "9965-9999"}, |
||||||
|
{"9966-00", "9966-69"}, |
||||||
|
{"9966-7000", "9966-7499"}, |
||||||
|
{"9966-750", "9966-959"}, |
||||||
|
{"9966-9600", "9966-9999"}, |
||||||
|
{"9967-00", "9967-39"}, |
||||||
|
{"9967-400", "9967-899"}, |
||||||
|
{"9967-9000", "9967-9999"}, |
||||||
|
{"9968-00", "9968-49"}, |
||||||
|
{"9968-500", "9968-939"}, |
||||||
|
{"9968-9400", "9968-9999"}, |
||||||
|
{"9970-00", "9970-39"}, |
||||||
|
{"9970-400", "9970-899"}, |
||||||
|
{"9970-9000", "9970-9999"}, |
||||||
|
{"9971-0", "9971-5"}, |
||||||
|
{"9971-60", "9971-89"}, |
||||||
|
{"9971-900", "9971-989"}, |
||||||
|
{"9971-9900", "9971-9999"}, |
||||||
|
{"9972-00", "9972-09"}, |
||||||
|
{"9972-1", "9972-1"}, |
||||||
|
{"9972-200", "9972-249"}, |
||||||
|
{"9972-2500", "9972-2999"}, |
||||||
|
{"9972-30", "9972-59"}, |
||||||
|
{"9972-600", "9972-899"}, |
||||||
|
{"9972-9000", "9972-9999"}, |
||||||
|
{"9973-0", "9973-0"}, |
||||||
|
{"9973-10", "9973-69"}, |
||||||
|
{"9973-700", "9973-969"}, |
||||||
|
{"9973-9700", "9973-9999"}, |
||||||
|
{"9974-0", "9974-2"}, |
||||||
|
{"9974-30", "9974-54"}, |
||||||
|
{"9974-550", "9974-749"}, |
||||||
|
{"9974-7500", "9974-9499"}, |
||||||
|
{"9974-95", "9974-99"}, |
||||||
|
{"9975-0", "9975-0"}, |
||||||
|
{"9975-100", "9975-399"}, |
||||||
|
{"9975-4000", "9975-4499"}, |
||||||
|
{"9975-45", "9975-89"}, |
||||||
|
{"9975-900", "9975-949"}, |
||||||
|
{"9975-9500", "9975-9999"}, |
||||||
|
{"9976-0", "9976-5"}, |
||||||
|
{"9976-60", "9976-89"}, |
||||||
|
{"9976-900", "9976-989"}, |
||||||
|
{"9976-9990", "9976-9999"}, |
||||||
|
{"9977-00", "9977-89"}, |
||||||
|
{"9977-900", "9977-989"}, |
||||||
|
{"9977-9900", "9977-9999"}, |
||||||
|
{"9978-00", "9978-29"}, |
||||||
|
{"9978-300", "9978-399"}, |
||||||
|
{"9978-40", "9978-94"}, |
||||||
|
{"9978-950", "9978-989"}, |
||||||
|
{"9978-9900", "9978-9999"}, |
||||||
|
{"9979-0", "9979-4"}, |
||||||
|
{"9979-50", "9979-75"}, |
||||||
|
{"9979-760", "9979-899"}, |
||||||
|
{"9979-9000", "9979-9999"}, |
||||||
|
{"9980-0", "9980-3"}, |
||||||
|
{"9980-40", "9980-89"}, |
||||||
|
{"9980-900", "9980-989"}, |
||||||
|
{"9980-9900", "9980-9999"}, |
||||||
|
{"9981-00", "9981-09"}, |
||||||
|
{"9981-100", "9981-159"}, |
||||||
|
{"9981-1600", "9981-1999"}, |
||||||
|
{"9981-20", "9981-79"}, |
||||||
|
{"9981-800", "9981-949"}, |
||||||
|
{"9981-9500", "9981-9999"}, |
||||||
|
{"9982-00", "9982-79"}, |
||||||
|
{"9982-800", "9982-989"}, |
||||||
|
{"9982-9900", "9982-9999"}, |
||||||
|
{"9983-80", "9983-94"}, |
||||||
|
{"9983-950", "9983-989"}, |
||||||
|
{"9983-9900", "9983-9999"}, |
||||||
|
{"9984-00", "9984-49"}, |
||||||
|
{"9984-500", "9984-899"}, |
||||||
|
{"9984-9000", "9984-9999"}, |
||||||
|
{"9985-0", "9985-4"}, |
||||||
|
{"9985-50", "9985-79"}, |
||||||
|
{"9985-800", "9985-899"}, |
||||||
|
{"9985-9000", "9985-9999"}, |
||||||
|
{"9986-00", "9986-39"}, |
||||||
|
{"9986-400", "9986-899"}, |
||||||
|
{"9986-9000", "9986-9399"}, |
||||||
|
{"9986-940", "9986-969"}, |
||||||
|
{"9986-97", "9986-99"}, |
||||||
|
{"9987-00", "9987-39"}, |
||||||
|
{"9987-400", "9987-879"}, |
||||||
|
{"9987-8800", "9987-9999"}, |
||||||
|
{"9988-0", "9988-2"}, |
||||||
|
{"9988-30", "9988-54"}, |
||||||
|
{"9988-550", "9988-749"}, |
||||||
|
{"9988-7500", "9988-9999"}, |
||||||
|
{"9989-0", "9989-0"}, |
||||||
|
{"9989-100", "9989-199"}, |
||||||
|
{"9989-2000", "9989-2999"}, |
||||||
|
{"9989-30", "9989-59"}, |
||||||
|
{"9989-600", "9989-949"}, |
||||||
|
{"9989-9500", "9989-9999"}, |
||||||
|
{"99901-00", "99901-49"}, |
||||||
|
{"99901-500", "99901-799"}, |
||||||
|
{"99901-80", "99901-99"}, |
||||||
|
{"99903-0", "99903-1"}, |
||||||
|
{"99903-20", "99903-89"}, |
||||||
|
{"99903-900", "99903-999"}, |
||||||
|
{"99904-0", "99904-5"}, |
||||||
|
{"99904-60", "99904-89"}, |
||||||
|
{"99904-900", "99904-999"}, |
||||||
|
{"99905-0", "99905-3"}, |
||||||
|
{"99905-40", "99905-79"}, |
||||||
|
{"99905-800", "99905-999"}, |
||||||
|
{"99906-0", "99906-2"}, |
||||||
|
{"99906-30", "99906-59"}, |
||||||
|
{"99906-600", "99906-699"}, |
||||||
|
{"99906-70", "99906-89"}, |
||||||
|
{"99906-9", "99906-9"}, |
||||||
|
{"99908-0", "99908-0"}, |
||||||
|
{"99908-10", "99908-89"}, |
||||||
|
{"99908-900", "99908-999"}, |
||||||
|
{"99909-0", "99909-3"}, |
||||||
|
{"99909-40", "99909-94"}, |
||||||
|
{"99909-950", "99909-999"}, |
||||||
|
{"99910-0", "99910-2"}, |
||||||
|
{"99910-30", "99910-89"}, |
||||||
|
{"99910-900", "99910-999"}, |
||||||
|
{"99911-00", "99911-59"}, |
||||||
|
{"99911-600", "99911-999"}, |
||||||
|
{"99912-0", "99912-3"}, |
||||||
|
{"99912-400", "99912-599"}, |
||||||
|
{"99912-60", "99912-89"}, |
||||||
|
{"99912-900", "99912-999"}, |
||||||
|
{"99913-0", "99913-2"}, |
||||||
|
{"99913-30", "99913-35"}, |
||||||
|
{"99913-600", "99913-604"}, |
||||||
|
{"99914-0", "99914-4"}, |
||||||
|
{"99914-50", "99914-89"}, |
||||||
|
{"99914-900", "99914-949"}, |
||||||
|
{"99915-0", "99915-4"}, |
||||||
|
{"99915-50", "99915-79"}, |
||||||
|
{"99915-800", "99915-999"}, |
||||||
|
{"99916-0", "99916-2"}, |
||||||
|
{"99916-30", "99916-69"}, |
||||||
|
{"99916-700", "99916-999"}, |
||||||
|
{"99917-0", "99917-2"}, |
||||||
|
{"99917-30", "99917-89"}, |
||||||
|
{"99917-900", "99917-999"}, |
||||||
|
{"99918-0", "99918-3"}, |
||||||
|
{"99918-40", "99918-79"}, |
||||||
|
{"99918-800", "99918-999"}, |
||||||
|
{"99919-0", "99919-2"}, |
||||||
|
{"99919-40", "99919-69"}, |
||||||
|
{"99919-900", "99919-999"}, |
||||||
|
{"99920-0", "99920-4"}, |
||||||
|
{"99920-50", "99920-89"}, |
||||||
|
{"99920-900", "99920-999"}, |
||||||
|
{"99921-0", "99921-1"}, |
||||||
|
{"99921-20", "99921-69"}, |
||||||
|
{"99921-700", "99921-799"}, |
||||||
|
{"99921-8", "99921-8"}, |
||||||
|
{"99921-90", "99921-99"}, |
||||||
|
{"99922-0", "99922-3"}, |
||||||
|
{"99922-40", "99922-69"}, |
||||||
|
{"99922-700", "99922-999"}, |
||||||
|
{"99923-0", "99923-1"}, |
||||||
|
{"99923-20", "99923-79"}, |
||||||
|
{"99923-800", "99923-999"}, |
||||||
|
{"99924-0", "99924-2"}, |
||||||
|
{"99924-30", "99924-79"}, |
||||||
|
{"99924-800", "99924-999"}, |
||||||
|
{"99925-0", "99925-3"}, |
||||||
|
{"99925-40", "99925-79"}, |
||||||
|
{"99925-800", "99925-999"}, |
||||||
|
{"99926-0", "99926-0"}, |
||||||
|
{"99926-10", "99926-59"}, |
||||||
|
{"99926-600", "99926-999"}, |
||||||
|
{"99927-0", "99927-2"}, |
||||||
|
{"99927-30", "99927-59"}, |
||||||
|
{"99927-600", "99927-999"}, |
||||||
|
{"99928-0", "99928-0"}, |
||||||
|
{"99928-10", "99928-79"}, |
||||||
|
{"99928-800", "99928-999"}, |
||||||
|
{"99929-0", "99929-4"}, |
||||||
|
{"99929-50", "99929-79"}, |
||||||
|
{"99929-800", "99929-999"}, |
||||||
|
{"99930-0", "99930-4"}, |
||||||
|
{"99930-50", "99930-79"}, |
||||||
|
{"99930-800", "99930-999"}, |
||||||
|
{"99931-0", "99931-4"}, |
||||||
|
{"99931-50", "99931-79"}, |
||||||
|
{"99931-800", "99931-999"}, |
||||||
|
{"99932-0", "99932-0"}, |
||||||
|
{"99932-10", "99932-59"}, |
||||||
|
{"99932-600", "99932-699"}, |
||||||
|
{"99932-7", "99932-7"}, |
||||||
|
{"99932-80", "99932-99"}, |
||||||
|
{"99933-0", "99933-2"}, |
||||||
|
{"99933-30", "99933-59"}, |
||||||
|
{"99933-600", "99933-999"}, |
||||||
|
{"99934-0", "99934-1"}, |
||||||
|
{"99934-20", "99934-79"}, |
||||||
|
{"99934-800", "99934-999"}, |
||||||
|
{"99935-0", "99935-2"}, |
||||||
|
{"99935-30", "99935-59"}, |
||||||
|
{"99935-600", "99935-799"}, |
||||||
|
{"99935-8", "99935-8"}, |
||||||
|
{"99935-90", "99935-99"}, |
||||||
|
{"99936-0", "99936-0"}, |
||||||
|
{"99936-10", "99936-59"}, |
||||||
|
{"99936-600", "99936-999"}, |
||||||
|
{"99937-0", "99937-1"}, |
||||||
|
{"99937-20", "99937-59"}, |
||||||
|
{"99937-600", "99937-999"}, |
||||||
|
{"99938-0", "99938-1"}, |
||||||
|
{"99938-20", "99938-59"}, |
||||||
|
{"99938-600", "99938-899"}, |
||||||
|
{"99938-90", "99938-99"}, |
||||||
|
{"99939-0", "99939-5"}, |
||||||
|
{"99939-60", "99939-89"}, |
||||||
|
{"99939-900", "99939-999"}, |
||||||
|
{"99940-0", "99940-0"}, |
||||||
|
{"99940-10", "99940-69"}, |
||||||
|
{"99940-700", "99940-999"}, |
||||||
|
{"99941-0", "99941-2"}, |
||||||
|
{"99941-30", "99941-89"}, |
||||||
|
{"99941-900", "99941-999"}, |
||||||
|
{"99942-0", "99942-4"}, |
||||||
|
{"99942-50", "99942-79"}, |
||||||
|
{"99942-800", "99942-999"}, |
||||||
|
{"99943-0", "99943-2"}, |
||||||
|
{"99943-30", "99943-59"}, |
||||||
|
{"99943-600", "99943-999"}, |
||||||
|
{"99944-0", "99944-4"}, |
||||||
|
{"99944-50", "99944-79"}, |
||||||
|
{"99944-800", "99944-999"}, |
||||||
|
{"99945-0", "99945-5"}, |
||||||
|
{"99945-60", "99945-89"}, |
||||||
|
{"99945-900", "99945-999"}, |
||||||
|
{"99946-0", "99946-2"}, |
||||||
|
{"99946-30", "99946-59"}, |
||||||
|
{"99946-600", "99946-999"}, |
||||||
|
{"99947-0", "99947-2"}, |
||||||
|
{"99947-30", "99947-69"}, |
||||||
|
{"99947-700", "99947-999"}, |
||||||
|
{"99948-0", "99948-4"}, |
||||||
|
{"99948-50", "99948-79"}, |
||||||
|
{"99948-800", "99948-999"}, |
||||||
|
{"99949-0", "99949-1"}, |
||||||
|
{"99949-20", "99949-89"}, |
||||||
|
{"99949-900", "99949-999"}, |
||||||
|
{"99950-0", "99950-4"}, |
||||||
|
{"99950-50", "99950-79"}, |
||||||
|
{"99950-800", "99950-999"}, |
||||||
|
{"99951-00", "99951-99"}, |
||||||
|
{"99952-0", "99952-4"}, |
||||||
|
{"99952-50", "99952-79"}, |
||||||
|
{"99952-800", "99952-999"}, |
||||||
|
{"99953-0", "99953-2"}, |
||||||
|
{"99953-30", "99953-79"}, |
||||||
|
{"99953-800", "99953-999"}, |
||||||
|
{"99954-0", "99954-2"}, |
||||||
|
{"99954-30", "99954-69"}, |
||||||
|
{"99954-700", "99954-999"}, |
||||||
|
{NULL, NULL}, |
||||||
|
}; |
@ -0,0 +1,52 @@ |
|||||||
|
/*
|
||||||
|
* ISMN.h |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* Information recompiled by Kronuz on November 12, 2004 |
||||||
|
* http://www.ismn-international.org
|
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/ISMN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
* M-3452-4680-5 <=> (0)-3452-4680-5 <=> 0345246805 <=> 9790345246805 <=> 979-0-3452-4680-5 |
||||||
|
* |
||||||
|
* (M counts as 3) |
||||||
|
* ISMN M 3 4 5 2 4 6 8 0 |
||||||
|
* Weight 3 1 3 1 3 1 3 1 3 |
||||||
|
* Product 9 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 65 |
||||||
|
* 65 / 10 = 6 remainder 5 |
||||||
|
* Check digit 10 - 5 = 5
|
||||||
|
* => M-3452-4680-5 |
||||||
|
* |
||||||
|
* ISMN 9 7 9 0 3 4 5 2 4 6 8 0 |
||||||
|
* Weight 1 3 1 3 1 3 1 3 1 3 1 3 |
||||||
|
* Product 9 + 21 + 9 + 0 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 95 |
||||||
|
* 95 / 10 = 9 remainder 5 |
||||||
|
* Check digit 10 - 5 = 5
|
||||||
|
* => 979-0-3452-4680-5 |
||||||
|
* |
||||||
|
* Since mod10(9*1 + 7*3 + 9*1 + 0*3) = mod10(M*3) = mod10(3*3) = 9; the check digit remains the same. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/* where the digit set begins, and how many of them are in the table */ |
||||||
|
const unsigned ISMN_index[10][2] = { |
||||||
|
{0, 5}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
{5, 0}, |
||||||
|
}; |
||||||
|
const char *ISMN_range[][2] = { |
||||||
|
{"0-000", "0-099"}, |
||||||
|
{"0-1000", "0-3999"}, |
||||||
|
{"0-40000", "0-69999"}, |
||||||
|
{"0-700000", "0-899999"}, |
||||||
|
{"0-9000000", "0-9999999"}, |
||||||
|
{NULL, NULL} |
||||||
|
}; |
@ -0,0 +1,49 @@ |
|||||||
|
/*
|
||||||
|
* ISSN.h |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* Information recompiled by Kronuz on November 12, 2004 |
||||||
|
* http://www.issn.org/
|
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/ISSN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
* 1144-875X <=> 1144875(X) <=> 1144875 <=> (977)1144875 <=> 9771144875(00) <=> 977114487500(7) <=> 977-1144-875-00-7 |
||||||
|
* |
||||||
|
*
|
||||||
|
* ISSN 1 1 4 4 8 7 5 |
||||||
|
* Weight 8 7 6 5 4 3 2
|
||||||
|
* Product 8 + 7 + 24 + 20 + 32 + 21 + 10 = 122 |
||||||
|
* 122 / 11 = 11 remainder 1 |
||||||
|
* Check digit 11 - 1 = 10 = X |
||||||
|
* => 1144-875X |
||||||
|
*
|
||||||
|
* ISSN 9 7 7 1 1 4 4 8 7 5 0 0 |
||||||
|
* Weight 1 3 1 3 1 3 1 3 1 3 1 3 |
||||||
|
* Product 9 + 21 + 7 + 3 + 1 + 12 + 4 + 24 + 7 + 15 + 0 + 0 = 103 |
||||||
|
* 103 / 10 = 10 remainder 3 |
||||||
|
* Check digit 10 - 3 = 7 |
||||||
|
* => 977-1144875-00-7 ?? <- suplemental number (number of the week, month, etc.) |
||||||
|
* ^^ 00 for non-daily publications (01=Monday, 02=Tuesday, ...) |
||||||
|
* |
||||||
|
* The hyphenation is always in after the four digits of the ISSN code. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/* where the digit set begins, and how many of them are in the table */ |
||||||
|
const unsigned ISSN_index[10][2] = { |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
{0, 1}, |
||||||
|
}; |
||||||
|
const char *ISSN_range[][2] = { |
||||||
|
{"0000-000", "9999-999"}, |
||||||
|
{NULL, NULL} |
||||||
|
}; |
@ -0,0 +1,16 @@ |
|||||||
|
# $PostgreSQL: pgsql/contrib/isn/Makefile,v 1.1 2006/09/09 04:07:52 tgl Exp $
|
||||||
|
|
||||||
|
MODULES = isn
|
||||||
|
DATA_built = isn.sql
|
||||||
|
DATA = uninstall_isn.sql
|
||||||
|
DOCS = README.isn
|
||||||
|
|
||||||
|
ifdef USE_PGXS |
||||||
|
PGXS = $(shell pg_config --pgxs)
|
||||||
|
include $(PGXS) |
||||||
|
else |
||||||
|
subdir = contrib/isn
|
||||||
|
top_builddir = ../..
|
||||||
|
include $(top_builddir)/src/Makefile.global |
||||||
|
include $(top_srcdir)/contrib/contrib-global.mk |
||||||
|
endif |
@ -0,0 +1,217 @@ |
|||||||
|
|
||||||
|
EAN13 - UPC - ISBN (books) - ISMN (music) - ISSN (serials) |
||||||
|
---------------------------------------------------------- |
||||||
|
|
||||||
|
Copyright Germán Méndez Bravo (Kronuz), 2004 - 2006 |
||||||
|
This module is released under the same BSD license as the rest of PostgreSQL. |
||||||
|
|
||||||
|
The information to implement this module was collected through |
||||||
|
several sites, including: |
||||||
|
http://www.isbn-international.org/ |
||||||
|
http://www.issn.org/ |
||||||
|
http://www.ismn-international.org/ |
||||||
|
http://www.wikipedia.org/ |
||||||
|
the prefixes used for hyphenation where also compiled from: |
||||||
|
http://www.gs1.org/productssolutions/idkeys/support/prefix_list.html |
||||||
|
http://www.isbn-international.org/en/identifiers.html |
||||||
|
http://www.ismn-international.org/ranges.html |
||||||
|
Care was taken during the creation of the algorithms and they |
||||||
|
were meticulously verified against the suggested algorithms |
||||||
|
in the official ISBN, ISMN, ISSN User Manuals. |
||||||
|
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||||
|
THIS MODULE IS PROVIDED "AS IS" AND WITHOUT ANY WARRANTY |
||||||
|
OF ANY KIND, EXPRESS OR IMPLIED. |
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||||
|
|
||||||
|
Content of the Module |
||||||
|
------------------------------------------------- |
||||||
|
|
||||||
|
This directory contains definitions for a few PostgreSQL |
||||||
|
data types, for the following international-standard namespaces: |
||||||
|
EAN13, UPC, ISBN (books), ISMN (music), and ISSN (serials). This module |
||||||
|
is inspired by Garrett A. Wollman's isbn_issn code. |
||||||
|
|
||||||
|
I wanted the database to fully validate numbers and also to use the |
||||||
|
upcoming ISBN-13 and the EAN13 standards, as well as to have it |
||||||
|
automatically doing hyphenations for ISBN numbers. |
||||||
|
|
||||||
|
This new module validates, and automatically adds the correct |
||||||
|
hyphenations to the numbers. Also, it supports the new ISBN-13 |
||||||
|
numbers to be used starting in January 2007. |
||||||
|
|
||||||
|
Premises: |
||||||
|
1. ISBN13, ISMN13, ISSN13 numbers are all EAN13 numbers |
||||||
|
2. EAN13 numbers aren't always ISBN13, ISMN13 or ISSN13 (some are) |
||||||
|
3. some ISBN13 numbers can be displayed as ISBN |
||||||
|
4. some ISMN13 numbers can be displayed as ISMN |
||||||
|
5. some ISSN13 numbers can be displayed as ISSN |
||||||
|
6. all UPC, ISBN, ISMN and ISSN can be represented as EAN13 numbers |
||||||
|
|
||||||
|
Note: All types are internally represented as 64 bit integers, |
||||||
|
and internally all are consistently interchangeable. |
||||||
|
|
||||||
|
We have the following data types: |
||||||
|
|
||||||
|
+ EAN13 for European Article Numbers. |
||||||
|
This type will always show the EAN13-display format. |
||||||
|
Te output function for this is -> ean13_out() |
||||||
|
|
||||||
|
+ ISBN13 for International Standard Book Numbers to be displayed in |
||||||
|
the new EAN13-display format. |
||||||
|
+ ISMN13 for International Standard Music Numbers to be displayed in |
||||||
|
the new EAN13-display format. |
||||||
|
+ ISSN13 for International Standard Serial Numbers to be displayed |
||||||
|
in the new EAN13-display format. |
||||||
|
These types will always display the long version of the ISxN (EAN13) |
||||||
|
The output function to do this is -> ean13_out() |
||||||
|
* The need for these types is just for displaying in different |
||||||
|
ways the same data: |
||||||
|
ISBN13 is actually the same as ISBN, ISMN13=ISMN and ISSN13=ISSN. |
||||||
|
|
||||||
|
+ ISBN for International Standard Book Numbers to be displayed in |
||||||
|
the current short-display format. |
||||||
|
+ ISMN for International Standard Music Numbers to be displayed in |
||||||
|
the current short-display format. |
||||||
|
+ ISSN for International Standard Serial Numbers to be displayed |
||||||
|
in the current short-display format. |
||||||
|
These types will display the short version of the ISxN (ISxN 10) |
||||||
|
whenever it's possible, and it will show ISxN 13 when it's |
||||||
|
impossible to show the short version. |
||||||
|
The output function to do this is -> isn_out() |
||||||
|
|
||||||
|
+ UPC for Universal Product Codes. |
||||||
|
UPC numbers are a subset of the EAN13 numbers (they are basically |
||||||
|
EAN13 without the first '0' digit.) |
||||||
|
The output function to do this is also -> isn_out() |
||||||
|
|
||||||
|
We have the following input functions: |
||||||
|
+ To take a string and return an EAN13 -> ean13_in() |
||||||
|
+ To take a string and return valid ISBN or ISBN13 numbers -> isbn_in() |
||||||
|
+ To take a string and return valid ISMN or ISMN13 numbers -> ismn_in() |
||||||
|
+ To take a string and return valid ISSN or ISSN13 numbers -> issn_in() |
||||||
|
+ To take a string and return an UPC codes -> upc_in() |
||||||
|
|
||||||
|
We are able to cast from: |
||||||
|
+ ISBN13 -> EAN13 |
||||||
|
+ ISMN13 -> EAN13 |
||||||
|
+ ISSN13 -> EAN13 |
||||||
|
|
||||||
|
+ ISBN -> EAN13 |
||||||
|
+ ISMN -> EAN13 |
||||||
|
+ ISSN -> EAN13 |
||||||
|
+ UPC -> EAN13 |
||||||
|
|
||||||
|
+ ISBN <-> ISBN13 |
||||||
|
+ ISMN <-> ISMN13 |
||||||
|
+ ISSN <-> ISSN13 |
||||||
|
|
||||||
|
We have two operator classes (for btree and for hash) so each data type |
||||||
|
can be indexed for faster access. |
||||||
|
|
||||||
|
The C API is implemented as: |
||||||
|
extern Datum isn_out(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ean13_out(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ean13_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum isbn_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ismn_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum issn_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum upc_in(PG_FUNCTION_ARGS); |
||||||
|
|
||||||
|
On success: |
||||||
|
+ isn_out() takes any of our types and returns a string containing |
||||||
|
the shortes possible representation of the number. |
||||||
|
|
||||||
|
+ ean13_out() takes any of our types and returns the |
||||||
|
EAN13 (long) representation of the number. |
||||||
|
|
||||||
|
+ ean13_in() takes a string and return a EAN13. Which, as stated in (2) |
||||||
|
could or could not be any of our types, but it certainly is an EAN13 |
||||||
|
number. Only if the string is a valid EAN13 number, otherwise it fails. |
||||||
|
|
||||||
|
+ isbn_in() takes a string and return an ISBN/ISBN13. Only if the string |
||||||
|
is really a ISBN/ISBN13, otherwise it fails. |
||||||
|
|
||||||
|
+ ismn_in() takes a string and return an ISMN/ISMN13. Only if the string |
||||||
|
is really a ISMN/ISMN13, otherwise it fails. |
||||||
|
|
||||||
|
+ issn_in() takes a string and return an ISSN/ISSN13. Only if the string |
||||||
|
is really a ISSN/ISSN13, otherwise it fails. |
||||||
|
|
||||||
|
+ upc_in() takes a string and return an UPC. Only if the string is |
||||||
|
really a UPC, otherwise it fails. |
||||||
|
|
||||||
|
(on failure, the functions 'ereport' the error) |
||||||
|
|
||||||
|
Testing/Playing Functions |
||||||
|
------------------------------------------------- |
||||||
|
isn_weak(boolean) - Sets the weak input mode. |
||||||
|
This function is intended for testing use only! |
||||||
|
isn_weak() gets the current status of the weak mode. |
||||||
|
|
||||||
|
"Weak" mode is used to be able to insert "invalid" data to a table. |
||||||
|
"Invalid" as in the check digit being wrong, not missing numbers. |
||||||
|
|
||||||
|
Why would you want to use the weak mode? well, it could be that |
||||||
|
you have a huge collection of ISBN numbers, and that there are so many of |
||||||
|
them that for weird reasons some have the wrong check digit (perhaps the |
||||||
|
numbers where scanned from a printed list and the OCR got the numbers wrong, |
||||||
|
perhaps the numbers were manually captured... who knows.) Anyway, the thing |
||||||
|
is you might want to clean the mess up, but you still want to be able to have |
||||||
|
all the numbers in your database and maybe use an external tool to access |
||||||
|
the invalid numbers in the database so you can verify the information and |
||||||
|
validate it more easily; as selecting all the invalid numbers in the table. |
||||||
|
|
||||||
|
When you insert invalid numbers in a table using the weak mode, the number |
||||||
|
will be inserted with the corrected check digit, but it will be flagged |
||||||
|
with an exclamation mark ('!') at the end (i.e. 0-11-000322-5!) |
||||||
|
|
||||||
|
You can also force the insertion of invalid numbers even not in the weak mode, |
||||||
|
appending the '!' character at the end of the number. |
||||||
|
|
||||||
|
To work with invalid numbers, you can use two functions: |
||||||
|
+ make_valid(), which validates an invalid number (deleting the invalid flag) |
||||||
|
+ is_valid(), which checks for the invalid flag presence. |
||||||
|
|
||||||
|
Examples of Use |
||||||
|
------------------------------------------------- |
||||||
|
--Using the types directly: |
||||||
|
select isbn('978-0-393-04002-9'); |
||||||
|
select isbn13('0901690546'); |
||||||
|
select issn('1436-4522'); |
||||||
|
|
||||||
|
--Casting types: |
||||||
|
-- note that you can't cast from ean13 to other type, thus the following |
||||||
|
-- will NOT work: select upc(ean13('0220356483481')); |
||||||
|
select ean13(upc('220356483481')); |
||||||
|
|
||||||
|
--Create a table with a single column to hold ISBN numbers: |
||||||
|
create table test ( id isbn ); |
||||||
|
insert into test values('9780393040029'); |
||||||
|
|
||||||
|
--Automatically calculating check digits (observe the '?'): |
||||||
|
insert into test values('220500896?'); |
||||||
|
insert into test values('978055215372?'); |
||||||
|
|
||||||
|
select issn('3251231?'); |
||||||
|
select ismn('979047213542?'); |
||||||
|
|
||||||
|
--Using the weak mode: |
||||||
|
select isn_weak(true); |
||||||
|
insert into test values('978-0-11-000533-4'); |
||||||
|
insert into test values('9780141219307'); |
||||||
|
insert into test values('2-205-00876-X'); |
||||||
|
select isn_weak(false); |
||||||
|
|
||||||
|
select id from test where not is_valid(id); |
||||||
|
update test set id=make_valid(id) where id = '2-205-00876-X!'; |
||||||
|
|
||||||
|
select * from test; |
||||||
|
|
||||||
|
select isbn13(id) from test; |
||||||
|
|
||||||
|
Contact |
||||||
|
------------------------------------------------- |
||||||
|
Please suggestions or bug reports to kronuz at users.sourceforge.net |
||||||
|
|
||||||
|
Last reviewed on August 23, 2006 by Kronuz. |
@ -0,0 +1,28 @@ |
|||||||
|
/*
|
||||||
|
* ISSN.h |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* No information available for UPC prefixes |
||||||
|
*
|
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/UPC.h,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
/* where the digit set begins, and how many of them are in the table */ |
||||||
|
const unsigned UPC_index[10][2] = { |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
{0, 0}, |
||||||
|
}; |
||||||
|
const char *UPC_range[][2] = { |
||||||
|
{NULL, NULL} |
||||||
|
}; |
@ -0,0 +1,910 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* isn.c |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* Copyright (c) 2004-2006, Germán Méndez Bravo (Kronuz) |
||||||
|
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group |
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/isn.c,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "postgres.h" |
||||||
|
|
||||||
|
#include "fmgr.h" |
||||||
|
#include "utils/builtins.h" |
||||||
|
|
||||||
|
PG_MODULE_MAGIC; |
||||||
|
|
||||||
|
#include "isn.h" |
||||||
|
|
||||||
|
#include "EAN13.h" |
||||||
|
#include "ISBN.h" |
||||||
|
#include "ISMN.h" |
||||||
|
#include "ISSN.h" |
||||||
|
#include "UPC.h" |
||||||
|
|
||||||
|
#define MAXEAN13LEN 18 |
||||||
|
|
||||||
|
enum isn_type { INVALID, ANY, EAN13, ISBN, ISMN, ISSN, UPC }; |
||||||
|
|
||||||
|
static const char *isn_names[] = { "ISN", "ISN", "EAN13", "ISBN", "ISMN", "ISSN", "UPC" }; |
||||||
|
|
||||||
|
static bool g_weak = false; |
||||||
|
static bool g_initialized = false; |
||||||
|
|
||||||
|
/* Macros for converting TEXT to and from c-string */ |
||||||
|
#define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp))) |
||||||
|
#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp))) |
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
** |
||||||
|
** Routines for ISNs. |
||||||
|
** |
||||||
|
** Note: |
||||||
|
** In this code, a normalized string is one that is known to be a valid
|
||||||
|
** ISN number containing only digits and hyphens and with enough space
|
||||||
|
** to hold the full 13 digits plus the maximum of four hyphens. |
||||||
|
***********************************************************************/ |
||||||
|
|
||||||
|
/*----------------------------------------------------------
|
||||||
|
* Debugging routines. |
||||||
|
*---------------------------------------------------------*/ |
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the table and its index is correct (just for debugging) |
||||||
|
*/ |
||||||
|
#ifdef ISN_DEBUG |
||||||
|
static |
||||||
|
bool check_table(const char *(*TABLE)[2], const unsigned TABLE_index[10][2]) |
||||||
|
{ |
||||||
|
const char *aux1, *aux2; |
||||||
|
int a, b, x=0, y=-1, i=0, j, cnt=0, init=0; |
||||||
|
|
||||||
|
if(TABLE == NULL || TABLE_index == NULL) return true; |
||||||
|
|
||||||
|
while(TABLE[i][0] && TABLE[i][1]) { |
||||||
|
aux1 = TABLE[i][0]; |
||||||
|
aux2 = TABLE[i][1]; |
||||||
|
|
||||||
|
/* must always start with a digit: */ |
||||||
|
if(!isdigit(*aux1) || !isdigit(*aux2)) goto invalidtable; |
||||||
|
a = *aux1 - '0'; |
||||||
|
b = *aux2 - '0'; |
||||||
|
|
||||||
|
/* must always have the same format and length: */ |
||||||
|
while(*aux1 && *aux2) { |
||||||
|
if(!(isdigit(*aux1) && isdigit(*aux2)) && (*aux1!=*aux2 || *aux1 != '-'))
|
||||||
|
goto invalidtable; |
||||||
|
aux1++; |
||||||
|
aux2++; |
||||||
|
} |
||||||
|
if(*aux1!=*aux2) goto invalidtable; |
||||||
|
|
||||||
|
/* found a new range */ |
||||||
|
if(a>y) { |
||||||
|
/* check current range in the index: */ |
||||||
|
for(j=x;j<=y;j++) { |
||||||
|
if(TABLE_index[j][0] != init) goto invalidindex; |
||||||
|
if(TABLE_index[j][1] != i-init) goto invalidindex; |
||||||
|
} |
||||||
|
init = i; |
||||||
|
x = a; |
||||||
|
}
|
||||||
|
|
||||||
|
/* Always get the new limit */ |
||||||
|
y = b; |
||||||
|
if(y<x) goto invalidtable; |
||||||
|
i++; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
|
||||||
|
invalidtable: |
||||||
|
elog(DEBUG1, "invalid table near {\"%s\", \"%s\"} (pos: %d)", |
||||||
|
TABLE[i][0], TABLE[i][1], i); |
||||||
|
return false; |
||||||
|
|
||||||
|
invalidindex: |
||||||
|
elog(DEBUG1, "index %d is invalid", j); |
||||||
|
return false; |
||||||
|
} |
||||||
|
#endif /* ISN_DEBUG */ |
||||||
|
|
||||||
|
/*----------------------------------------------------------
|
||||||
|
* Formatting and conversion routines. |
||||||
|
*---------------------------------------------------------*/ |
||||||
|
|
||||||
|
static |
||||||
|
unsigned dehyphenate(char *bufO, char *bufI) |
||||||
|
{ |
||||||
|
unsigned ret = 0; |
||||||
|
while(*bufI) { |
||||||
|
if(isdigit(*bufI)) { |
||||||
|
*bufO++ = *bufI; |
||||||
|
ret++; |
||||||
|
} |
||||||
|
bufI++; |
||||||
|
} |
||||||
|
*bufO = '\0'; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* hyphenate --- Try to hyphenate, in-place, the string starting at bufI
|
||||||
|
* into bufO using the given hyphenation range TABLE. |
||||||
|
* Assumes the input string to be used is of only digits. |
||||||
|
* |
||||||
|
* Returns the number of characters acctually hyphenated. |
||||||
|
*/ |
||||||
|
static |
||||||
|
unsigned hyphenate(char *bufO, char *bufI, const char *(*TABLE)[2], const unsigned TABLE_index[10][2]) |
||||||
|
{ |
||||||
|
unsigned ret = 0; |
||||||
|
const char *ean_aux1, *ean_aux2, *ean_p; |
||||||
|
char *firstdig, *aux1, *aux2; |
||||||
|
unsigned search, upper, lower, step; |
||||||
|
bool ean_in1, ean_in2; |
||||||
|
|
||||||
|
/* just compress the string if no further hyphenation is required */ |
||||||
|
if(TABLE == NULL || TABLE_index == NULL) { |
||||||
|
while(*bufI) { |
||||||
|
*bufO++ = *bufI++; |
||||||
|
ret++; |
||||||
|
} |
||||||
|
*bufO = '\0'; |
||||||
|
return (ret+1); |
||||||
|
} |
||||||
|
|
||||||
|
/* add remaining hyphenations */ |
||||||
|
|
||||||
|
search = *bufI - '0'; |
||||||
|
upper = lower = TABLE_index[search][0]; |
||||||
|
upper += TABLE_index[search][1]; |
||||||
|
lower--; |
||||||
|
|
||||||
|
step = (upper - lower) / 2; |
||||||
|
if(step == 0) return 0; |
||||||
|
search = lower + step; |
||||||
|
|
||||||
|
firstdig = bufI; |
||||||
|
ean_in1 = ean_in2 = false; |
||||||
|
ean_aux1 = TABLE[search][0]; |
||||||
|
ean_aux2 = TABLE[search][1]; |
||||||
|
do { |
||||||
|
if((ean_in1 || *firstdig>=*ean_aux1) && (ean_in2 || *firstdig<=*ean_aux2)) { |
||||||
|
if(*firstdig > *ean_aux1) ean_in1 = true; |
||||||
|
if(*firstdig < *ean_aux2) ean_in2 = true; |
||||||
|
if(ean_in1 && ean_in2) break; |
||||||
|
|
||||||
|
firstdig++, ean_aux1++, ean_aux2++; |
||||||
|
if(!(*ean_aux1 && *ean_aux2 && *firstdig)) break; |
||||||
|
if(!isdigit(*ean_aux1)) ean_aux1++, ean_aux2++; |
||||||
|
} else { |
||||||
|
/* check in what direction we should go and move the pointer accordingly */ |
||||||
|
if(*firstdig < *ean_aux1 && !ean_in1) upper = search; |
||||||
|
else lower = search; |
||||||
|
|
||||||
|
step = (upper - lower) / 2; |
||||||
|
search = lower + step; |
||||||
|
|
||||||
|
/* Initialize stuff again: */ |
||||||
|
firstdig = bufI; |
||||||
|
ean_in1 = ean_in2 = false; |
||||||
|
ean_aux1 = TABLE[search][0]; |
||||||
|
ean_aux2 = TABLE[search][1]; |
||||||
|
} |
||||||
|
} while(step); |
||||||
|
|
||||||
|
if(step) { |
||||||
|
aux1 = bufO; |
||||||
|
aux2 = bufI; |
||||||
|
ean_p = TABLE[search][0]; |
||||||
|
while(*ean_p && *aux2) { |
||||||
|
if(*ean_p++!='-') *aux1++ = *aux2++; |
||||||
|
else *aux1++ = '-'; |
||||||
|
ret++; |
||||||
|
} |
||||||
|
*aux1++='-'; |
||||||
|
*aux1 = *aux2; /* add a lookahead char */ |
||||||
|
return (ret+1); |
||||||
|
} |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* weight_checkdig -- Receives a buffer with a normalized ISN string number,
|
||||||
|
* and the length to weight. |
||||||
|
* |
||||||
|
* Returns the weight of the number (the check digit value, 0-10) |
||||||
|
*/ |
||||||
|
static |
||||||
|
unsigned weight_checkdig(char *isn, unsigned size) |
||||||
|
{ |
||||||
|
unsigned weight = 0; |
||||||
|
while(*isn && size>1) { |
||||||
|
if(isdigit(*isn)) { |
||||||
|
weight += size-- * (*isn - '0'); |
||||||
|
} |
||||||
|
isn++; |
||||||
|
} |
||||||
|
weight = weight % 11; |
||||||
|
if(weight != 0) weight = 11 - weight; |
||||||
|
return weight; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* checkdig --- Receives a buffer with a normalized ISN string number,
|
||||||
|
* and the length to check. |
||||||
|
* |
||||||
|
* Returns the check digit value (0-9) |
||||||
|
*/ |
||||||
|
static |
||||||
|
unsigned checkdig(char *num, unsigned size) |
||||||
|
{ |
||||||
|
unsigned check=0, check3=0; |
||||||
|
unsigned pos = 0; |
||||||
|
if(*num == 'M') { /* ISMN start with 'M' */ |
||||||
|
check3 = 3; |
||||||
|
pos = 1; |
||||||
|
} |
||||||
|
while(*num && size>1) { |
||||||
|
if(isdigit(*num)) { |
||||||
|
if(pos++%2) check3 += *num - '0'; |
||||||
|
else check += *num - '0'; |
||||||
|
size--; |
||||||
|
} |
||||||
|
num++; |
||||||
|
} |
||||||
|
check = (check + 3*check3) % 10; |
||||||
|
if(check != 0) check = 10 - check; |
||||||
|
return check; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* ean2isn --- Convert in-place a normalized EAN13 string to the corresponding
|
||||||
|
* ISN string number. Assumes the input string is normalized. |
||||||
|
*/ |
||||||
|
static inline |
||||||
|
void ean2ISBN(char *isn) |
||||||
|
{ |
||||||
|
char *aux; |
||||||
|
unsigned check; |
||||||
|
/* the number should come in this format: 978-0-000-00000-0 */ |
||||||
|
/* Strip the first part and calculate the new check digit */ |
||||||
|
hyphenate(isn, isn+4, NULL, NULL); |
||||||
|
check = weight_checkdig(isn, 10); |
||||||
|
aux = strchr(isn, '\0'); |
||||||
|
while(!isdigit(*--aux)); |
||||||
|
if(check == 10) *aux = 'X'; |
||||||
|
else *aux = check + '0'; |
||||||
|
} |
||||||
|
static inline |
||||||
|
void ean2ISMN(char *isn) |
||||||
|
{ |
||||||
|
/* the number should come in this format: 979-0-000-00000-0 */ |
||||||
|
/* Just strip the first part and change the first digit ('0') to 'M' */ |
||||||
|
hyphenate(isn, isn+4, NULL, NULL); |
||||||
|
isn[0] = 'M'; |
||||||
|
} |
||||||
|
static inline |
||||||
|
void ean2ISSN(char *isn) |
||||||
|
{ |
||||||
|
unsigned check; |
||||||
|
/* the number should come in this format: 977-0000-000-00-0 */ |
||||||
|
/* Strip the first part, crop, and calculate the new check digit */ |
||||||
|
hyphenate(isn, isn+4, NULL, NULL); |
||||||
|
check = weight_checkdig(isn, 8); |
||||||
|
if(check == 10) isn[8] = 'X'; |
||||||
|
else isn[8] = check + '0'; |
||||||
|
isn[9] = '\0'; |
||||||
|
} |
||||||
|
static inline |
||||||
|
void ean2UPC(char *isn) |
||||||
|
{ |
||||||
|
/* the number should come in this format: 000-000000000-0 */ |
||||||
|
/* Strip the first part, crop, and dehyphenate */ |
||||||
|
dehyphenate(isn, isn+1); |
||||||
|
isn[12] = '\0'; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* ean2* --- Converts a string of digits into an ean13 number. |
||||||
|
* Assumes the input string is a string with only digits
|
||||||
|
* on it, and that it's within the range of ean13. |
||||||
|
* |
||||||
|
* Returns the ean13 value of the string. |
||||||
|
*/ |
||||||
|
static |
||||||
|
ean13 str2ean(const char *num)
|
||||||
|
{ |
||||||
|
ean13 ean = 0; /* current ean */ |
||||||
|
while(*num) { |
||||||
|
ean = 10 * ean + ((*num++) - '0'); |
||||||
|
} |
||||||
|
return (ean<<1); /* also give room to a flag */ |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* ean2string --- Try to convert an ean13 number to an hyphenated string. |
||||||
|
* Assumes there's enough space in result to hold |
||||||
|
* the string (maximum MAXEAN13LEN+1 bytes) |
||||||
|
* This doesn't verify for a valid check digit. |
||||||
|
* |
||||||
|
* If shortType is true, the returned string is in the old ISN short format. |
||||||
|
* If errorOK is false, ereport a useful error message if the string is bad. |
||||||
|
* If errorOK is true, just return "false" for bad input. |
||||||
|
*/ |
||||||
|
static |
||||||
|
bool ean2string(ean13 ean, bool errorOK, char *result, bool shortType) |
||||||
|
{ |
||||||
|
const char *(*TABLE)[2]; |
||||||
|
const unsigned (*TABLE_index)[2]; |
||||||
|
enum isn_type type = INVALID; |
||||||
|
|
||||||
|
char *firstdig, *aux; |
||||||
|
unsigned digval; |
||||||
|
unsigned search; |
||||||
|
char valid = '\0'; /* was the number initially written with a valid check digit? */ |
||||||
|
|
||||||
|
TABLE_index = ISBN_index; |
||||||
|
|
||||||
|
if((ean & 1)!=0) valid = '!'; |
||||||
|
ean >>= 1; |
||||||
|
/* verify it's in the EAN13 range */ |
||||||
|
if(ean > UINT64CONST(9999999999999)) |
||||||
|
goto eantoobig; |
||||||
|
|
||||||
|
/* convert the number */ |
||||||
|
search = 0; |
||||||
|
firstdig = aux = result + MAXEAN13LEN; |
||||||
|
*aux = '\0'; /* terminate string; aux points to last digit */ |
||||||
|
*--aux = valid; /* append '!' for numbers with invalid but corrected check digit */ |
||||||
|
do { |
||||||
|
digval = (unsigned)(ean % 10); /* get the decimal value */
|
||||||
|
ean /= 10; /* get next digit */ |
||||||
|
*--aux = (char)(digval + '0'); /* convert to ascii and store */ |
||||||
|
if(++search == 1) *--aux = '-'; /* the check digit is always there */ |
||||||
|
} while(ean); |
||||||
|
while(search++<13) *--aux = '0'; /* fill the remaining EAN13 with '0' */ |
||||||
|
|
||||||
|
/* The string should be in this form: ???DDDDDDDDDDDD-D" */ |
||||||
|
search = hyphenate(result, result+3, EAN13_range, EAN13_index); |
||||||
|
|
||||||
|
/* verify it's a logically valid EAN13 */ |
||||||
|
if(search == 0) { |
||||||
|
search = hyphenate(result, result+3, NULL, NULL); |
||||||
|
goto okay; |
||||||
|
} |
||||||
|
|
||||||
|
/* find out what type of hyphenation is needed: */ |
||||||
|
if(!strncmp("978-", result, search)) { /* ISBN */ |
||||||
|
/* The string should be in this form: 978-??000000000-0" */ |
||||||
|
type = ISBN; |
||||||
|
TABLE = ISBN_range; |
||||||
|
TABLE_index = ISBN_index; |
||||||
|
} else if(!strncmp("977-", result, search)) { /* ISSN */ |
||||||
|
/* The string should be in this form: 977-??000000000-0" */ |
||||||
|
type = ISSN; |
||||||
|
TABLE = ISSN_range; |
||||||
|
TABLE_index = ISSN_index; |
||||||
|
} else if(!strncmp("979-0", result, search+1)) { /* ISMN */ |
||||||
|
/* The string should be in this form: 979-0?000000000-0" */ |
||||||
|
type = ISMN; |
||||||
|
TABLE = ISMN_range; |
||||||
|
TABLE_index = ISMN_index; |
||||||
|
} else if(*result == '0') { /* UPC */ |
||||||
|
/* The string should be in this form: 000-00000000000-0" */ |
||||||
|
type = UPC; |
||||||
|
TABLE = UPC_range; |
||||||
|
TABLE_index = UPC_index; |
||||||
|
} else { |
||||||
|
type = EAN13; |
||||||
|
TABLE = NULL; |
||||||
|
TABLE_index = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/* verify it's a logically valid EAN13/ISN */ |
||||||
|
digval = search; |
||||||
|
search = hyphenate(result+digval, result+digval+2, TABLE, TABLE_index); |
||||||
|
|
||||||
|
/* verify it's a valid EAN13 */ |
||||||
|
if(search == 0) { |
||||||
|
search = hyphenate(result+digval, result+digval+2, NULL, NULL); |
||||||
|
goto okay; |
||||||
|
} |
||||||
|
|
||||||
|
okay: |
||||||
|
/* convert to the old short type: */ |
||||||
|
if(shortType)
|
||||||
|
switch(type) { |
||||||
|
case ISBN: |
||||||
|
ean2ISBN(result); |
||||||
|
break; |
||||||
|
case ISMN: |
||||||
|
ean2ISMN(result); |
||||||
|
break; |
||||||
|
case ISSN: |
||||||
|
ean2ISSN(result); |
||||||
|
break; |
||||||
|
case UPC: |
||||||
|
ean2UPC(result); |
||||||
|
break; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
return true; |
||||||
|
|
||||||
|
eantoobig: |
||||||
|
if(!errorOK) |
||||||
|
{ |
||||||
|
char eanbuf[64]; |
||||||
|
|
||||||
|
/*
|
||||||
|
* Format the number separately to keep the machine-dependent |
||||||
|
* format code out of the translatable message text |
||||||
|
*/ |
||||||
|
snprintf(eanbuf, sizeof(eanbuf), EAN13_FORMAT, ean); |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
||||||
|
errmsg("value \"%s\" is out of range for ISN type", |
||||||
|
eanbuf))); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* string2ean --- try to parse a string into an ean13. |
||||||
|
* |
||||||
|
* If errorOK is false, ereport a useful error message if the string is bad. |
||||||
|
* If errorOK is true, just return "false" for bad input. |
||||||
|
* |
||||||
|
* if the input string ends with '!' it will always be treated as invalid |
||||||
|
* (even if the check digit is valid) |
||||||
|
*/ |
||||||
|
static |
||||||
|
bool string2ean(const char *str, bool errorOK, ean13 *result, |
||||||
|
enum isn_type accept) |
||||||
|
{ |
||||||
|
bool digit, last; |
||||||
|
char buf[17] = " "; |
||||||
|
char *aux1 = buf + 3; /* leave space for the first part, in case it's needed */ |
||||||
|
const char *aux2 = str; |
||||||
|
enum isn_type type = INVALID; |
||||||
|
unsigned check = 0, rcheck = (unsigned)-1; |
||||||
|
unsigned length = 0; |
||||||
|
bool magic = false, valid = true; |
||||||
|
|
||||||
|
/* recognize and validate the number: */ |
||||||
|
while(*aux2 && length <= 13) { |
||||||
|
last = (*(aux2+1) == '!' || *(aux2+1) == '\0'); /* is the last character */ |
||||||
|
digit = isdigit(*aux2); /* is current character a digit? */ |
||||||
|
if(*aux2=='?' && last) /* automagically calculate check digit if it's '?' */ |
||||||
|
magic = digit = true; |
||||||
|
if(length == 0 && (*aux2=='M' || *aux2=='m')) { |
||||||
|
/* only ISMN can be here */ |
||||||
|
if(type != INVALID) goto eaninvalid; |
||||||
|
type = ISMN; |
||||||
|
*aux1++ = 'M'; |
||||||
|
length++; |
||||||
|
} else if(length == 7 && (digit || *aux2=='X' || *aux2=='x') && last) { |
||||||
|
/* only ISSN can be here */ |
||||||
|
if(type != INVALID) goto eaninvalid; |
||||||
|
type = ISSN; |
||||||
|
*aux1++ = toupper(*aux2); |
||||||
|
length++; |
||||||
|
} else if(length == 9 && (digit || *aux2=='X' || *aux2=='x') && last) { |
||||||
|
/* only ISBN and ISMN can be here */ |
||||||
|
if(type != INVALID && type != ISMN) goto eaninvalid; |
||||||
|
if(type == INVALID) type = ISBN; /* ISMN must start with 'M' */ |
||||||
|
*aux1++ = toupper(*aux2); |
||||||
|
length++; |
||||||
|
} else if(length == 11 && digit && last) { |
||||||
|
/* only UPC can be here */ |
||||||
|
if(type != INVALID) goto eaninvalid; |
||||||
|
type = UPC; |
||||||
|
*aux1++ = *aux2; |
||||||
|
length++; |
||||||
|
} else if(*aux2 == '-' || *aux2 == ' ') { |
||||||
|
/* skip, we could validate but I think it's worthless */ |
||||||
|
} else if(*aux2 == '!' && *(aux2+1) == '\0') { |
||||||
|
/* the invalid check digit sufix was found, set it */ |
||||||
|
if(!magic) valid = false; |
||||||
|
magic = true; |
||||||
|
} else if(!digit) { |
||||||
|
goto eaninvalid; |
||||||
|
} else { |
||||||
|
*aux1++ = *aux2; |
||||||
|
if(++length > 13) goto eantoobig; |
||||||
|
} |
||||||
|
aux2++; |
||||||
|
} |
||||||
|
*aux1 = '\0'; /* terminate the string */ |
||||||
|
|
||||||
|
/* find the current check digit value */ |
||||||
|
if(length == 13) { |
||||||
|
/* only EAN13 can be here */ |
||||||
|
if(type != INVALID) goto eaninvalid; |
||||||
|
type = EAN13; |
||||||
|
check = buf[15]-'0'; |
||||||
|
} else if(length == 12) { |
||||||
|
/* only UPC can be here */ |
||||||
|
if(type != UPC) goto eaninvalid; |
||||||
|
check = buf[14]-'0'; |
||||||
|
} else if(length == 10) { |
||||||
|
if(type != ISBN && type != ISMN) goto eaninvalid; |
||||||
|
if(buf[12] == 'X') check = 10; |
||||||
|
else check = buf[12]-'0'; |
||||||
|
} else if(length == 8) { |
||||||
|
if(type != INVALID && type != ISSN) goto eaninvalid; |
||||||
|
type = ISSN; |
||||||
|
if(buf[10] == 'X') check = 10; |
||||||
|
else check = buf[10]-'0'; |
||||||
|
} else goto eaninvalid; |
||||||
|
|
||||||
|
if(type == INVALID) goto eaninvalid; |
||||||
|
|
||||||
|
/* obtain the real check digit value, validate, and convert to ean13: */
|
||||||
|
if(accept == EAN13 && type != accept) goto eanwrongtype; |
||||||
|
if(accept != ANY && type != EAN13 && type != accept) goto eanwrongtype; |
||||||
|
switch(type) { |
||||||
|
case EAN13: |
||||||
|
valid = (valid && ((rcheck=checkdig(buf+3, 13)) == check || magic)); |
||||||
|
/* now get the subtype of EAN13: */ |
||||||
|
if(buf[3] == '0') type = UPC; |
||||||
|
else if(!strncmp("977", buf+3, 3)) type = ISSN; |
||||||
|
else if(!strncmp("978", buf+3, 3)) type = ISBN; |
||||||
|
else if(!strncmp("9790", buf+3, 4)) type = ISMN; |
||||||
|
else if(!strncmp("979", buf+3, 3)) type = ISBN; |
||||||
|
if(accept != EAN13 && accept != ANY && type != accept) goto eanwrongtype; |
||||||
|
break; |
||||||
|
case ISMN: |
||||||
|
strncpy(buf, "9790", 4); /* this isn't for sure yet, for now ISMN it's only 9790 */ |
||||||
|
valid = (valid && ((rcheck=checkdig(buf+3, 10)) == check || magic)); |
||||||
|
break; |
||||||
|
case ISBN: |
||||||
|
strncpy(buf, "978", 3); |
||||||
|
valid = (valid && ((rcheck=weight_checkdig(buf+3, 10)) == check || magic)); |
||||||
|
break; |
||||||
|
case ISSN: |
||||||
|
strncpy(buf+10, "00", 2); /* append 00 as the normal issue publication code */ |
||||||
|
strncpy(buf, "977", 3); |
||||||
|
valid = (valid && ((rcheck=weight_checkdig(buf+3, 8)) == check || magic)); |
||||||
|
break; |
||||||
|
case UPC: |
||||||
|
buf[2] = '0'; |
||||||
|
valid = (valid && ((rcheck=checkdig(buf+2, 13)) == check || magic)); |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if(!valid && !magic) goto eanbadcheck; |
||||||
|
|
||||||
|
for(aux1 = buf; *aux1 && *aux1 <= ' '; aux1++); |
||||||
|
aux1[12] = checkdig(aux1, 13) + '0'; |
||||||
|
aux1[13] = '\0'; |
||||||
|
|
||||||
|
*result = str2ean(aux1); |
||||||
|
*result |= valid?0:1; |
||||||
|
|
||||||
|
return true; |
||||||
|
|
||||||
|
eanbadcheck:
|
||||||
|
if(!g_weak) { |
||||||
|
if(!errorOK) { |
||||||
|
if(rcheck == (unsigned)-1) { |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
||||||
|
errmsg("invalid %s number: \"%s\"", |
||||||
|
isn_names[accept], str))); |
||||||
|
} else { |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
||||||
|
errmsg("invalid check digit for %s number: \"%s\", should be %c", |
||||||
|
isn_names[accept], str, (rcheck==10)?('X'):(rcheck+'0')))); |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
if(accept != EAN13 && accept != ANY && type != accept) goto eanwrongtype; |
||||||
|
|
||||||
|
/* fix the check digit: */ |
||||||
|
for(aux1 = buf; *aux1 && *aux1 <= ' '; aux1++); |
||||||
|
aux1[12] = checkdig(aux1, 13) + '0'; |
||||||
|
aux1[13] = '\0'; |
||||||
|
*result = str2ean(aux1); |
||||||
|
|
||||||
|
/* set the "invalid-check-digit-on-input" flag */
|
||||||
|
*result |= 1; |
||||||
|
|
||||||
|
/* just warn about the error when there was a real check digit error: */ |
||||||
|
if(check != rcheck) { |
||||||
|
if(rcheck == (unsigned)-1) { |
||||||
|
elog(WARNING, "invalid %s number: \"%s\"", |
||||||
|
isn_names[accept], str); |
||||||
|
} else { |
||||||
|
elog(WARNING, "invalid check digit for %s number: \"%s\", should be %c", |
||||||
|
isn_names[accept], str, (rcheck==10)?('X'):(rcheck+'0')); |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
|
||||||
|
eaninvalid: |
||||||
|
if(!errorOK) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
||||||
|
errmsg("invalid input syntax for %s number: \"%s\"", |
||||||
|
isn_names[accept], str))); |
||||||
|
return false; |
||||||
|
|
||||||
|
eanwrongtype: |
||||||
|
if(!errorOK) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
||||||
|
errmsg("invalid %s type for number: \"%s\"", |
||||||
|
isn_names[accept], str))); |
||||||
|
return false; |
||||||
|
|
||||||
|
eantoobig: |
||||||
|
if(!errorOK) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), |
||||||
|
errmsg("value \"%s\" is out of range for %s type", |
||||||
|
str, isn_names[accept]))); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/*----------------------------------------------------------
|
||||||
|
* Exported routines. |
||||||
|
*---------------------------------------------------------*/ |
||||||
|
|
||||||
|
void initialize(void) |
||||||
|
{ |
||||||
|
#ifdef ISN_DEBUG |
||||||
|
if(!check_table(EAN13, EAN13_index)) |
||||||
|
elog(LOG, "EAN13 failed check"); |
||||||
|
if(!check_table(ISBN, ISBN_index)) |
||||||
|
elog(LOG, "ISBN failed check"); |
||||||
|
if(!check_table(ISMN, ISMN_index)) |
||||||
|
elog(LOG, "ISMN failed check"); |
||||||
|
if(!check_table(ISSN, ISSN_index)) |
||||||
|
elog(LOG, "ISSN failed check"); |
||||||
|
if(!check_table(UPC, UPC_index)) |
||||||
|
elog(LOG, "UPC failed check"); |
||||||
|
#endif |
||||||
|
g_initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
/* isn_out
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(isn_out); |
||||||
|
Datum |
||||||
|
isn_out(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
ean13 val = PG_GETARG_EAN13(0); |
||||||
|
char *result; |
||||||
|
char buf[MAXEAN13LEN + 1]; |
||||||
|
|
||||||
|
(void) ean2string(val, false, buf, true); |
||||||
|
|
||||||
|
result = pstrdup(buf); |
||||||
|
PG_RETURN_CSTRING(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* ean13_out
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(ean13_out); |
||||||
|
Datum |
||||||
|
ean13_out(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
ean13 val = PG_GETARG_EAN13(0); |
||||||
|
char *result; |
||||||
|
char buf[MAXEAN13LEN + 1]; |
||||||
|
|
||||||
|
(void) ean2string(val, false, buf, false); |
||||||
|
|
||||||
|
result = pstrdup(buf); |
||||||
|
PG_RETURN_CSTRING(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* ean13_in
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(ean13_in); |
||||||
|
Datum |
||||||
|
ean13_in(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = PG_GETARG_CSTRING(0); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, EAN13); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* isbn_in
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(isbn_in); |
||||||
|
Datum |
||||||
|
isbn_in(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = PG_GETARG_CSTRING(0); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, ISBN); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* ismn_in
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(ismn_in); |
||||||
|
Datum |
||||||
|
ismn_in(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = PG_GETARG_CSTRING(0); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, ISMN); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* issn_in
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(issn_in); |
||||||
|
Datum |
||||||
|
issn_in(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = PG_GETARG_CSTRING(0); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, ISSN); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* upc_in
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(upc_in); |
||||||
|
Datum |
||||||
|
upc_in(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = PG_GETARG_CSTRING(0); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, UPC); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* casting functions
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(ean13_cast_to_text); |
||||||
|
Datum |
||||||
|
ean13_cast_to_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
ean13 val = PG_GETARG_EAN13(0); |
||||||
|
char buf[MAXEAN13LEN + 1]; |
||||||
|
|
||||||
|
(void) ean2string(val, false, buf, false); |
||||||
|
|
||||||
|
PG_RETURN_TEXT_P(GET_TEXT(buf)); |
||||||
|
} |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(isn_cast_to_text); |
||||||
|
Datum |
||||||
|
isn_cast_to_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
ean13 val = PG_GETARG_EAN13(0); |
||||||
|
char buf[MAXEAN13LEN + 1]; |
||||||
|
|
||||||
|
(void) ean2string(val, false, buf, true); |
||||||
|
|
||||||
|
PG_RETURN_TEXT_P(GET_TEXT(buf)); |
||||||
|
} |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(ean13_cast_from_text); |
||||||
|
Datum |
||||||
|
ean13_cast_from_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = GET_STR(PG_GETARG_TEXT_P(0)); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, EAN13); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(isbn_cast_from_text); |
||||||
|
Datum |
||||||
|
isbn_cast_from_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = GET_STR(PG_GETARG_TEXT_P(0)); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, ISBN); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(ismn_cast_from_text); |
||||||
|
Datum |
||||||
|
ismn_cast_from_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = GET_STR(PG_GETARG_TEXT_P(0)); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, ISMN); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(issn_cast_from_text); |
||||||
|
Datum |
||||||
|
issn_cast_from_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = GET_STR(PG_GETARG_TEXT_P(0)); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, ISSN); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(upc_cast_from_text); |
||||||
|
Datum |
||||||
|
upc_cast_from_text(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
const char *str = GET_STR(PG_GETARG_TEXT_P(0)); |
||||||
|
ean13 result; |
||||||
|
|
||||||
|
(void) string2ean(str, false, &result, UPC); |
||||||
|
PG_RETURN_EAN13(result); |
||||||
|
} |
||||||
|
|
||||||
|
/* is_valid - returns false if the "invalid-check-digit-on-input" is set
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(is_valid); |
||||||
|
Datum |
||||||
|
is_valid(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
ean13 val = PG_GETARG_EAN13(0); |
||||||
|
PG_RETURN_BOOL((val & 1) == 0); |
||||||
|
} |
||||||
|
|
||||||
|
/* make_valid - unsets the "invalid-check-digit-on-input" flag
|
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(make_valid); |
||||||
|
Datum |
||||||
|
make_valid(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
ean13 val = PG_GETARG_EAN13(0); |
||||||
|
val &= ~((ean13) 1); |
||||||
|
PG_RETURN_EAN13(val); |
||||||
|
} |
||||||
|
|
||||||
|
#ifdef ISN_WEAK_MODE |
||||||
|
/* this function temporarily sets weak input flag
|
||||||
|
* (to lose the strictness of check digit acceptance) |
||||||
|
* It's a helper function, not intended to be used!! |
||||||
|
*/ |
||||||
|
PG_FUNCTION_INFO_V1(accept_weak_input); |
||||||
|
Datum |
||||||
|
accept_weak_input(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
g_weak = PG_GETARG_BOOL(0); |
||||||
|
PG_RETURN_BOOL(g_weak); |
||||||
|
} |
||||||
|
#else |
||||||
|
PG_FUNCTION_INFO_V1(accept_weak_input); |
||||||
|
Datum |
||||||
|
accept_weak_input(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
/* function has no effect */ |
||||||
|
PG_RETURN_BOOL(false); |
||||||
|
} |
||||||
|
#endif /* ISN_WEAK_MODE */ |
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(weak_input_status); |
||||||
|
Datum |
||||||
|
weak_input_status(PG_FUNCTION_ARGS) |
||||||
|
{ |
||||||
|
PG_RETURN_BOOL(g_weak); |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* isn.h |
||||||
|
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC) |
||||||
|
* |
||||||
|
* Copyright (c) 2004-2006, Germán Méndez Bravo (Kronuz) |
||||||
|
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group |
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* $PostgreSQL: pgsql/contrib/isn/isn.h,v 1.1 2006/09/09 04:07:52 tgl Exp $ |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef ISN_H |
||||||
|
#define ISN_H |
||||||
|
|
||||||
|
#include "fmgr.h" |
||||||
|
|
||||||
|
#undef ISN_DEBUG |
||||||
|
#define ISN_WEAK_MODE |
||||||
|
|
||||||
|
/*
|
||||||
|
* uint64 is the internal storage format for ISNs. |
||||||
|
*/ |
||||||
|
typedef uint64 ean13; |
||||||
|
|
||||||
|
#define EAN13_FORMAT UINT64_FORMAT |
||||||
|
|
||||||
|
#define PG_GETARG_EAN13(n) PG_GETARG_INT64(n) |
||||||
|
#define PG_RETURN_EAN13(x) PG_RETURN_INT64(x) |
||||||
|
|
||||||
|
extern Datum isn_out(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ean13_out(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ean13_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum isbn_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ismn_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum issn_in(PG_FUNCTION_ARGS); |
||||||
|
extern Datum upc_in(PG_FUNCTION_ARGS); |
||||||
|
|
||||||
|
extern Datum ean13_cast_to_text(PG_FUNCTION_ARGS); |
||||||
|
extern Datum isn_cast_to_text(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ean13_cast_from_text(PG_FUNCTION_ARGS); |
||||||
|
extern Datum isbn_cast_from_text(PG_FUNCTION_ARGS); |
||||||
|
extern Datum ismn_cast_from_text(PG_FUNCTION_ARGS); |
||||||
|
extern Datum issn_cast_from_text(PG_FUNCTION_ARGS); |
||||||
|
extern Datum upc_cast_from_text(PG_FUNCTION_ARGS); |
||||||
|
|
||||||
|
extern Datum is_valid(PG_FUNCTION_ARGS); |
||||||
|
extern Datum make_valid(PG_FUNCTION_ARGS); |
||||||
|
|
||||||
|
extern Datum accept_weak_input(PG_FUNCTION_ARGS); |
||||||
|
extern Datum weak_input_status(PG_FUNCTION_ARGS); |
||||||
|
|
||||||
|
extern void initialize(void); |
||||||
|
|
||||||
|
#endif /* ISN_H */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,18 @@ |
|||||||
|
-- |
||||||
|
-- Drop the actual types (in cascade): |
||||||
|
-- |
||||||
|
--------------------------------------------------- |
||||||
|
SET search_path = public; |
||||||
|
|
||||||
|
DROP TYPE ean13 CASCADE; |
||||||
|
DROP TYPE isbn13 CASCADE; |
||||||
|
DROP TYPE ismn13 CASCADE; |
||||||
|
DROP TYPE issn13 CASCADE; |
||||||
|
DROP TYPE isbn CASCADE; |
||||||
|
DROP TYPE ismn CASCADE; |
||||||
|
DROP TYPE issn CASCADE; |
||||||
|
DROP TYPE upc CASCADE; |
||||||
|
|
||||||
|
DROP FUNCTION isn_weak(); |
||||||
|
DROP FUNCTION isn_weak(boolean); |
||||||
|
|
Loading…
Reference in new issue