diff --git a/contrib/ip_and_mac/Makefile b/contrib/ip_and_mac/Makefile
index 924a20029e41660775634477b85e1224c26fa759..773fdc24f9c70dd79b50c26b08bdcd8d00b95be5 100644
--- a/contrib/ip_and_mac/Makefile
+++ b/contrib/ip_and_mac/Makefile
@@ -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
+#
diff --git a/contrib/ip_and_mac/README b/contrib/ip_and_mac/README
index a2da4fc46d525a59775f1ed55ba9eaa60b720571..efa400fc7dbaadd0f3b5e8af0beef304aac6db53 100644
--- a/contrib/ip_and_mac/README
+++ b/contrib/ip_and_mac/README
@@ -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).
diff --git a/contrib/ip_and_mac/ip.c b/contrib/ip_and_mac/ip.c
index de967aa8eda722c4e5fd2079aa103a0da327952a..d941c26742fab481ff19742bc770f2d7984afbb6 100644
--- a/contrib/ip_and_mac/ip.c
+++ b/contrib/ip_and_mac/ip.c
@@ -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,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
  */
diff --git a/contrib/ip_and_mac/ip.sql b/contrib/ip_and_mac/ip.sql
index bcfe1a24d90ff8a7f7a800f77854180beb0930d3..d5a695b6912bfd6d09256d315cc0c3b1c984db45 100644
--- a/contrib/ip_and_mac/ip.sql
+++ b/contrib/ip_and_mac/ip.sql
@@ -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
 --
diff --git a/contrib/ip_and_mac/mac.c b/contrib/ip_and_mac/mac.c
index 3317eab24eb0453b8b254abe0164bc39f8b0b995..34aed59267414cfa65dc90bc6665582dc2933fea 100644
--- a/contrib/ip_and_mac/mac.c
+++ b/contrib/ip_and_mac/mac.c
@@ -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".
  */
diff --git a/contrib/ip_and_mac/mac.h b/contrib/ip_and_mac/mac.h
index 39f12d83bb3d90e3f43912475368c4534cc27c99..27c4c1ec27811002211983ae6394483e82d0ad0b 100644
--- a/contrib/ip_and_mac/mac.h
+++ b/contrib/ip_and_mac/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 {
diff --git a/contrib/ip_and_mac/mac.sql b/contrib/ip_and_mac/mac.sql
index 9e5ec61277bd868775082ffbfe4dcbbfc251305c..47c6b811c9beb6579b91c1aa5781b61512149c92 100644
--- a/contrib/ip_and_mac/mac.sql
+++ b/contrib/ip_and_mac/mac.sql
@@ -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
index 0000000000000000000000000000000000000000..296e1ebe947759985127c3bc949231e9f348169e
--- /dev/null
+++ b/contrib/ip_and_mac/test.sql
@@ -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
+--