OSDN Git Service

I'm including an update to my user defined IP and MAC address type
authorMarc G. Fournier <scrappy@hub.org>
Sat, 14 Feb 1998 17:58:09 +0000 (17:58 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Sat, 14 Feb 1998 17:58:09 +0000 (17:58 +0000)
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>

contrib/ip_and_mac/Makefile
contrib/ip_and_mac/README
contrib/ip_and_mac/ip.c
contrib/ip_and_mac/ip.sql
contrib/ip_and_mac/mac.c
contrib/ip_and_mac/mac.h
contrib/ip_and_mac/mac.sql
contrib/ip_and_mac/test.sql [new file with mode: 0644]

index 924a200..773fdc2 100644 (file)
@@ -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
+#
index a2da4fc..efa400f 100644 (file)
@@ -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.
-
-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.
-
-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
+<=, =, >=, > 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 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.
+
+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).
index de967aa..d941c26 100644 (file)
@@ -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>
  */
 
 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,48 +158,59 @@ 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_like(ipaddr *a1, ipaddr *a2) {
-  unsigned long a1bits, a2bits, maskbits;
-  if ((a1->w == 0) || (a2->w == 0))
+bool ipaddr_in_net(ipaddr *a1, ipaddr *a2) {
+  uint32 maskbits;
+  if (a1->width < a2->width)
     return FALSE;
-  if ((a1->w == 32) && (a2->w == 32))
+  if ((a1->width == 32) && (a2->width == 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));
-  }
+  maskbits = build_mask(a2->width);
+  if ((a1->address & maskbits) == (a2->address & maskbits))
+    return TRUE;
   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
  */
index bcfe1a2..d5a695b 100644 (file)
@@ -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,20 +83,18 @@ create function ipaddr_like(ipaddr, ipaddr)
 --     will be implicitly defined when those are, further down.
 --
 
-create operator <= (
+create operator < (
        leftarg = ipaddr,
        rightarg = ipaddr,
---     commutator = >,
---     negator = >,
-       procedure = ipaddr_le
+--     negator = >=,
+       procedure = ipaddr_lt
 );
 
-create operator < (
+create operator <= (
        leftarg = ipaddr,
        rightarg = ipaddr,
---     commutator = >=,
---     negator = >=,
-       procedure = ipaddr_lt
+--     negator = >,
+       procedure = ipaddr_le
 );
 
 create operator = (
@@ -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
 --
index 3317eab..34aed59 100644 (file)
@@ -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,38 +159,19 @@ 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".
  */
 
index 39f12d8..27c4c1e 100644 (file)
@@ -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 {
index 9e5ec61..47c6b81 100644 (file)
@@ -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,38 +21,67 @@ 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_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
        as '/usr/local/pgsql/modules/mac.so'
        language 'c';
 
-create function macaddr_like(macaddr, macaddr)
+create function macaddr_ne(macaddr, macaddr)
        returns bool
        as '/usr/local/pgsql/modules/mac.so'
        language 'c';
 
 --
---     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.
+--     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 = macaddr,
+       rightarg = macaddr,
+--     negator = >=,
+       procedure = macaddr_lt
+);
+
+create operator <= (
+       leftarg = macaddr,
+       rightarg = macaddr,
+--     negator = >,
+       procedure = macaddr_le
+);
+
 create operator = (
        leftarg = macaddr,
        rightarg = macaddr,
@@ -59,19 +90,25 @@ create operator = (
        procedure = macaddr_eq
 );
 
-create operator <> (
+create operator >= (
        leftarg = macaddr,
        rightarg = macaddr,
-       commutator = <>,
-       negator = =,
-       procedure = macaddr_ne
+       negator = <,
+       procedure = macaddr_ge
+);
+
+create operator > (
+       leftarg = macaddr,
+       rightarg = macaddr,
+       negator = <=,
+       procedure = macaddr_gt
 );
 
-create operator ~~ (
+create operator <> (
        leftarg = macaddr,
        rightarg = macaddr,
-       commutator = ~~,
-       procedure = macaddr_like
+       negator = =,
+       procedure = macaddr_ne
 );
 
 --
diff --git a/contrib/ip_and_mac/test.sql b/contrib/ip_and_mac/test.sql
new file mode 100644 (file)
index 0000000..296e1eb
--- /dev/null
@@ -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
+--