mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-30 19:00:29 +08:00
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>
This commit is contained in:
parent
9336b9b280
commit
a377ad58ea
@ -1,4 +1,7 @@
|
||||
# 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
|
||||
|
||||
@ -17,4 +20,6 @@ mac.o: mac.c mac.h
|
||||
install: ip.so mac.so
|
||||
install -c ip.so mac.so /usr/local/pgsql/modules
|
||||
|
||||
#
|
||||
# eof
|
||||
#
|
||||
|
@ -1,6 +1,8 @@
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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,
|
||||
it might as well round well) that contains the four bytes of address
|
||||
and a mask width. Thus, a node address looks like '158.37.96.15/32'
|
||||
(or just '158.37.96.15', which is understood to mean the same thing).
|
||||
This address happens to be part of a subnet where I work;
|
||||
'158.37.96.0/24', which itself is a part of the larger subnet
|
||||
allocated to our institution, which is '158.37.96.0/21', which again,
|
||||
if you go by the book, is part of the class "B" net '158.37.0.0/16'.
|
||||
it might as well be an even number of bytes) that contains the four
|
||||
byte address and a mask width. The external representation of an IP
|
||||
address looks like '158.37.96.15/32' (or just '158.37.96.15', which is
|
||||
understood to mean the same thing). This address happens to be part
|
||||
of a subnet where I work; '158.37.96.0/24', which itself is a part of
|
||||
the larger subnet allocated to our site, which is '158.37.96.0/21',
|
||||
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" <,
|
||||
<=, =, >=, > and <> operators, which all do what you expect, and the
|
||||
similarity operator ~~, which checks whether two given addresses are
|
||||
either the same, or, failing that, whether one is a subnet
|
||||
specification and the other an address (or a smaller subnet) within
|
||||
that. Good for picking out records with addresses in a given subnet:
|
||||
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.
|
||||
<=, =, >=, > and <> operators, which all do what you expect. In
|
||||
addition, there is a function to check whether a given address is a
|
||||
member of a given subnet: ipaddr_in_net(addr, net), and functions to
|
||||
return the netmask and the broadcast address of a given network:
|
||||
ipaddr_mask(net) and ipaddr_bcast(net).
|
||||
|
||||
MAC level ethernet addresses are also implemented as an 8 byte struct
|
||||
(I wish I knew what alignment needs are actually present -- I'm just
|
||||
not taking any chances here) that contains the address as unsigned
|
||||
chars. Several input forms are accepted: the following are all the
|
||||
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
|
||||
accepted for the digits 'a' through 'f'. Output is always in the
|
||||
latter of the given forms.
|
||||
MAC level ethernet addresses are implemented as a 6 byte struct that
|
||||
contains the address as unsigned chars. Several input forms are
|
||||
accepted; the following are all the 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 accepted for the digits
|
||||
'a' through 'f'. Output is always in the 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
|
||||
As with IP addresses, input and output functions are supplied as well
|
||||
as the "normal" operators, which do what you expect. As an extra
|
||||
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
|
||||
you need to, then make, make install, slurp the SQL files into psql or
|
||||
I don't know what changes are needed to the Makefile for other systems
|
||||
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!
|
||||
|
||||
Bergen, Norway, 1998-01-11, Tom Ivar Helbekkmo (tih@Hamartun.Priv.NO).
|
||||
Bergen, Norway, 1998-01-31, Tom Ivar Helbekkmo (tih@Hamartun.Priv.NO).
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* PostgreSQL type definitions for IP addresses.
|
||||
*
|
||||
* $Id: ip.c,v 1.2 1998/02/14 17:58:03 scrappy Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -12,13 +14,8 @@
|
||||
*/
|
||||
|
||||
typedef struct ipaddr {
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned char c;
|
||||
unsigned char d;
|
||||
unsigned char w;
|
||||
unsigned char pad1;
|
||||
short pad2;
|
||||
uint32 address;
|
||||
int16 width;
|
||||
} ipaddr;
|
||||
|
||||
/*
|
||||
@ -35,15 +32,24 @@ bool ipaddr_ge(ipaddr *a1, ipaddr *a2);
|
||||
bool ipaddr_gt(ipaddr *a1, ipaddr *a2);
|
||||
|
||||
bool ipaddr_ne(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)((addr->a<<24)|(addr->b<<16)|(addr->c<<8)|(addr->d)))
|
||||
unsigned long build_mask(unsigned char bits) {
|
||||
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()
|
||||
@ -79,11 +85,9 @@ ipaddr *ipaddr_in(char *str) {
|
||||
|
||||
result = (ipaddr *)palloc(sizeof(ipaddr));
|
||||
|
||||
result->a = a;
|
||||
result->b = b;
|
||||
result->c = c;
|
||||
result->d = d;
|
||||
result->w = w;
|
||||
result->address = (uint32) ((a<<24)|(b<<16)|(c<<8)|d);
|
||||
result->address &= build_mask(w);
|
||||
result->width = w;
|
||||
|
||||
return(result);
|
||||
}
|
||||
@ -101,13 +105,20 @@ char *ipaddr_out(ipaddr *addr) {
|
||||
|
||||
result = (char *)palloc(32);
|
||||
|
||||
if (Mag(addr) > 0) {
|
||||
if (addr->w == 32)
|
||||
if (addr->address > 0) {
|
||||
if (addr->width == 32)
|
||||
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
|
||||
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 {
|
||||
result[0] = 0; /* special case for missing address */
|
||||
}
|
||||
@ -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) {
|
||||
unsigned long a1mag, a2mag;
|
||||
a1mag = Mag(a1);
|
||||
a2mag = Mag(a2);
|
||||
return (a1mag < a2mag);
|
||||
return (a1->address < a2->address);
|
||||
};
|
||||
|
||||
bool ipaddr_le(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1mag, a2mag;
|
||||
a1mag = Mag(a1);
|
||||
a2mag = Mag(a2);
|
||||
return (a1mag <= a2mag);
|
||||
return (a1->address <= a2->address);
|
||||
};
|
||||
|
||||
bool ipaddr_eq(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1mag, a2mag;
|
||||
a1mag = Mag(a1);
|
||||
a2mag = Mag(a2);
|
||||
return ((a1mag == a2mag) && (a1->w == a2->w));
|
||||
return (a1->address == a2->address);
|
||||
};
|
||||
|
||||
bool ipaddr_ge(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1mag, a2mag;
|
||||
a1mag = Mag(a1);
|
||||
a2mag = Mag(a2);
|
||||
return (a1mag >= a2mag);
|
||||
return (a1->address >= a2->address);
|
||||
};
|
||||
|
||||
bool ipaddr_gt(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1mag, a2mag;
|
||||
a1mag = Mag(a1);
|
||||
a2mag = Mag(a2);
|
||||
return (a1mag > a2mag);
|
||||
return (a1->address > a2->address);
|
||||
};
|
||||
|
||||
bool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1mag, a2mag;
|
||||
a1mag = Mag(a1);
|
||||
a2mag = Mag(a2);
|
||||
return ((a1mag != a2mag) || (a1->w != a2->w));
|
||||
return (a1->address != a2->address);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -165,46 +158,57 @@ bool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
|
||||
*/
|
||||
|
||||
int4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1mag = Mag(a1), a2mag = Mag(a2);
|
||||
if (a1mag < a2mag)
|
||||
if (a1->address < a2->address)
|
||||
return -1;
|
||||
else if (a1mag > a2mag)
|
||||
else if (a1->address > a2->address)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our "similarity" operator checks whether two addresses are
|
||||
* 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.
|
||||
* Test whether an address is within a given subnet:
|
||||
*/
|
||||
|
||||
unsigned long build_mask(unsigned char bits) {
|
||||
unsigned long mask = 0;
|
||||
int i;
|
||||
for (i = 0; i < bits; i++)
|
||||
mask = (mask >> 1) | 0x80000000;
|
||||
return mask;
|
||||
bool ipaddr_in_net(ipaddr *a1, ipaddr *a2) {
|
||||
uint32 maskbits;
|
||||
if (a1->width < a2->width)
|
||||
return FALSE;
|
||||
if ((a1->width == 32) && (a2->width == 32))
|
||||
return ipaddr_eq(a1, a2);
|
||||
maskbits = build_mask(a2->width);
|
||||
if ((a1->address & maskbits) == (a2->address & maskbits))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool ipaddr_like(ipaddr *a1, ipaddr *a2) {
|
||||
unsigned long a1bits, a2bits, maskbits;
|
||||
if ((a1->w == 0) || (a2->w == 0))
|
||||
return FALSE;
|
||||
if ((a1->w == 32) && (a2->w == 32))
|
||||
return ipaddr_eq(a1, a2);
|
||||
a1bits = Mag(a1);
|
||||
a2bits = Mag(a2);
|
||||
if (a1->w > a2->w) {
|
||||
maskbits = build_mask(a2->w);
|
||||
return ((a1bits & maskbits) == (a2bits & maskbits));
|
||||
} else {
|
||||
maskbits = build_mask(a1->w);
|
||||
return ((a2bits & maskbits) == (a1bits & maskbits));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,6 +1,8 @@
|
||||
--
|
||||
-- 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';
|
||||
|
||||
@ -19,7 +21,7 @@ create function ipaddr_out(opaque)
|
||||
language 'c';
|
||||
|
||||
create type ipaddr (
|
||||
internallength = 8,
|
||||
internallength = 6,
|
||||
externallength = variable,
|
||||
input = ipaddr_in,
|
||||
output = ipaddr_out
|
||||
@ -59,11 +61,21 @@ create function ipaddr_ne(ipaddr, ipaddr)
|
||||
as '/usr/local/pgsql/modules/ip.so'
|
||||
language 'c';
|
||||
|
||||
create function ipaddr_like(ipaddr, ipaddr)
|
||||
create function ipaddr_in_net(ipaddr, ipaddr)
|
||||
returns bool
|
||||
as '/usr/local/pgsql/modules/ip.so'
|
||||
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
|
||||
-- of the 'create operator' commands are commented out. This
|
||||
@ -71,22 +83,20 @@ create function ipaddr_like(ipaddr, ipaddr)
|
||||
-- will be implicitly defined when those are, further down.
|
||||
--
|
||||
|
||||
create operator <= (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
-- commutator = >,
|
||||
-- negator = >,
|
||||
procedure = ipaddr_le
|
||||
);
|
||||
|
||||
create operator < (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
-- commutator = >=,
|
||||
-- negator = >=,
|
||||
procedure = ipaddr_lt
|
||||
);
|
||||
|
||||
create operator <= (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
-- negator = >,
|
||||
procedure = ipaddr_le
|
||||
);
|
||||
|
||||
create operator = (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
@ -98,7 +108,6 @@ create operator = (
|
||||
create operator >= (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
commutator = <,
|
||||
negator = <,
|
||||
procedure = ipaddr_ge
|
||||
);
|
||||
@ -106,7 +115,6 @@ create operator >= (
|
||||
create operator > (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
commutator = <=,
|
||||
negator = <=,
|
||||
procedure = ipaddr_gt
|
||||
);
|
||||
@ -114,18 +122,10 @@ create operator > (
|
||||
create operator <> (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
commutator = <>,
|
||||
negator = =,
|
||||
procedure = ipaddr_ne
|
||||
);
|
||||
|
||||
create operator ~~ (
|
||||
leftarg = ipaddr,
|
||||
rightarg = ipaddr,
|
||||
commutator = ~~,
|
||||
procedure = ipaddr_like
|
||||
);
|
||||
|
||||
--
|
||||
-- eof
|
||||
--
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* PostgreSQL type definitions for MAC addresses.
|
||||
*
|
||||
* $Id: mac.c,v 1.2 1998/02/14 17:58:05 scrappy Exp $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -20,7 +22,6 @@ typedef struct macaddr {
|
||||
unsigned char d;
|
||||
unsigned char e;
|
||||
unsigned char f;
|
||||
short pad;
|
||||
} macaddr;
|
||||
|
||||
/*
|
||||
@ -30,21 +31,26 @@ typedef struct macaddr {
|
||||
macaddr *macaddr_in(char *str);
|
||||
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_ge(macaddr *a1, macaddr *a2);
|
||||
bool macaddr_gt(macaddr *a1, macaddr *a2);
|
||||
|
||||
bool macaddr_ne(macaddr *a1, macaddr *a2);
|
||||
|
||||
int4 macaddr_cmp(macaddr *a1, macaddr *a2);
|
||||
bool macaddr_like(macaddr *a1, macaddr *a2);
|
||||
|
||||
text *macaddr_manuf(macaddr *addr);
|
||||
|
||||
/*
|
||||
* Utility macros used for sorting and comparing:
|
||||
*/
|
||||
|
||||
#define MagM(addr) \
|
||||
#define hibits(addr) \
|
||||
((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)))
|
||||
|
||||
/*
|
||||
@ -107,7 +113,7 @@ char *macaddr_out(macaddr *addr) {
|
||||
|
||||
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",
|
||||
addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
|
||||
} else {
|
||||
@ -120,16 +126,32 @@ char *macaddr_out(macaddr *addr) {
|
||||
* 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) {
|
||||
return((a1->a == a2->a) && (a1->b == a2->b) &&
|
||||
(a1->c == a2->c) && (a1->d == a2->d) &&
|
||||
(a1->e == a2->e) && (a1->f == a2->f));
|
||||
return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
|
||||
};
|
||||
|
||||
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) {
|
||||
return((a1->a != a2->a) || (a1->b != a2->b) ||
|
||||
(a1->c != a2->c) || (a1->d != a2->d) ||
|
||||
(a1->e != a2->e) || (a1->f != a2->f));
|
||||
return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
|
||||
};
|
||||
|
||||
/*
|
||||
@ -137,37 +159,18 @@ bool macaddr_ne(macaddr *a1, macaddr *a2) {
|
||||
*/
|
||||
|
||||
int4 macaddr_cmp(macaddr *a1, macaddr *a2) {
|
||||
unsigned long a1magm, a1magh, a2magm, a2magh;
|
||||
a1magm = MagM(a1);
|
||||
a1magh = MagH(a1);
|
||||
a2magm = MagM(a2);
|
||||
a2magh = MagH(a2);
|
||||
if (a1magm < a2magm)
|
||||
if (hibits(a1) < hibits(a2))
|
||||
return -1;
|
||||
else if (a1magm > a2magm)
|
||||
else if (hibits(a1) > hibits(a2))
|
||||
return 1;
|
||||
else if (a1magh < a2magh)
|
||||
else if (lobits(a1) < lobits(a2))
|
||||
return -1;
|
||||
else if (a1magh > a2magh)
|
||||
else if (lobits(a1) > lobits(a2))
|
||||
return 1;
|
||||
else
|
||||
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".
|
||||
*/
|
||||
|
@ -1,5 +1,7 @@
|
||||
/*
|
||||
* PostgreSQL type definitions for MAC addresses.
|
||||
*
|
||||
* $Id: mac.h,v 1.2 1998/02/14 17:58:07 scrappy Exp $
|
||||
*/
|
||||
|
||||
typedef struct manufacturer {
|
||||
|
@ -1,6 +1,8 @@
|
||||
--
|
||||
-- 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';
|
||||
|
||||
@ -19,37 +21,66 @@ create function macaddr_out(opaque)
|
||||
language 'c';
|
||||
|
||||
create type macaddr (
|
||||
internallength = 8,
|
||||
internallength = 6,
|
||||
externallength = variable,
|
||||
input = macaddr_in,
|
||||
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)
|
||||
returns bool
|
||||
as '/usr/local/pgsql/modules/mac.so'
|
||||
language 'c';
|
||||
|
||||
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
|
||||
as '/usr/local/pgsql/modules/mac.so'
|
||||
language 'c';
|
||||
|
||||
create function macaddr_ne(macaddr, macaddr)
|
||||
returns bool
|
||||
as '/usr/local/pgsql/modules/mac.so'
|
||||
language 'c';
|
||||
|
||||
create function macaddr_like(macaddr, macaddr)
|
||||
returns bool
|
||||
as '/usr/local/pgsql/modules/mac.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.
|
||||
--
|
||||
|
||||
--
|
||||
-- Now the operators. Note how the "negator = <>" in the
|
||||
-- definition of the equivalence operator is commented out.
|
||||
-- It gets defined implicitly when "<>" is defined, with
|
||||
-- "=" as its negator.
|
||||
--
|
||||
create operator < (
|
||||
leftarg = macaddr,
|
||||
rightarg = macaddr,
|
||||
-- negator = >=,
|
||||
procedure = macaddr_lt
|
||||
);
|
||||
|
||||
create operator <= (
|
||||
leftarg = macaddr,
|
||||
rightarg = macaddr,
|
||||
-- negator = >,
|
||||
procedure = macaddr_le
|
||||
);
|
||||
|
||||
create operator = (
|
||||
leftarg = macaddr,
|
||||
@ -59,21 +90,27 @@ create operator = (
|
||||
procedure = macaddr_eq
|
||||
);
|
||||
|
||||
create operator >= (
|
||||
leftarg = macaddr,
|
||||
rightarg = macaddr,
|
||||
negator = <,
|
||||
procedure = macaddr_ge
|
||||
);
|
||||
|
||||
create operator > (
|
||||
leftarg = macaddr,
|
||||
rightarg = macaddr,
|
||||
negator = <=,
|
||||
procedure = macaddr_gt
|
||||
);
|
||||
|
||||
create operator <> (
|
||||
leftarg = macaddr,
|
||||
rightarg = macaddr,
|
||||
commutator = <>,
|
||||
negator = =,
|
||||
procedure = macaddr_ne
|
||||
);
|
||||
|
||||
create operator ~~ (
|
||||
leftarg = macaddr,
|
||||
rightarg = macaddr,
|
||||
commutator = ~~,
|
||||
procedure = macaddr_like
|
||||
);
|
||||
|
||||
--
|
||||
-- Finally, the special manufacurer matching function:
|
||||
--
|
||||
|
71
contrib/ip_and_mac/test.sql
Normal file
71
contrib/ip_and_mac/test.sql
Normal file
@ -0,0 +1,71 @@
|
||||
--
|
||||
-- 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
|
||||
--
|
Loading…
Reference in New Issue
Block a user