mirror of https://github.com/postgres/postgres
parent
efc9a91db9
commit
3fa676a74c
@ -0,0 +1,25 @@ |
||||
#
|
||||
# PostgreSQL types for ISBN and ISSN identifiers.
|
||||
#
|
||||
# $Id: Makefile,v 1.1 1998/08/17 03:35:04 scrappy Exp $
|
||||
|
||||
all: isbn.so issn.so |
||||
|
||||
isbn.so: isbn.o |
||||
ld -Bshareable -o isbn.so isbn.o
|
||||
|
||||
isbn.o: isbn.c |
||||
cc -g -O -fPIC -I/usr/local/pgsql/include -c isbn.c
|
||||
|
||||
issn.so: issn.o |
||||
ld -Bshareable -o issn.so issn.o
|
||||
|
||||
issn.o: issn.c |
||||
cc -g -O -fPIC -I/usr/local/pgsql/include -c issn.c
|
||||
|
||||
install: isbn.so issn.so |
||||
install -c isbn.so issn.so /usr/local/pgsql/modules
|
||||
|
||||
#
|
||||
# eof
|
||||
#
|
||||
@ -0,0 +1,18 @@ |
||||
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 |
||||
@ -0,0 +1,187 @@ |
||||
/*
|
||||
* PostgreSQL type definitions for ISBNs. |
||||
* |
||||
* $Id: isbn.c,v 1.1 1998/08/17 03:35:04 scrappy Exp $ |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <postgres.h> |
||||
#include <utils/palloc.h> |
||||
|
||||
/*
|
||||
* 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; |
||||
char *cp; |
||||
int count; |
||||
|
||||
if (strlen(str) != 13) { |
||||
elog(ERROR, "isbn_in: invalid ISBN \"%s\"", str); |
||||
return (NULL); |
||||
} |
||||
if (isbn_sum(str) != 0) { |
||||
elog(ERROR, "isbn_in: purported ISBN \"%s\" failed checksum", |
||||
str); |
||||
return (NULL); |
||||
} |
||||
|
||||
result = (isbn *) palloc(sizeof(isbn)); |
||||
|
||||
strncpy(result->num, str, 13); |
||||
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)); |
||||
} |
||||
|
||||
/*
|
||||
* eof |
||||
*/ |
||||
@ -0,0 +1,116 @@ |
||||
-- |
||||
-- PostgreSQL code for ISBNs. |
||||
-- |
||||
-- $Id: isbn.sql,v 1.1 1998/08/17 03:35:05 scrappy Exp $ |
||||
-- |
||||
|
||||
load '/usr/local/pgsql/modules/isbn.so'; |
||||
|
||||
-- |
||||
-- Input and output functions and the type itself: |
||||
-- |
||||
|
||||
create function isbn_in(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_out(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create type isbn ( |
||||
internallength = 16, |
||||
externallength = 13, |
||||
input = isbn_in, |
||||
output = isbn_out |
||||
); |
||||
|
||||
-- |
||||
-- The various boolean tests: |
||||
-- |
||||
|
||||
create function isbn_lt(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_le(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_eq(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_ge(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_gt(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
create function isbn_ne(isbn, isbn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/isbn.so' |
||||
language 'c'; |
||||
|
||||
-- |
||||
-- 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 |
||||
); |
||||
|
||||
-- |
||||
-- eof |
||||
-- |
||||
@ -0,0 +1,178 @@ |
||||
/*
|
||||
* PostgreSQL type definitions for ISSNs. |
||||
* |
||||
* $Id: issn.c,v 1.1 1998/08/17 03:35:05 scrappy Exp $ |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
|
||||
#include <postgres.h> |
||||
#include <utils/palloc.h> |
||||
|
||||
/*
|
||||
* 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; |
||||
char *cp; |
||||
int count; |
||||
|
||||
if (strlen(str) != 9) { |
||||
elog(ERROR, "issn_in: invalid ISSN \"%s\"", str); |
||||
return (NULL); |
||||
} |
||||
if (issn_sum(str) != 0) { |
||||
elog(ERROR, "issn_in: purported ISSN \"%s\" failed checksum", |
||||
str); |
||||
return (NULL); |
||||
} |
||||
|
||||
result = (issn *) palloc(sizeof(issn)); |
||||
|
||||
strncpy(result->num, str, 9); |
||||
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)); |
||||
} |
||||
|
||||
/*
|
||||
* eof |
||||
*/ |
||||
@ -0,0 +1,116 @@ |
||||
-- |
||||
-- PostgreSQL code for ISSNs. |
||||
-- |
||||
-- $Id: issn.sql,v 1.1 1998/08/17 03:35:05 scrappy Exp $ |
||||
-- |
||||
|
||||
load '/usr/local/pgsql/modules/issn.so'; |
||||
|
||||
-- |
||||
-- Input and output functions and the type itself: |
||||
-- |
||||
|
||||
create function issn_in(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_out(opaque) |
||||
returns opaque |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create type issn ( |
||||
internallength = 16, |
||||
externallength = 9, |
||||
input = issn_in, |
||||
output = issn_out |
||||
); |
||||
|
||||
-- |
||||
-- The various boolean tests: |
||||
-- |
||||
|
||||
create function issn_lt(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_le(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_eq(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_ge(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_gt(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
create function issn_ne(issn, issn) |
||||
returns bool |
||||
as '/usr/local/pgsql/modules/issn.so' |
||||
language 'c'; |
||||
|
||||
-- |
||||
-- 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 |
||||
); |
||||
|
||||
-- |
||||
-- eof |
||||
-- |
||||
Loading…
Reference in new issue