Commit a377ad58 authored by Marc G. Fournier's avatar Marc G. Fournier

I'm including an update to my user defined IP and MAC address type

implementation that's in contrib/ip_and_mac/.  This one works right
with 6.3, avoids the problems I ran into earlier with LIKE, and
includes a bit of extra functionality.

From: Tom I Helbekkmo <tih@Hamartun.Priv.NO>
parent 9336b9b2
# PostgreSQL type definitions for IP and MAC addresses. #
# PostgreSQL types for IP and MAC addresses
#
# $Id: Makefile,v 1.2 1998/02/14 17:58:02 scrappy Exp $
all: ip.so mac.so all: ip.so mac.so
...@@ -17,4 +20,6 @@ mac.o: mac.c mac.h ...@@ -17,4 +20,6 @@ mac.o: mac.c mac.h
install: ip.so mac.so install: ip.so mac.so
install -c ip.so mac.so /usr/local/pgsql/modules install -c ip.so mac.so /usr/local/pgsql/modules
#
# eof # eof
#
PostgreSQL type extensions for IP and MAC addresses. PostgreSQL type extensions for IP and MAC addresses.
--------------------------------------------------- ---------------------------------------------------
$Id: README,v 1.2 1998/02/14 17:58:03 scrappy Exp $
I needed to record IP and MAC level ethernet addresses in a data I needed to record IP and MAC level ethernet addresses in a data
base, and I really didn't want to store them as plain strings, with base, and I really didn't want to store them as plain strings, with
no enforced error checking, so I put together the accompanying code no enforced error checking, so I put together the accompanying code
...@@ -9,43 +11,46 @@ then thought that this might be useful to others, both directly and ...@@ -9,43 +11,46 @@ then thought that this might be useful to others, both directly and
as a very simple example of how to do this sort of thing, so here as a very simple example of how to do this sort of thing, so here
it is, in the hope that it will be useful. it is, in the hope that it will be useful.
IP addresses are implemented as an 8 byte struct (this may well be IP addresses are implemented as a 6 byte struct (this may be 1 byte
more than is useful, but I figured that since it has to be at least 5, more than is useful, but I figured that since it has to be at least 5,
it might as well round well) that contains the four bytes of address it might as well be an even number of bytes) that contains the four
and a mask width. Thus, a node address looks like '158.37.96.15/32' byte address and a mask width. The external representation of an IP
(or just '158.37.96.15', which is understood to mean the same thing). address looks like '158.37.96.15/32' (or just '158.37.96.15', which is
This address happens to be part of a subnet where I work; understood to mean the same thing). This address happens to be part
'158.37.96.0/24', which itself is a part of the larger subnet of a subnet where I work; '158.37.96.0/24', which itself is a part of
allocated to our institution, which is '158.37.96.0/21', which again, the larger subnet allocated to our site, which is '158.37.96.0/21',
if you go by the book, is part of the class "B" net '158.37.0.0/16'. which again, if you go by the old book, is part of the class "B" net
called '158.37.0.0/16'.
Input and output functions are supplied, along with the "normal" <, Input and output functions are supplied, along with the "normal" <,
<=, =, >=, > and <> operators, which all do what you expect, and the <=, =, >=, > and <> operators, which all do what you expect. In
similarity operator ~~, which checks whether two given addresses are addition, there is a function to check whether a given address is a
either the same, or, failing that, whether one is a subnet member of a given subnet: ipaddr_in_net(addr, net), and functions to
specification and the other an address (or a smaller subnet) within return the netmask and the broadcast address of a given network:
that. Good for picking out records with addresses in a given subnet: ipaddr_mask(net) and ipaddr_bcast(net).
note that '158.37.96.0/21' spans '158.37.96.0' to '158.37.103.255',
which is not all that easily handled in its external representation. MAC level ethernet addresses are implemented as a 6 byte struct that
contains the address as unsigned chars. Several input forms are
MAC level ethernet addresses are also implemented as an 8 byte struct accepted; the following are all the same address: '08002b:010203',
(I wish I knew what alignment needs are actually present -- I'm just '08002b-010203', '0800.2b01.0203', '08-00-2b-01-02-03' and
not taking any chances here) that contains the address as unsigned '08:00:2b:01:02:03'. Upper and lower case is accepted for the digits
chars. Several input forms are accepted: the following are all the 'a' through 'f'. Output is always in the latter of the given forms.
same address: '08002b:010203', '08002b-010203', '0800.2b01.0203',
'08-00-2b-01-02-03' and '08:00:2b:01:02:03'. Upper and lower case is As with IP addresses, input and output functions are supplied as well
accepted for the digits 'a' through 'f'. Output is always in the as the "normal" operators, which do what you expect. As an extra
latter of the given forms.
Input and output functions are supplied, along with the = and <>
operators, which do what you expect, and the similarity operator ~~,
which checks whether two given addresses belong to hardware from the
same manufacturer (first three bytes the same, that is). As an extra
feature, a function macaddr_manuf() is defined, which returns the name feature, a function macaddr_manuf() is defined, which returns the name
of the manufacturer as a string. of the manufacturer as a string. This is currently held in a
hard-coded struct internal to the C module -- it might be smarter to
put this information into an actual data base table, and look up the
manufacturer there. (Another TODO, for both new data types, is to
interface them to indices. If anyone can explain this to me in a way
that is easier to understand than the current documentation, I would
be most grateful!)
To install: fix the path names in the SQL files and the Makefile if I don't know what changes are needed to the Makefile for other systems
you need to, then make, make install, slurp the SQL files into psql or than the one I'm running (NetBSD 1.3), but anyway: to install on a BSD
system: fix the path names in the SQL files and the Makefile if you
need to, then make, make install, slurp the SQL files into psql or
whatever, and you're off. Enjoy! whatever, and you're off. Enjoy!
Bergen, Norway, 1998-01-11, Tom Ivar Helbekkmo (tih@Hamartun.Priv.NO). Bergen, Norway, 1998-01-31, Tom Ivar Helbekkmo (tih@Hamartun.Priv.NO).
/* /*
* PostgreSQL type definitions for IP addresses. * PostgreSQL type definitions for IP addresses.
*
* $Id: ip.c,v 1.2 1998/02/14 17:58:03 scrappy Exp $
*/ */
#include <stdio.h> #include <stdio.h>
...@@ -12,13 +14,8 @@ ...@@ -12,13 +14,8 @@
*/ */
typedef struct ipaddr { typedef struct ipaddr {
unsigned char a; uint32 address;
unsigned char b; int16 width;
unsigned char c;
unsigned char d;
unsigned char w;
unsigned char pad1;
short pad2;
} ipaddr; } ipaddr;
/* /*
...@@ -35,15 +32,24 @@ bool ipaddr_ge(ipaddr *a1, ipaddr *a2); ...@@ -35,15 +32,24 @@ bool ipaddr_ge(ipaddr *a1, ipaddr *a2);
bool ipaddr_gt(ipaddr *a1, ipaddr *a2); bool ipaddr_gt(ipaddr *a1, ipaddr *a2);
bool ipaddr_ne(ipaddr *a1, ipaddr *a2); bool ipaddr_ne(ipaddr *a1, ipaddr *a2);
int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2); int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2);
bool ipaddr_like(ipaddr *a1, ipaddr *a2);
bool ipaddr_in_net(ipaddr *a1, ipaddr *a2);
ipaddr *ipaddr_mask(ipaddr *a);
ipaddr *ipaddr_bcast(ipaddr *a);
/* /*
* A utility macro used for sorting addresses numerically: * Build a mask of a given width:
*/ */
#define Mag(addr) \ unsigned long build_mask(unsigned char bits) {
((unsigned long)((addr->a<<24)|(addr->b<<16)|(addr->c<<8)|(addr->d))) unsigned long mask = 0;
int i;
for (i = 0; i < bits; i++)
mask = (mask >> 1) | 0x80000000;
return mask;
}
/* /*
* IP address reader. Note how the count returned by sscanf() * IP address reader. Note how the count returned by sscanf()
...@@ -79,11 +85,9 @@ ipaddr *ipaddr_in(char *str) { ...@@ -79,11 +85,9 @@ ipaddr *ipaddr_in(char *str) {
result = (ipaddr *)palloc(sizeof(ipaddr)); result = (ipaddr *)palloc(sizeof(ipaddr));
result->a = a; result->address = (uint32) ((a<<24)|(b<<16)|(c<<8)|d);
result->b = b; result->address &= build_mask(w);
result->c = c; result->width = w;
result->d = d;
result->w = w;
return(result); return(result);
} }
...@@ -101,13 +105,20 @@ char *ipaddr_out(ipaddr *addr) { ...@@ -101,13 +105,20 @@ char *ipaddr_out(ipaddr *addr) {
result = (char *)palloc(32); result = (char *)palloc(32);
if (Mag(addr) > 0) { if (addr->address > 0) {
if (addr->w == 32) if (addr->width == 32)
sprintf(result, "%d.%d.%d.%d", sprintf(result, "%d.%d.%d.%d",
addr->a, addr->b, addr->c, addr->d); (addr->address >> 24) & 0xff,
(addr->address >> 16) & 0xff,
(addr->address >> 8) & 0xff,
addr->address & 0xff);
else else
sprintf(result, "%d.%d.%d.%d/%d", sprintf(result, "%d.%d.%d.%d/%d",
addr->a, addr->b, addr->c, addr->d, addr->w); (addr->address >> 24) & 0xff,
(addr->address >> 16) & 0xff,
(addr->address >> 8) & 0xff,
addr->address & 0xff,
addr->width);
} else { } else {
result[0] = 0; /* special case for missing address */ result[0] = 0; /* special case for missing address */
} }
...@@ -115,49 +126,31 @@ char *ipaddr_out(ipaddr *addr) { ...@@ -115,49 +126,31 @@ char *ipaddr_out(ipaddr *addr) {
} }
/* /*
* Boolean tests. The Mag() macro was defined above. * Boolean tests for magnitude.
*/ */
bool ipaddr_lt(ipaddr *a1, ipaddr *a2) { bool ipaddr_lt(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag, a2mag; return (a1->address < a2->address);
a1mag = Mag(a1);
a2mag = Mag(a2);
return (a1mag < a2mag);
}; };
bool ipaddr_le(ipaddr *a1, ipaddr *a2) { bool ipaddr_le(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag, a2mag; return (a1->address <= a2->address);
a1mag = Mag(a1);
a2mag = Mag(a2);
return (a1mag <= a2mag);
}; };
bool ipaddr_eq(ipaddr *a1, ipaddr *a2) { bool ipaddr_eq(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag, a2mag; return (a1->address == a2->address);
a1mag = Mag(a1);
a2mag = Mag(a2);
return ((a1mag == a2mag) && (a1->w == a2->w));
}; };
bool ipaddr_ge(ipaddr *a1, ipaddr *a2) { bool ipaddr_ge(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag, a2mag; return (a1->address >= a2->address);
a1mag = Mag(a1);
a2mag = Mag(a2);
return (a1mag >= a2mag);
}; };
bool ipaddr_gt(ipaddr *a1, ipaddr *a2) { bool ipaddr_gt(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag, a2mag; return (a1->address > a2->address);
a1mag = Mag(a1);
a2mag = Mag(a2);
return (a1mag > a2mag);
}; };
bool ipaddr_ne(ipaddr *a1, ipaddr *a2) { bool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag, a2mag; return (a1->address != a2->address);
a1mag = Mag(a1);
a2mag = Mag(a2);
return ((a1mag != a2mag) || (a1->w != a2->w));
}; };
/* /*
...@@ -165,48 +158,59 @@ bool ipaddr_ne(ipaddr *a1, ipaddr *a2) { ...@@ -165,48 +158,59 @@ bool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
*/ */
int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) { int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) {
unsigned long a1mag = Mag(a1), a2mag = Mag(a2); if (a1->address < a2->address)
if (a1mag < a2mag)
return -1; return -1;
else if (a1mag > a2mag) else if (a1->address > a2->address)
return 1; return 1;
else else
return 0; return 0;
} }
/* /*
* Our "similarity" operator checks whether two addresses are * Test whether an address is within a given subnet:
* either the same node address, or, failing that, whether one
* of them contains the other. This will be true if they have
* the same high bits down as far as the shortest mask reaches.
*/ */
unsigned long build_mask(unsigned char bits) { bool ipaddr_in_net(ipaddr *a1, ipaddr *a2) {
unsigned long mask = 0; uint32 maskbits;
int i; if (a1->width < a2->width)
for (i = 0; i < bits; i++)
mask = (mask >> 1) | 0x80000000;
return mask;
}
bool ipaddr_like(ipaddr *a1, ipaddr *a2) {
unsigned long a1bits, a2bits, maskbits;
if ((a1->w == 0) || (a2->w == 0))
return FALSE; return FALSE;
if ((a1->w == 32) && (a2->w == 32)) if ((a1->width == 32) && (a2->width == 32))
return ipaddr_eq(a1, a2); return ipaddr_eq(a1, a2);
a1bits = Mag(a1); maskbits = build_mask(a2->width);
a2bits = Mag(a2); if ((a1->address & maskbits) == (a2->address & maskbits))
if (a1->w > a2->w) { return TRUE;
maskbits = build_mask(a2->w);
return ((a1bits & maskbits) == (a2bits & maskbits));
} else {
maskbits = build_mask(a1->w);
return ((a2bits & maskbits) == (a1bits & maskbits));
}
return FALSE; return FALSE;
} }
/*
* Pick out just the mask of a network:
*/
ipaddr *ipaddr_mask(ipaddr *a) {
ipaddr *result;
result = (ipaddr *)palloc(sizeof(ipaddr));
result->address = build_mask(a->width);
result->width = 32;
return result;
}
/*
* Return the broadcast address of a network:
*/
ipaddr *ipaddr_bcast(ipaddr *a) {
ipaddr *result;
result = (ipaddr *)palloc(sizeof(ipaddr));
result->address = a->address;
result->address |= (build_mask(32 - a->width) >> a->width);
result->width = 32;
return result;
}
/* /*
* eof * eof
*/ */
-- --
-- PostgreSQL code for IP addresses. -- PostgreSQL code for IP addresses.
-- --
-- $Id: ip.sql,v 1.2 1998/02/14 17:58:04 scrappy Exp $
--
load '/usr/local/pgsql/modules/ip.so'; load '/usr/local/pgsql/modules/ip.so';
...@@ -19,7 +21,7 @@ create function ipaddr_out(opaque) ...@@ -19,7 +21,7 @@ create function ipaddr_out(opaque)
language 'c'; language 'c';
create type ipaddr ( create type ipaddr (
internallength = 8, internallength = 6,
externallength = variable, externallength = variable,
input = ipaddr_in, input = ipaddr_in,
output = ipaddr_out output = ipaddr_out
...@@ -59,11 +61,21 @@ create function ipaddr_ne(ipaddr, ipaddr) ...@@ -59,11 +61,21 @@ create function ipaddr_ne(ipaddr, ipaddr)
as '/usr/local/pgsql/modules/ip.so' as '/usr/local/pgsql/modules/ip.so'
language 'c'; language 'c';
create function ipaddr_like(ipaddr, ipaddr) create function ipaddr_in_net(ipaddr, ipaddr)
returns bool returns bool
as '/usr/local/pgsql/modules/ip.so' as '/usr/local/pgsql/modules/ip.so'
language 'c'; language 'c';
create function ipaddr_mask(ipaddr)
returns ipaddr
as '/usr/local/pgsql/modules/ip.so'
language 'c';
create function ipaddr_bcast(ipaddr)
returns ipaddr
as '/usr/local/pgsql/modules/ip.so'
language 'c';
-- --
-- Now the operators. Note how some of the parameters to some -- Now the operators. Note how some of the parameters to some
-- of the 'create operator' commands are commented out. This -- of the 'create operator' commands are commented out. This
...@@ -71,20 +83,18 @@ create function ipaddr_like(ipaddr, ipaddr) ...@@ -71,20 +83,18 @@ create function ipaddr_like(ipaddr, ipaddr)
-- will be implicitly defined when those are, further down. -- will be implicitly defined when those are, further down.
-- --
create operator <= ( create operator < (
leftarg = ipaddr, leftarg = ipaddr,
rightarg = ipaddr, rightarg = ipaddr,
-- commutator = >, -- negator = >=,
-- negator = >, procedure = ipaddr_lt
procedure = ipaddr_le
); );
create operator < ( create operator <= (
leftarg = ipaddr, leftarg = ipaddr,
rightarg = ipaddr, rightarg = ipaddr,
-- commutator = >=, -- negator = >,
-- negator = >=, procedure = ipaddr_le
procedure = ipaddr_lt
); );
create operator = ( create operator = (
...@@ -98,7 +108,6 @@ create operator = ( ...@@ -98,7 +108,6 @@ create operator = (
create operator >= ( create operator >= (
leftarg = ipaddr, leftarg = ipaddr,
rightarg = ipaddr, rightarg = ipaddr,
commutator = <,
negator = <, negator = <,
procedure = ipaddr_ge procedure = ipaddr_ge
); );
...@@ -106,7 +115,6 @@ create operator >= ( ...@@ -106,7 +115,6 @@ create operator >= (
create operator > ( create operator > (
leftarg = ipaddr, leftarg = ipaddr,
rightarg = ipaddr, rightarg = ipaddr,
commutator = <=,
negator = <=, negator = <=,
procedure = ipaddr_gt procedure = ipaddr_gt
); );
...@@ -114,18 +122,10 @@ create operator > ( ...@@ -114,18 +122,10 @@ create operator > (
create operator <> ( create operator <> (
leftarg = ipaddr, leftarg = ipaddr,
rightarg = ipaddr, rightarg = ipaddr,
commutator = <>,
negator = =, negator = =,
procedure = ipaddr_ne procedure = ipaddr_ne
); );
create operator ~~ (
leftarg = ipaddr,
rightarg = ipaddr,
commutator = ~~,
procedure = ipaddr_like
);
-- --
-- eof -- eof
-- --
/* /*
* PostgreSQL type definitions for MAC addresses. * PostgreSQL type definitions for MAC addresses.
*
* $Id: mac.c,v 1.2 1998/02/14 17:58:05 scrappy Exp $
*/ */
#include <stdio.h> #include <stdio.h>
...@@ -20,7 +22,6 @@ typedef struct macaddr { ...@@ -20,7 +22,6 @@ typedef struct macaddr {
unsigned char d; unsigned char d;
unsigned char e; unsigned char e;
unsigned char f; unsigned char f;
short pad;
} macaddr; } macaddr;
/* /*
...@@ -30,21 +31,26 @@ typedef struct macaddr { ...@@ -30,21 +31,26 @@ typedef struct macaddr {
macaddr *macaddr_in(char *str); macaddr *macaddr_in(char *str);
char *macaddr_out(macaddr *addr); char *macaddr_out(macaddr *addr);
bool macaddr_lt(macaddr *a1, macaddr *a2);
bool macaddr_le(macaddr *a1, macaddr *a2);
bool macaddr_eq(macaddr *a1, macaddr *a2); bool macaddr_eq(macaddr *a1, macaddr *a2);
bool macaddr_ge(macaddr *a1, macaddr *a2);
bool macaddr_gt(macaddr *a1, macaddr *a2);
bool macaddr_ne(macaddr *a1, macaddr *a2); bool macaddr_ne(macaddr *a1, macaddr *a2);
int4 macaddr_cmp(macaddr *a1, macaddr *a2); int4 macaddr_cmp(macaddr *a1, macaddr *a2);
bool macaddr_like(macaddr *a1, macaddr *a2);
text *macaddr_manuf(macaddr *addr); text *macaddr_manuf(macaddr *addr);
/* /*
* Utility macros used for sorting and comparing: * Utility macros used for sorting and comparing:
*/ */
#define MagM(addr) \ #define hibits(addr) \
((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c))) ((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c)))
#define MagH(addr) \ #define lobits(addr) \
((unsigned long)((addr->c<<16)|(addr->e<<8)|(addr->f))) ((unsigned long)((addr->c<<16)|(addr->e<<8)|(addr->f)))
/* /*
...@@ -107,7 +113,7 @@ char *macaddr_out(macaddr *addr) { ...@@ -107,7 +113,7 @@ char *macaddr_out(macaddr *addr) {
result = (char *)palloc(32); result = (char *)palloc(32);
if ((MagM(addr) > 0) || (MagH(addr) > 0)) { if ((hibits(addr) > 0) || (lobits(addr) > 0)) {
sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x", sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x",
addr->a, addr->b, addr->c, addr->d, addr->e, addr->f); addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
} else { } else {
...@@ -120,16 +126,32 @@ char *macaddr_out(macaddr *addr) { ...@@ -120,16 +126,32 @@ char *macaddr_out(macaddr *addr) {
* Boolean tests. * Boolean tests.
*/ */
bool macaddr_lt(macaddr *a1, macaddr *a2) {
return((hibits(a1) < hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) < lobits(a2)));
};
bool macaddr_le(macaddr *a1, macaddr *a2) {
return((hibits(a1) < hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) <= lobits(a2)));
};
bool macaddr_eq(macaddr *a1, macaddr *a2) { bool macaddr_eq(macaddr *a1, macaddr *a2) {
return((a1->a == a2->a) && (a1->b == a2->b) && return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
(a1->c == a2->c) && (a1->d == a2->d) && };
(a1->e == a2->e) && (a1->f == a2->f));
bool macaddr_ge(macaddr *a1, macaddr *a2) {
return((hibits(a1) > hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) >= lobits(a2)));
};
bool macaddr_gt(macaddr *a1, macaddr *a2) {
return((hibits(a1) > hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) > lobits(a2)));
}; };
bool macaddr_ne(macaddr *a1, macaddr *a2) { bool macaddr_ne(macaddr *a1, macaddr *a2) {
return((a1->a != a2->a) || (a1->b != a2->b) || return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
(a1->c != a2->c) || (a1->d != a2->d) ||
(a1->e != a2->e) || (a1->f != a2->f));
}; };
/* /*
...@@ -137,37 +159,18 @@ bool macaddr_ne(macaddr *a1, macaddr *a2) { ...@@ -137,37 +159,18 @@ bool macaddr_ne(macaddr *a1, macaddr *a2) {
*/ */
int4 macaddr_cmp(macaddr *a1, macaddr *a2) { int4 macaddr_cmp(macaddr *a1, macaddr *a2) {
unsigned long a1magm, a1magh, a2magm, a2magh; if (hibits(a1) < hibits(a2))
a1magm = MagM(a1);
a1magh = MagH(a1);
a2magm = MagM(a2);
a2magh = MagH(a2);
if (a1magm < a2magm)
return -1; return -1;
else if (a1magm > a2magm) else if (hibits(a1) > hibits(a2))
return 1; return 1;
else if (a1magh < a2magh) else if (lobits(a1) < lobits(a2))
return -1; return -1;
else if (a1magh > a2magh) else if (lobits(a1) > lobits(a2))
return 1; return 1;
else else
return 0; return 0;
} }
/*
* Similarity means having the same manufacurer, which means
* having the same first three bytes of address:
*/
bool macaddr_like(macaddr *a1, macaddr *a2) {
unsigned long a1magm, a2magm;
a1magm = MagM(a1);
a2magm = MagM(a2);
if ((a1magm == 0) || (a2magm == 0))
return FALSE;
return (a1magm == a2magm);
}
/* /*
* The special manufacturer fetching function. See "mac.h". * The special manufacturer fetching function. See "mac.h".
*/ */
......
/* /*
* PostgreSQL type definitions for MAC addresses. * PostgreSQL type definitions for MAC addresses.
*
* $Id: mac.h,v 1.2 1998/02/14 17:58:07 scrappy Exp $
*/ */
typedef struct manufacturer { typedef struct manufacturer {
......
-- --
-- PostgreSQL code for MAC addresses. -- PostgreSQL code for MAC addresses.
-- --
-- $Id: mac.sql,v 1.2 1998/02/14 17:58:08 scrappy Exp $
--
load '/usr/local/pgsql/modules/mac.so'; load '/usr/local/pgsql/modules/mac.so';
...@@ -19,38 +21,67 @@ create function macaddr_out(opaque) ...@@ -19,38 +21,67 @@ create function macaddr_out(opaque)
language 'c'; language 'c';
create type macaddr ( create type macaddr (
internallength = 8, internallength = 6,
externallength = variable, externallength = variable,
input = macaddr_in, input = macaddr_in,
output = macaddr_out output = macaddr_out
); );
-- --
-- The various boolean tests: -- The boolean tests:
-- --
create function macaddr_lt(macaddr, macaddr)
returns bool
as '/usr/local/pgsql/modules/mac.so'
language 'c';
create function macaddr_le(macaddr, macaddr)
returns bool
as '/usr/local/pgsql/modules/mac.so'
language 'c';
create function macaddr_eq(macaddr, macaddr) create function macaddr_eq(macaddr, macaddr)
returns bool returns bool
as '/usr/local/pgsql/modules/mac.so' as '/usr/local/pgsql/modules/mac.so'
language 'c'; language 'c';
create function macaddr_ne(macaddr, macaddr) create function macaddr_ge(macaddr, macaddr)
returns bool
as '/usr/local/pgsql/modules/mac.so'
language 'c';
create function macaddr_gt(macaddr, macaddr)
returns bool returns bool
as '/usr/local/pgsql/modules/mac.so' as '/usr/local/pgsql/modules/mac.so'
language 'c'; language 'c';
create function macaddr_like(macaddr, macaddr) create function macaddr_ne(macaddr, macaddr)
returns bool returns bool
as '/usr/local/pgsql/modules/mac.so' as '/usr/local/pgsql/modules/mac.so'
language 'c'; language 'c';
-- --
-- Now the operators. Note how the "negator = <>" in the -- Now the operators. Note how some of the parameters to some
-- definition of the equivalence operator is commented out. -- of the 'create operator' commands are commented out. This
-- It gets defined implicitly when "<>" is defined, with -- is because they reference as yet undefined operators, and
-- "=" as its negator. -- will be implicitly defined when those are, further down.
-- --
create operator < (
leftarg = macaddr,
rightarg = macaddr,
-- negator = >=,
procedure = macaddr_lt
);
create operator <= (
leftarg = macaddr,
rightarg = macaddr,
-- negator = >,
procedure = macaddr_le
);
create operator = ( create operator = (
leftarg = macaddr, leftarg = macaddr,
rightarg = macaddr, rightarg = macaddr,
...@@ -59,19 +90,25 @@ create operator = ( ...@@ -59,19 +90,25 @@ create operator = (
procedure = macaddr_eq procedure = macaddr_eq
); );
create operator <> ( create operator >= (
leftarg = macaddr, leftarg = macaddr,
rightarg = macaddr, rightarg = macaddr,
commutator = <>, negator = <,
negator = =, procedure = macaddr_ge
procedure = macaddr_ne );
create operator > (
leftarg = macaddr,
rightarg = macaddr,
negator = <=,
procedure = macaddr_gt
); );
create operator ~~ ( create operator <> (
leftarg = macaddr, leftarg = macaddr,
rightarg = macaddr, rightarg = macaddr,
commutator = ~~, negator = =,
procedure = macaddr_like procedure = macaddr_ne
); );
-- --
......
--
-- A quick test of the IP address code
--
-- $Id: test.sql,v 1.1 1998/02/14 17:58:09 scrappy Exp $
--
-- temporary table:
create table addresses (address ipaddr);
-- sample data from two subnets:
insert into addresses values ('158.37.96.15');
insert into addresses values ('158.37.96.16');
insert into addresses values ('158.37.96.17');
insert into addresses values ('158.37.97.15');
insert into addresses values ('158.37.97.16');
insert into addresses values ('158.37.97.17');
insert into addresses values ('158.37.98.15');
insert into addresses values ('158.37.98.16');
insert into addresses values ('158.37.98.17');
insert into addresses values ('158.37.96.150');
insert into addresses values ('158.37.96.160');
insert into addresses values ('158.37.96.170');
insert into addresses values ('158.37.97.150');
insert into addresses values ('158.37.97.160');
insert into addresses values ('158.37.97.170');
insert into addresses values ('158.37.98.150');
insert into addresses values ('158.37.98.160');
insert into addresses values ('158.37.98.170');
-- show them all:
select * from addresses;
-- select the ones in subnet 96:
select * from addresses where ipaddr_in_net(address, '158.37.96.0/24');
-- select the ones not in subnet 96:
select * from addresses where not ipaddr_in_net(address, '158.37.96.0/24');
-- select the ones in subnet 97:
select * from addresses where ipaddr_in_net(address, '158.37.97.0/24');
-- select the ones not in subnet 97:
select * from addresses where not ipaddr_in_net(address, '158.37.97.0/24');
-- select the ones in subnet 96 or 97, sorted:
select * from addresses where ipaddr_in_net(address, '158.37.96.0/23')
order by address;
-- now some networks:
create table networks (network ipaddr);
-- now the subnets mentioned above:
insert into networks values ('158.37.96.0/24');
insert into networks values ('158.37.97.0/24');
insert into networks values ('158.37.98.0/24');
-- select the netmasks of the net containing each:
select address, ipaddr_mask(network) from addresses, networks
where ipaddr_in_net(address, network);
-- select the broadcast address of the net containing each:
select address, ipaddr_bcast(network) from addresses, networks
where ipaddr_in_net(address, network);
-- tidy up:
drop table addresses;
drop table networks;
--
-- eof
--
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment