Обсуждение: CIDR/IP types. Was: [GENERAL] big numbers

Поиск
Список
Период
Сортировка

CIDR/IP types. Was: [GENERAL] big numbers

От
Tom Ivar Helbekkmo
Дата:
Bruce Momjian <maillist@candle.pha.pa.us> writes:

> The person who said they were going to work on the IP type has not
> responded to my requests for a status, and nothing has been added in
> that area in 6.4.

That would be me.  What I said was that it looked like the thing to do
was to pick the best ideas the three implementations available, and
that I, at least, would be doing that for my local needs.  I still
plan to do that, but having recently become a father for the first
time, and having lots of projects going at work, I haven't found time
yet.  Unless someone beats me to it, I will be doing this soon, and
probably within the next couple of weeks, but obviously not in time
for the 6.4 beta period.  Besides, I have no idea how to integrate a
new type as a built-in type, so someone else would have to do that.

-tih
--
Popularity is the hallmark of mediocrity.  --Niles Crane, "Frasier"

Re: CIDR/IP types. Was: [GENERAL] big numbers]

От
Bruce Momjian
Дата:
> Bruce Momjian <maillist@candle.pha.pa.us> writes:
>
> > The person who said they were going to work on the IP type has not
> > responded to my requests for a status, and nothing has been added in
> > that area in 6.4.
>
> That would be me.  What I said was that it looked like the thing to do
> was to pick the best ideas the three implementations available, and
> that I, at least, would be doing that for my local needs.  I still
> plan to do that, but having recently become a father for the first
> time, and having lots of projects going at work, I haven't found time
> yet.  Unless someone beats me to it, I will be doing this soon, and
> probably within the next couple of weeks, but obviously not in time
> for the 6.4 beta period.  Besides, I have no idea how to integrate a
> new type as a built-in type, so someone else would have to do that.

I would be glad to help with integrating it.  We need a decision,
people.  Who do we want to do this, and how are we going to handle
integrating this into the beta, if we want to?

BTW, does pg_upgrade work for people.  That may be a quick fix for the
beta people to get these new system types WITHOUT dump/reload.


--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers]

От
"Thomas G. Lockhart"
Дата:
> I would be glad to help with integrating it.  We need a decision,
> people.  Who do we want to do this, and how are we going to handle
> integrating this into the beta, if we want to?
>
> BTW, does pg_upgrade work for people.  That may be a quick fix for the
> beta people to get these new system types WITHOUT dump/reload.

Better yet, they _should_ use pg_upgrade, so it gets some beta testing
too :)

I can help with making the types built-in, once there is code ready.
However, until we finish tracking down the indexing problems I'd like to
stay away from unrelated changes to the catalogs and backend code to
avoid confusing the issue.

Now that I think about it, that would have probably included the
snprintf changes, since now people trying to do debugging may not be
able to build with a new tree until that gets integrated...

                     - Tom

Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers]

От
The Hermit Hacker
Дата:
On Fri, 4 Sep 1998, Thomas G. Lockhart wrote:

> > I would be glad to help with integrating it.  We need a decision,
> > people.  Who do we want to do this, and how are we going to handle
> > integrating this into the beta, if we want to?
> >
> > BTW, does pg_upgrade work for people.  That may be a quick fix for the
> > beta people to get these new system types WITHOUT dump/reload.
>
> Better yet, they _should_ use pg_upgrade, so it gets some beta testing
> too :)
>
> I can help with making the types built-in, once there is code ready.
> However, until we finish tracking down the indexing problems I'd like to
> stay away from unrelated changes to the catalogs and backend code to
> avoid confusing the issue.
>
> Now that I think about it, that would have probably included the
> snprintf changes, since now people trying to do debugging may not be
> able to build with a new tree until that gets integrated...

    I'm going to be spending this afternoon on one of my Solaris 2.5.1
machines making sure that it does compile...I have to do an upgrade here
anyway :)  Well, not "here", but at work...


Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers]

От
Bruce Momjian
Дата:
> > I would be glad to help with integrating it.  We need a decision,
> > people.  Who do we want to do this, and how are we going to handle
> > integrating this into the beta, if we want to?
> >
> > BTW, does pg_upgrade work for people.  That may be a quick fix for the
> > beta people to get these new system types WITHOUT dump/reload.
>
> Better yet, they _should_ use pg_upgrade, so it gets some beta testing
> too :)
>
> I can help with making the types built-in, once there is code ready.
> However, until we finish tracking down the indexing problems I'd like to
> stay away from unrelated changes to the catalogs and backend code to
> avoid confusing the issue.
>
> Now that I think about it, that would have probably included the
> snprintf changes, since now people trying to do debugging may not be
> able to build with a new tree until that gets integrated...

Yes, we are definately on hold until the indexing this is fixed.

--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Bruce Momjian
Дата:
> Bruce Momjian <maillist@candle.pha.pa.us> writes:
>
> > The person who said they were going to work on the IP type has not
> > responded to my requests for a status, and nothing has been added in
> > that area in 6.4.
>
> That would be me.  What I said was that it looked like the thing to do
> was to pick the best ideas the three implementations available, and
> that I, at least, would be doing that for my local needs.  I still
> plan to do that, but having recently become a father for the first
> time, and having lots of projects going at work, I haven't found time
> yet.  Unless someone beats me to it, I will be doing this soon, and
> probably within the next couple of weeks, but obviously not in time
> for the 6.4 beta period.  Besides, I have no idea how to integrate a
> new type as a built-in type, so someone else would have to do that.

Tom, Paul Vixie has said he can work on it, and in fact he already sent
in his version a month ago.  I just had a baby three months ago, so I
know how busy you must be.

Unfortunately, there are few people who can integrate Paul's stuff with
the current ip_and_mac code, to get the best of both.  I would hate to
throw out the ip_and_mac stuff without knowing if it has certain
advantages over his in certain areas.

I can take care of putting the code into the main PostgreSQL system, but
I need someone to give me a definitive cidr/ip type that I can
integrate.

People really want this for 6.4.  We are in beta, but we can add this
type IF we can get it integrated within the next week or ten days.

When do you think you can you look over both versions, and send me one
good version to work with?

I can take it from there, and Paul and I can work out any bugs in the
code.

Even if you just say, "Paul's is better, throw out ip_and_mac", that is
all we need.

--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Paul A Vixie
Дата:
> I can take care of putting the code into the main PostgreSQL system, but
> I need someone to give me a definitive cidr/ip type that I can
> integrate.
>
> People really want this for 6.4.  We are in beta, but we can add this
> type IF we can get it integrated within the next week or ten days.
>
> When do you think you can you look over both versions, and send me one
> good version to work with?
>
> I can take it from there, and Paul and I can work out any bugs in the
> code.
>
> Even if you just say, "Paul's is better, throw out ip_and_mac", that is
> all we need.

i don't think it's that clear cut.  my type is intended for layer 3
applications (IP) where either hosts or networks (or subnets including
variable-width subnets) need to be used as keys.  the ip_and_mac type
is host-only but has an unfortunate bridging between layer 3 and layer 2.
in my opinion these are separate types, and since cidr is ready to go in
we ought to defer ip_and_mac to 6.5, and refocus it on layer 2 applications.

consider an ARP or DHCP table, which maps between layer 3 and layer 2.
having a type optimized for layer 3 and a different type optimized for
layer 2 creates no ugliness in my mind, and in fact serves the only need
i can imagine better than a single multihedral type would do.

note that cidr as supplied is capable of holding ipv6, which is also a
layer 3 entity.  changing the name from CIDR to INET would be ok by me,
but making a type which is capable of holding either a layer 3 entity
or a layer 2 one would create semantic tension in my mind about it.

Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
The Hermit Hacker
Дата:
On Fri, 4 Sep 1998, Bruce Momjian wrote:

> Unfortunately, there are few people who can integrate Paul's stuff with
> the current ip_and_mac code, to get the best of both.  I would hate to
> throw out the ip_and_mac stuff without knowing if it has certain
> advantages over his in certain areas.

    Can we integrate Paul's CIDR type to give us the base, leave the
ip_and_mac stuff in contrib and then once Tom has a spare moment between
feedings *grin* we can get what is in the ip_and_mac stuff integrated?

> Even if you just say, "Paul's is better, throw out ip_and_mac", that is
> all we need.

    That woudn't be wise...Paul's stuff focuses on the ip aspect of
ip_and_mac, not the the _and_mac part, which I feel to be as valuable,
especially in a DHCP environment :)



Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Michael Meskes
Дата:
On Fri, Sep 04, 1998 at 02:15:55PM -0400, Bruce Momjian wrote:
> > plan to do that, but having recently become a father for the first

Congrats Mark. How do you feel getting up each night? :-)

> Tom, Paul Vixie has said he can work on it, and in fact he already sent
> in his version a month ago.  I just had a baby three months ago, so I
> know how busy you must be.

Oops, missed that. Congrats to you also, Bruce.

Michael
--
Michael Meskes            meskes@online-club.de, meskes@debian.org
Go SF49ers! Go Rhein Fire!    Use Debian GNU/Linux!

Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Tom Ivar Helbekkmo
Дата:
Bruce Momjian wrote:

> When do you think you can you look over both versions, and send me
> one good version to work with?

I've got something working right now, by taking what I was using, and
changing it to work the way Paul's code does, with some enhancements:
My code is ready for storing both IPV4 and IPV6 at the same time with
variable length storage in the data base, and it's got Aleksei's index
integration in place.  The type name is still "ipaddr" -- but that's
easy to change, of course.

> Even if you just say, "Paul's is better, throw out ip_and_mac", that
> is all we need.

I am definitely *not* going to say "I can do this better than Vixie".

The way I feel about this right now is that Paul's code is better than
what I originally submitted, and better than Aleksei's improvements on
that code.  However, what I currently run has certain improvements
over all of those versions, and I kind of like the way it's going...

I'll append it below.  Take a look, and let me know what you think.

Oh, and a correction:  Paul Vixie wrote:

> the ip_and_mac type is host-only but has an unfortunate bridging
> between layer 3 and layer 2.

No, it was (and is) two different types, just packaged in the same
directory because I thought they conceptually belonged together.

Anyway, I'm appending a shar of what I've got right now.  It's only
minimally tested so far, and I'm *not* a professional programmer.
I'm basically just having a lot of fun with this, while it is at the
same time useful for me in my work, and if what I write can be of use
to others, that's great!  :-)

-tih
--
Popularity is the hallmark of mediocrity.  --Niles Crane, "Frasier"

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#    Makefile
#    README
#    inet_net_ntop.c
#    inet_net_pton.c
#    ip.c
#    ip.sql.in
#    mac.c
#    mac.h
#    mac.sql.in
#    test.sql
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
X#
X#    PostgreSQL types for IP and MAC addresses
X#
X#    $Id: Makefile,v 1.4 1998/09/08 12:23:30 tih Exp $
X
XPGINST=/usr/local/pgsql
XTARGET=/u/tih/databases
X
Xall: ip.so mac.so ip.sql mac.sql
X
Xip.so: ip.o inet_net_ntop.o inet_net_pton.o
X    ld -Bshareable -o ip.so ip.o inet_net_ntop.o inet_net_pton.o
X
Xip.o: ip.c
X    cc -g -O -fPIC -I${PGINST}/include -c ip.c
X
Xinet_net_ntop.o: inet_net_ntop.c
X    cc -g -O -fPIC -c inet_net_ntop.c
X
Xinet_net_pton.o: inet_net_pton.c
X    cc -g -O -fPIC -c inet_net_pton.c
X
Xmac.so: mac.o
X    ld -Bshareable -o mac.so mac.o
X
Xmac.o: mac.c mac.h
X    cc -g -O -fPIC -I${PGINST}/include -c mac.c
X
Xip.sql: ip.sql.in
X    cat ip.sql.in | sed s@TARGET@${TARGET}/modules@ > ip.sql
X
Xmac.sql: mac.sql.in
X    cat mac.sql.in | sed s@TARGET@${TARGET}/modules@ > mac.sql
X
Xinstall: ip.so mac.so
X    install -c ip.sql ip.so mac.sql mac.so ${TARGET}/modules
X
Xclean:
X    rm -f *.o *.so ip.sql mac.sql
X
XFILES=Makefile README inet_net_ntop.c inet_net_pton.c \
X    ip.c ip.sql.in mac.c mac.h mac.sql.in test.sql
X
Xip+mac.shar: ${FILES}
X    shar ${FILES} > ip+mac.shar
X
X#
X#    eof
X#
END-of-Makefile
echo x - README
sed 's/^X//' >README << 'END-of-README'
XPostgreSQL type extensions for IP and MAC addresses.
X---------------------------------------------------
X
X$Id: README,v 1.2 1998/09/08 12:10:22 tih Exp $
X
XI needed to record IP and MAC level ethernet addresses in a data
Xbase, and I really didn't want to store them as plain strings, with
Xno enforced error checking, so I put together the accompanying code
Xas my first experiment with adding a data type to PostgreSQL.  I
Xthen thought that this might be useful to others, both directly and
Xas a very simple example of how to do this sort of thing, so I
Xsubmitted it to the PostgreSQL project for inclusion in the contrib
Xdirectory.  Since then, that directory has been modified to contain
XAleksei Roudnev's implementation, which is based on mine.
X
XFor those who have seen my previous contribution of these types, note
Xthat much has changed: I've modified the IP address type to work the
Xway Paul Vixie did with his CIDR type.  In fact, I've pretty much just
Xstolen his solution, modifying it into my framework in such a way as
Xto facilitate the addition of IPV6 handling code in the future.  I've
Xpretty much ignored Aleksei's C code, but I've added his SQL code to
Xenter the necessary operators into the various system tables needed to
Xmake the types indexable.
X
XIP addresses are implemented as a struct of fixed in-memory length,
Xbut variable on-disk storage size.  For IPV4, it contains the address
Xfamily (AF_INET), the CIDR prefix length and four byte address.  For
XIPV6, the address family will be different, and the address longer.
X
XThe external representation of an IP address generally looks like
X'158.37.96.15/32'.  This address happens to be part of a subnet where
XI work; '158.37.96.0/24', which itself is a part of the larger subnet
Xallocated to our site, which is '158.37.96.0/21', which again, if you
Xgo by the old book, is part of the class "B" net '158.37.0.0/16'.
X
XInput and output functions are supplied, along with the "normal" <,
X<=, =, >=, > and <> operators, which all do what you expect.  In
Xaddition, there are operators to check for networks or addresses being
Xsubnets of or addresses contained within other networks.  << tests
Xwhether the left operand is contained within the right, <<= includes
Xequality, >> and >>= do the same things the opposite way.
X
XThe input and output functions use routines from Paul Vixie's BIND,
Xand I've snarfed the source files inet_net_ntop.c and inet_net_pton.c
Xdirectly from a recent distribution of that code.  They are included
Xhere to avoid the need to fetch and install the BIND libraries to be
Xable to use this code.  IANAL, but it looks from the copyright
Xmessages in the files as if this should be acceptable.  Read the
Xdocumentation in inet_net_pton.c to see the legal input formats.
X
XMAC level ethernet addresses are implemented as a 6 byte struct that
Xcontains the address as unsigned chars.  Several input forms are
Xaccepted; the following are all the same address: '08002b:010203',
X'08002b-010203', '0800.2b01.0203', '08-00-2b-01-02-03' and
X'08:00:2b:01:02:03'.  Upper and lower case is accepted for the digits
X'a' through 'f'.  Output is always in the latter of the given forms.
X
XAs with IP addresses, input and output functions are supplied as well
Xas the "normal" operators, which do what you expect.  As an extra
Xfeature, a function macaddr_manuf() is defined, which returns the name
Xof the manufacturer as a string.  This is currently held in a
Xhard-coded struct internal to the C module -- it might be smarter to
Xput this information into an actual data base table, and look up the
Xmanufacturer there.
X
XMany thanks to Aleksei Roudnev and Paul Vixie for their fine work!
X
XI don't know what changes are needed to the Makefile for other systems
Xthan the one I'm running (NetBSD 1.3), but anyway: to install on a BSD
Xsystem: fix the path names in the Makefile if you need to, then make,
Xmake install, slurp the SQL files into psql or whatever, and you're
Xoff.  Enjoy!
X
XBergen, Norway, 1998-08-09, Tom Ivar Helbekkmo (tih@nhh.no).
END-of-README
echo x - inet_net_ntop.c
sed 's/^X//' >inet_net_ntop.c << 'END-of-inet_net_ntop.c'
X/*
X * Copyright (c) 1996 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic const char rcsid[] = "$Id: inet_net_ntop.c,v 8.2 1996/08/08 06:54:44 vixie Exp $";
X#endif
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X
X#ifdef SPRINTF_CHAR
X# define SPRINTF(x) strlen(sprintf/**/x)
X#else
X# define SPRINTF(x) ((size_t)sprintf x)
X#endif
X
Xstatic char *    inet_net_ntop_ipv4 __P((const u_char *src, int bits,
X                    char *dst, size_t size));
X
X/*
X * char *
X * inet_net_ntop(af, src, bits, dst, size)
X *    convert network number from network to presentation format.
X *    generates CIDR style result always.
X * return:
X *    pointer to dst, or NULL if an error occurred (check errno).
X * author:
X *    Paul Vixie (ISC), July 1996
X */
Xchar *
Xinet_net_ntop(af, src, bits, dst, size)
X    int af;
X    const void *src;
X    int bits;
X    char *dst;
X    size_t size;
X{
X    switch (af) {
X    case AF_INET:
X        return (inet_net_ntop_ipv4(src, bits, dst, size));
X    default:
X        errno = EAFNOSUPPORT;
X        return (NULL);
X    }
X}
X
X/*
X * static char *
X * inet_net_ntop_ipv4(src, bits, dst, size)
X *    convert IPv4 network number from network to presentation format.
X *    generates CIDR style result always.
X * return:
X *    pointer to dst, or NULL if an error occurred (check errno).
X * note:
X *    network byte order assumed.  this means 192.5.5.240/28 has
X *    0x11110000 in its fourth octet.
X * author:
X *    Paul Vixie (ISC), July 1996
X */
Xstatic char *
Xinet_net_ntop_ipv4(src, bits, dst, size)
X    const u_char *src;
X    int bits;
X    char *dst;
X    size_t size;
X{
X    char *odst = dst;
X    char *t;
X    u_int m;
X    int b;
X
X    if (bits < 0 || bits > 32) {
X        errno = EINVAL;
X        return (NULL);
X    }
X    if (bits == 0) {
X        if (size < sizeof "0")
X            goto emsgsize;
X        *dst++ = '0';
X        *dst = '\0';
X    }
X
X    /* Format whole octets. */
X    for (b = bits / 8; b > 0; b--) {
X        if (size < sizeof "255.")
X            goto emsgsize;
X        t = dst;
X        dst += SPRINTF((dst, "%u", *src++));
X        if (b > 1) {
X            *dst++ = '.';
X            *dst = '\0';
X        }
X        size -= (size_t)(dst - t);
X    }
X
X    /* Format partial octet. */
X    b = bits % 8;
X    if (b > 0) {
X        if (size < sizeof ".255")
X            goto emsgsize;
X        t = dst;
X        if (dst != odst)
X            *dst++ = '.';
X        m = ((1 << b) - 1) << (8 - b);
X        dst += SPRINTF((dst, "%u", *src & m));
X        size -= (size_t)(dst - t);
X    }
X
X    /* Format CIDR /width. */
X    if (size < sizeof "/32")
X        goto emsgsize;
X    dst += SPRINTF((dst, "/%u", bits));
X    return (odst);
X
X emsgsize:
X    errno = EMSGSIZE;
X    return (NULL);
X}
END-of-inet_net_ntop.c
echo x - inet_net_pton.c
sed 's/^X//' >inet_net_pton.c << 'END-of-inet_net_pton.c'
X/*
X * Copyright (c) 1996 by Internet Software Consortium.
X *
X * Permission to use, copy, modify, and distribute this software for any
X * purpose with or without fee is hereby granted, provided that the above
X * copyright notice and this permission notice appear in all copies.
X *
X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic const char rcsid[] = "$Id: inet_net_pton.c,v 8.3 1996/11/11 06:36:52 vixie Exp $";
X#endif
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#include <assert.h>
X#include <ctype.h>
X#include <errno.h>
X#include <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X
X#ifdef SPRINTF_CHAR
X# define SPRINTF(x) strlen(sprintf/**/x)
X#else
X# define SPRINTF(x) ((size_t)sprintf x)
X#endif
X
Xstatic int    inet_net_pton_ipv4 __P((const char *src, u_char *dst,
X                    size_t size));
X
X/*
X * static int
X * inet_net_pton(af, src, dst, size)
X *    convert network number from presentation to network format.
X *    accepts hex octets, hex strings, decimal octets, and /CIDR.
X *    "size" is in bytes and describes "dst".
X * return:
X *    number of bits, either imputed classfully or specified with /CIDR,
X *    or -1 if some failure occurred (check errno).  ENOENT means it was
X *    not a valid network specification.
X * author:
X *    Paul Vixie (ISC), June 1996
X */
Xint
Xinet_net_pton(af, src, dst, size)
X    int af;
X    const char *src;
X    void *dst;
X    size_t size;
X{
X    switch (af) {
X    case AF_INET:
X        return (inet_net_pton_ipv4(src, dst, size));
X    default:
X        errno = EAFNOSUPPORT;
X        return (-1);
X    }
X}
X
X/*
X * static int
X * inet_net_pton_ipv4(src, dst, size)
X *    convert IPv4 network number from presentation to network format.
X *    accepts hex octets, hex strings, decimal octets, and /CIDR.
X *    "size" is in bytes and describes "dst".
X * return:
X *    number of bits, either imputed classfully or specified with /CIDR,
X *    or -1 if some failure occurred (check errno).  ENOENT means it was
X *    not an IPv4 network specification.
X * note:
X *    network byte order assumed.  this means 192.5.5.240/28 has
X *    0x11110000 in its fourth octet.
X * author:
X *    Paul Vixie (ISC), June 1996
X */
Xstatic int
Xinet_net_pton_ipv4(src, dst, size)
X    const char *src;
X    u_char *dst;
X    size_t size;
X{
X    static const char
X        xdigits[] = "0123456789abcdef",
X        digits[] = "0123456789";
X    int n, ch, tmp, dirty, bits;
X    const u_char *odst = dst;
X
X    ch = *src++;
X    if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
X        && isascii(src[1]) && isxdigit(src[1])) {
X        /* Hexadecimal: Eat nybble string. */
X        if (size <= 0)
X            goto emsgsize;
X        *dst = 0, dirty = 0;
X        src++;    /* skip x or X. */
X        while ((ch = *src++) != '\0' &&
X               isascii(ch) && isxdigit(ch)) {
X            if (isupper(ch))
X                ch = tolower(ch);
X            n = strchr(xdigits, ch) - xdigits;
X            assert(n >= 0 && n <= 15);
X            *dst |= n;
X            if (!dirty++)
X                *dst <<= 4;
X            else if (size-- > 0)
X                *++dst = 0, dirty = 0;
X            else
X                goto emsgsize;
X        }
X        if (dirty)
X            size--;
X    } else if (isascii(ch) && isdigit(ch)) {
X        /* Decimal: eat dotted digit string. */
X        for (;;) {
X            tmp = 0;
X            do {
X                n = strchr(digits, ch) - digits;
X                assert(n >= 0 && n <= 9);
X                tmp *= 10;
X                tmp += n;
X                if (tmp > 255)
X                    goto enoent;
X            } while ((ch = *src++) != '\0' &&
X                 isascii(ch) && isdigit(ch));
X            if (size-- <= 0)
X                goto emsgsize;
X            *dst++ = (u_char) tmp;
X            if (ch == '\0' || ch == '/')
X                break;
X            if (ch != '.')
X                goto enoent;
X            ch = *src++;
X            if (!isascii(ch) || !isdigit(ch))
X                goto enoent;
X        }
X    } else
X        goto enoent;
X
X    bits = -1;
X    if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
X        /* CIDR width specifier.  Nothing can follow it. */
X        ch = *src++;    /* Skip over the /. */
X        bits = 0;
X        do {
X            n = strchr(digits, ch) - digits;
X            assert(n >= 0 && n <= 9);
X            bits *= 10;
X            bits += n;
X        } while ((ch = *src++) != '\0' &&
X             isascii(ch) && isdigit(ch));
X        if (ch != '\0')
X            goto enoent;
X        if (bits > 32)
X            goto emsgsize;
X    }
X
X    /* Firey death and destruction unless we prefetched EOS. */
X    if (ch != '\0')
X        goto enoent;
X
X    /* If nothing was written to the destination, we found no address. */
X    if (dst == odst)
X        goto enoent;
X    /* If no CIDR spec was given, infer width from net class. */
X    if (bits == -1) {
X        if (*odst >= 240)    /* Class E */
X            bits = 32;
X        else if (*odst >= 224)    /* Class D */
X            bits = 4;
X        else if (*odst >= 192)    /* Class C */
X            bits = 24;
X        else if (*odst >= 128)    /* Class B */
X            bits = 16;
X        else            /* Class A */
X            bits = 8;
X        /* If imputed mask is narrower than specified octets, widen. */
X        if (bits >= 8 && bits < ((dst - odst) * 8))
X            bits = (dst - odst) * 8;
X    }
X    /* Extend network to cover the actual mask. */
X    while (bits > ((dst - odst) * 8)) {
X        if (size-- <= 0)
X            goto emsgsize;
X        *dst++ = '\0';
X    }
X    return (bits);
X
X enoent:
X    errno = ENOENT;
X    return (-1);
X
X emsgsize:
X    errno = EMSGSIZE;
X    return (-1);
X}
END-of-inet_net_pton.c
echo x - ip.c
sed 's/^X//' >ip.c << 'END-of-ip.c'
X/*
X *    PostgreSQL type definitions for IP addresses.  This
X *    is for IP V4 CIDR notation, but prepared for V6: just
X *    add the necessary bits where the comments indicate.
X *
X *    $Id: ip.c,v 1.2 1998/09/08 12:10:36 tih Exp $
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X
X#include <stdio.h>
X#include <errno.h>
X
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#include <postgres.h>
X#include <utils/palloc.h>
X
X/*
X *    This is the internal storage format for IP addresses:
X */
X
Xtypedef struct {
X  unsigned char family;
X  unsigned char bits;
X  union {
X    u_int32_t ipv4_addr;    /* network byte order */
X                /* add IPV6 address type here */
X  } addr;
X} ipaddr_struct;
X
Xtypedef struct varlena ipaddr;
X
X/*
X *    Access macros.  Add IPV6 support.
X */
X
X#define ip_addrsize(ipaddrptr) \
X    (((ipaddr_struct *)VARDATA(ipaddrptr))->family == AF_INET ? 4 : -1)
X
X#define ip_family(ipaddrptr) \
X    (((ipaddr_struct *)VARDATA(ipaddrptr))->family)
X
X#define ip_bits(ipaddrptr) \
X    (((ipaddr_struct *)VARDATA(ipaddrptr))->bits)
X
X#define ip_v4addr(ipaddrptr) \
X    (((ipaddr_struct *)VARDATA(ipaddrptr))->addr.ipv4_addr)
X
X/*
X *    Various forward declarations:
X */
X
Xipaddr *ipaddr_in(char *str);
Xchar *ipaddr_out(ipaddr *addr);
X
Xbool ipaddr_lt(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_le(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_eq(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_ge(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_gt(ipaddr *a1, ipaddr *a2);
X
Xbool ipaddr_ne(ipaddr *a1, ipaddr *a2);
X
Xbool ipaddr_sub(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_subeq(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_sup(ipaddr *a1, ipaddr *a2);
Xbool ipaddr_supeq(ipaddr *a1, ipaddr *a2);
X
Xint4 ipaddr_cmp(ipaddr *a1, ipaddr *a2);
X
Xint v4bitncmp(u_int32_t a1, u_int32_t a2, int bits);
X
X/*
X *    IP address reader.
X */
X
Xipaddr *ipaddr_in(char *src) {
X  int bits;
X  ipaddr *dst;
X
X  dst = palloc(VARHDRSZ + sizeof(ipaddr_struct));
X  if (dst == NULL) {
X    elog(ERROR, "unable to allocate memory in ipaddr_in()");
X    return(NULL);
X  }
X  /* First, try for an IP V4 address: */
X  ip_family(dst) = AF_INET;
X  bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ip_addrsize(dst));
X  if ((bits < 0) || (bits > 32)) {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "could not parse \"%s\"", src);
X    pfree(dst);
X    return(NULL);
X  }
X  VARSIZE(dst) = VARHDRSZ
X    + ((char *)&ip_v4addr(dst) - (char *)VARDATA(dst))
X    + ip_addrsize(dst);
X  ip_bits(dst) = bits;
X  return(dst);
X}
X
X/*
X *    IP address output function.
X */
X
Xchar *ipaddr_out(ipaddr *src) {
X  char *dst, tmp[sizeof("255.255.255.255/32")];
X
X  if (ip_family(src) == AF_INET) {
X    /* It's an IP V4 address: */
X    if (inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
X              tmp, sizeof(tmp)) < 0) {
X      elog(ERROR, "unable to print address (%s)", strerror(errno));
X      return(NULL);
X    }
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "unknown address family (%d)", ip_family(src));
X    return(NULL);
X  }
X  dst = palloc(strlen(tmp) + 1);
X  if (dst == NULL) {
X    elog(ERROR, "unable to allocate memory in ipaddr_out()");
X    return(NULL);
X  }
X  strcpy(dst, tmp);
X  return(dst);
X}
X
X/*
X *    Boolean tests for magnitude.  Add V4/V6 testing!
X */
X
Xbool ipaddr_lt(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
X    return((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
Xbool ipaddr_le(ipaddr *a1, ipaddr *a2) {
X  return(ipaddr_lt(a1, a2) || ipaddr_eq(a1, a2));
X}
X
Xbool ipaddr_eq(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    return((ip_bits(a1) == ip_bits(a2))
X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
Xbool ipaddr_ge(ipaddr *a1, ipaddr *a2) {
X  return(ipaddr_gt(a1, a2) || ipaddr_eq(a1, a2));
X}
X
Xbool ipaddr_gt(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
X    return((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
Xbool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
X  return(!ipaddr_eq(a1, a2));
X}
X
Xbool ipaddr_sub(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    return((ip_bits(a1) > ip_bits(a2))
X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
Xbool ipaddr_subeq(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    return((ip_bits(a1) >= ip_bits(a2))
X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
Xbool ipaddr_sup(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    return((ip_bits(a1) < ip_bits(a2))
X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
Xbool ipaddr_supeq(ipaddr *a1, ipaddr *a2) {
X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
X    return((ip_bits(a1) <= ip_bits(a2))
X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
X  } else {
X    /* Go for an IPV6 address here, before faulting out: */
X    elog(ERROR, "cannot compare address families %d and %d",
X     ip_family(a1), ip_family(a2));
X    return(FALSE);
X  }
X}
X
X/*
X *    Comparison function for sorting.  Add V4/V6 testing!
X */
X
Xint4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) {
X  if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2))) {
X    return(-1);
X  } else if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2))) {
X    return(1);
X  }
X  return 0;
X}
X
X/*
X *    Bitwise comparison for V4 addresses.  Add V6 implementation!
X */
X
Xint v4bitncmp(u_int32_t a1, u_int32_t a2, int bits) {
X  unsigned long mask = 0;
X  int i;
X  for (i = 0; i < bits; i++) {
X    mask = (mask >> 1) | 0x80000000;
X  }
X  a1 = ntohl(a1);
X  a2 = ntohl(a2);
X  if ((a1 & mask) < (a2 & mask)) {
X    return(-1);
X  } else if ((a1 & mask) > (a2 & mask)) {
X    return(1);
X  }
X  return(0);
X}
X
X/*
X *    eof
X */
END-of-ip.c
echo x - ip.sql.in
sed 's/^X//' >ip.sql.in << 'END-of-ip.sql.in'
X--
X--    PostgreSQL code for IP addresses.
X--
X--    $Id: ip.sql.in,v 1.2 1998/09/08 12:10:45 tih Exp $
X--
X
Xload 'TARGET/ip.so';
X
X--
X--    Input and output functions and the type itself:
X--
X
Xcreate function ipaddr_in(opaque)
X    returns opaque
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_out(opaque)
X    returns opaque
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate type ipaddr (
X    internallength = variable,
X    externallength = variable,
X    input = ipaddr_in,
X    output = ipaddr_out
X);
X
X--
X--    The various boolean tests:
X--
X
Xcreate function ipaddr_lt(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_le(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_eq(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_ge(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_gt(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_ne(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_sub(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_subeq(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_sup(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_supeq(ipaddr, ipaddr)
X    returns bool
X    as 'TARGET/ip.so'
X    language 'c';
X
Xcreate function ipaddr_cmp(ipaddr, ipaddr)
X    returns int4
X    as 'TARGET/ip.so'
X    language 'c';
X
X--
X--    Now the operators.  Note how some of the parameters to some
X--    of the 'create operator' commands are commented out.  This
X--    is because they reference as yet undefined operators, and
X--    will be implicitly defined when those are, further down.
X--
X
Xcreate operator < (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X--    negator = >=,
X    restrict = intltsel,
X    join = intltjoinsel,
X    procedure = ipaddr_lt
X);
X
Xcreate operator <= (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X--    negator = >,
X    restrict = intltsel,
X    join = intltjoinsel,
X    procedure = ipaddr_le
X);
X
Xcreate operator = (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    commutator = =,
X--    negator = <>,
X    restrict = eqsel,
X    join = eqjoinsel,
X    procedure = ipaddr_eq
X);
X
Xcreate operator >= (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    negator = <,
X    restrict = intgtsel,
X    join = intgtjoinsel,
X    procedure = ipaddr_ge
X);
X
Xcreate operator > (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    negator = <=,
X    restrict = intgtsel,
X    join = intgtjoinsel,
X    procedure = ipaddr_gt
X);
X
Xcreate operator <> (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    negator = =,
X    restrict = neqsel,
X    join = neqjoinsel,
X    procedure = ipaddr_ne
X);
X
Xcreate operator << (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    procedure = ipaddr_sub
X);
X
Xcreate operator <<= (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    procedure = ipaddr_subeq
X);
X
Xcreate operator >> (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    procedure = ipaddr_sup
X);
X
Xcreate operator >>= (
X    leftarg = ipaddr,
X    rightarg = ipaddr,
X    procedure = ipaddr_supeq
X);
X
X--
X--    Finally, make it possible to do btree indexing on IP addresses.
X--
X
Xbegin;
X
Xcreate table tmp_op (oprname name, opi int2);
X
Xinsert into tmp_op values ('<',  1);
Xinsert into tmp_op values ('<=', 2);
Xinsert into tmp_op values ('=',  3);
Xinsert into tmp_op values ('>=', 4);
Xinsert into tmp_op values ('>',  5);
X
Xdelete from pg_opclass
X    where opcname = 'ipaddr_ops';
X
Xinsert into pg_opclass (opcname, opcdeftype)
X    select 'ipaddr_ops', oid from pg_type
X        where typname = 'ipaddr';
X
Xselect o.oid as opoid, o.oprname
X    into table ipaddr_tmp
X    from pg_operator o, pg_type t
X    where o.oprleft = t.oid and
X          o.oprright = t.oid and
X          t.typname = 'ipaddr';
X
Xinsert into pg_amop (amopid, amopclaid, amopopr, amopstrategy,
X             amopselect, amopnpages)
X    select am.oid, opcl.oid, c.opoid, t.opi,
X            'btreesel'::regproc, 'btreenpage'::regproc
X        from pg_am am, pg_opclass opcl, ipaddr_tmp c, tmp_op t
X        where t.oprname = c.oprname and
X              amname = 'btree' and opcname = 'ipaddr_ops';
X
Xinsert into pg_amproc (amid, amopclaid, amproc, amprocnum)
X    select pgam.oid, opc.oid, prc.oid, '1'::int2
X        from pg_am pgam, pg_opclass opc, pg_proc prc
X        where prc.proname = 'ipaddr_cmp' and
X              pgam.amname = 'btree' and
X              opc.opcname = 'ipaddr_ops';
X
Xdrop table tmp_op;
Xdrop table ipaddr_tmp;
X
Xcommit;
X
X--
X--    eof
X--
END-of-ip.sql.in
echo x - mac.c
sed 's/^X//' >mac.c << 'END-of-mac.c'
X/*
X *    PostgreSQL type definitions for MAC addresses.
X *
X *    $Id: mac.c,v 1.1 1998/09/07 12:31:18 tih Exp $
X */
X
X#include <stdio.h>
X
X#include <postgres.h>
X#include <utils/palloc.h>
X
X#include "mac.h"
X
X/*
X *    This is the internal storage format for MAC addresses:
X */
X
Xtypedef struct macaddr {
X  unsigned char a;
X  unsigned char b;
X  unsigned char c;
X  unsigned char d;
X  unsigned char e;
X  unsigned char f;
X} macaddr;
X
X/*
X *    Various forward declarations:
X */
X
Xmacaddr *macaddr_in(char *str);
Xchar *macaddr_out(macaddr *addr);
X
Xbool macaddr_lt(macaddr *a1, macaddr *a2);
Xbool macaddr_le(macaddr *a1, macaddr *a2);
Xbool macaddr_eq(macaddr *a1, macaddr *a2);
Xbool macaddr_ge(macaddr *a1, macaddr *a2);
Xbool macaddr_gt(macaddr *a1, macaddr *a2);
X
Xbool macaddr_ne(macaddr *a1, macaddr *a2);
X
Xint4 macaddr_cmp(macaddr *a1, macaddr *a2);
X
Xtext *macaddr_manuf(macaddr *addr);
X
X/*
X *    Utility macros used for sorting and comparing:
X */
X
X#define hibits(addr) \
X  ((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c)))
X
X#define lobits(addr) \
X  ((unsigned long)((addr->c<<16)|(addr->e<<8)|(addr->f)))
X
X/*
X *    MAC address reader.  Accepts several common notations.
X */
X
Xmacaddr *macaddr_in(char *str) {
X  int a, b, c, d, e, f;
X  macaddr *result;
X  int count;
X
X  if (strlen(str) > 0) {
X
X    count = sscanf(str, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
X    if (count != 6)
X      count = sscanf(str, "%x-%x-%x-%x-%x-%x", &a, &b, &c, &d, &e, &f);
X    if (count != 6)
X      count = sscanf(str, "%2x%2x%2x:%2x%2x%2x", &a, &b, &c, &d, &e, &f);
X    if (count != 6)
X      count = sscanf(str, "%2x%2x%2x-%2x%2x%2x", &a, &b, &c, &d, &e, &f);
X    if (count != 6)
X      count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x", &a, &b, &c, &d, &e, &f);
X
X    if (count != 6) {
X      elog(ERROR, "macaddr_in: error in parsing \"%s\"", str);
X      return(NULL);
X    }
X
X    if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
X    (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
X    (e < 0) || (e > 255) || (f < 0) || (f > 255)) {
X      elog(ERROR, "macaddr_in: illegal address \"%s\"", str);
X      return(NULL);
X    }
X  } else {
X    a = b = c = d = e = f = 0;    /* special case for missing address */
X  }
X
X  result = (macaddr *)palloc(sizeof(macaddr));
X
X  result->a = a;
X  result->b = b;
X  result->c = c;
X  result->d = d;
X  result->e = e;
X  result->f = f;
X
X  return(result);
X}
X
X/*
X *    MAC address output function.  Fixed format.
X */
X
Xchar *macaddr_out(macaddr *addr) {
X  char *result;
X
X  if (addr == NULL)
X    return(NULL);
X
X  result = (char *)palloc(32);
X
X  if ((hibits(addr) > 0) || (lobits(addr) > 0)) {
X    sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x",
X        addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
X  } else {
X    result[0] = 0;        /* special case for missing address */
X  }
X  return(result);
X}
X
X/*
X *    Boolean tests.
X */
X
Xbool macaddr_lt(macaddr *a1, macaddr *a2) {
X  return((hibits(a1) < hibits(a2)) ||
X     ((hibits(a1) == hibits(a2)) && lobits(a1) < lobits(a2)));
X};
X
Xbool macaddr_le(macaddr *a1, macaddr *a2) {
X  return((hibits(a1) < hibits(a2)) ||
X     ((hibits(a1) == hibits(a2)) && lobits(a1) <= lobits(a2)));
X};
X
Xbool macaddr_eq(macaddr *a1, macaddr *a2) {
X  return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
X};
X
Xbool macaddr_ge(macaddr *a1, macaddr *a2) {
X  return((hibits(a1) > hibits(a2)) ||
X     ((hibits(a1) == hibits(a2)) && lobits(a1) >= lobits(a2)));
X};
X
Xbool macaddr_gt(macaddr *a1, macaddr *a2) {
X  return((hibits(a1) > hibits(a2)) ||
X     ((hibits(a1) == hibits(a2)) && lobits(a1) > lobits(a2)));
X};
X
Xbool macaddr_ne(macaddr *a1, macaddr *a2) {
X  return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
X};
X
X/*
X *    Comparison function for sorting:
X */
X
Xint4 macaddr_cmp(macaddr *a1, macaddr *a2) {
X  if (hibits(a1) < hibits(a2))
X    return -1;
X  else if (hibits(a1) > hibits(a2))
X    return 1;
X  else if (lobits(a1) < lobits(a2))
X    return -1;
X  else if (lobits(a1) > lobits(a2))
X    return 1;
X  else
X    return 0;
X}
X
X/*
X *    The special manufacturer fetching function.  See "mac.h".
X */
X
Xtext *macaddr_manuf(macaddr *addr) {
X  manufacturer *manuf;
X  int length;
X  text *result;
X
X  for (manuf = manufacturers; manuf->name != NULL; manuf++) {
X    if ((manuf->a == addr->a) &&
X    (manuf->b == addr->b) &&
X    (manuf->c == addr->c))
X      break;
X  }
X  if (manuf->name == NULL) {
X    result = palloc(VARHDRSZ + 1);
X    memset(result, 0, VARHDRSZ + 1);
X    VARSIZE(result) = VARHDRSZ + 1;
X  } else {
X    length = strlen(manuf->name) + 1;
X    result = palloc(length + VARHDRSZ);
X    memset(result, 0, length + VARHDRSZ);
X    VARSIZE(result) = length + VARHDRSZ;
X    memcpy(VARDATA(result), manuf->name, length);
X  }
X  return result;
X}
X
X/*
X *    eof
X */
END-of-mac.c
echo x - mac.h
sed 's/^X//' >mac.h << 'END-of-mac.h'
X/*
X *    PostgreSQL type definitions for MAC addresses.
X *
X *    $Id: mac.h,v 1.1 1998/09/07 12:31:22 tih Exp $
X */
X
Xtypedef struct manufacturer {
X  unsigned char a;
X  unsigned char b;
X  unsigned char c;
X  char *name;
X} manufacturer;
X
Xmanufacturer manufacturers[] = {
X  {0x00, 0x00, 0x0C, "Cisco"},
X  {0x00, 0x00, 0x0E, "Fujitsu"},
X  {0x00, 0x00, 0x0F, "NeXT"},
X  {0x00, 0x00, 0x10, "Sytek"},
X  {0x00, 0x00, 0x1D, "Cabletron"},
X  {0x00, 0x00, 0x20, "DIAB"},
X  {0x00, 0x00, 0x22, "Visual Technology"},
X  {0x00, 0x00, 0x2A, "TRW"},
X  {0x00, 0x00, 0x32, "GPT Limited"},
X  {0x00, 0x00, 0x5A, "S & Koch"},
X  {0x00, 0x00, 0x5E, "IANA"},
X  {0x00, 0x00, 0x65, "Network General"},
X  {0x00, 0x00, 0x6B, "MIPS"},
X  {0x00, 0x00, 0x77, "MIPS"},
X  {0x00, 0x00, 0x7A, "Ardent"},
X  {0x00, 0x00, 0x89, "Cayman Systems"},
X  {0x00, 0x00, 0x93, "Proteon"},
X  {0x00, 0x00, 0x9F, "Ameristar Technology"},
X  {0x00, 0x00, 0xA2, "Wellfleet"},
X  {0x00, 0x00, 0xA3, "Network Application Technology"},
X  {0x00, 0x00, 0xA6, "Network General"},
X  {0x00, 0x00, 0xA7, "NCD"},
X  {0x00, 0x00, 0xA9, "Network Systems"},
X  {0x00, 0x00, 0xAA, "Xerox"},
X  {0x00, 0x00, 0xB3, "CIMLinc"},
X  {0x00, 0x00, 0xB7, "Dove Fastnet"},
X  {0x00, 0x00, 0xBC, "Allen-Bradley"},
X  {0x00, 0x00, 0xC0, "Western Digital"},
X  {0x00, 0x00, 0xC5, "Farallon"},
X  {0x00, 0x00, 0xC6, "Hewlett-Packard"},
X  {0x00, 0x00, 0xC8, "Altos"},
X  {0x00, 0x00, 0xC9, "Emulex"},
X  {0x00, 0x00, 0xD7, "Dartmouth College"},
X  {0x00, 0x00, 0xD8, "3Com (?)"},
X  {0x00, 0x00, 0xDD, "Gould"},
X  {0x00, 0x00, 0xDE, "Unigraph"},
X  {0x00, 0x00, 0xE2, "Acer Counterpoint"},
X  {0x00, 0x00, 0xEF, "Alantec"},
X  {0x00, 0x00, 0xFD, "High Level Hardware"},
X  {0x00, 0x01, 0x02, "BBN internal usage"},
X  {0x00, 0x20, 0xAF, "3Com"},
X  {0x00, 0x17, 0x00, "Kabel"},
X  {0x00, 0x80, 0x64, "Wyse Technology"},
X  {0x00, 0x80, 0x2B, "IMAC (?)"},
X  {0x00, 0x80, 0x2D, "Xylogics, Inc."},
X  {0x00, 0x80, 0x8C, "Frontier Software Development"},
X  {0x00, 0x80, 0xC2, "IEEE 802.1 Committee"},
X  {0x00, 0x80, 0xD3, "Shiva"},
X  {0x00, 0xAA, 0x00, "Intel"},
X  {0x00, 0xDD, 0x00, "Ungermann-Bass"},
X  {0x00, 0xDD, 0x01, "Ungermann-Bass"},
X  {0x02, 0x07, 0x01, "Racal InterLan"},
X  {0x02, 0x04, 0x06, "BBN internal usage"},
X  {0x02, 0x60, 0x86, "Satelcom MegaPac"},
X  {0x02, 0x60, 0x8C, "3Com"},
X  {0x02, 0xCF, 0x1F, "CMC"},
X  {0x08, 0x00, 0x02, "3Com"},
X  {0x08, 0x00, 0x03, "ACC"},
X  {0x08, 0x00, 0x05, "Symbolics"},
X  {0x08, 0x00, 0x08, "BBN"},
X  {0x08, 0x00, 0x09, "Hewlett-Packard"},
X  {0x08, 0x00, 0x0A, "Nestar Systems"},
X  {0x08, 0x00, 0x0B, "Unisys"},
X  {0x08, 0x00, 0x11, "Tektronix"},
X  {0x08, 0x00, 0x14, "Excelan"},
X  {0x08, 0x00, 0x17, "NSC"},
X  {0x08, 0x00, 0x1A, "Data General"},
X  {0x08, 0x00, 0x1B, "Data General"},
X  {0x08, 0x00, 0x1E, "Apollo"},
X  {0x08, 0x00, 0x20, "Sun"},
X  {0x08, 0x00, 0x22, "NBI"},
X  {0x08, 0x00, 0x25, "CDC"},
X  {0x08, 0x00, 0x26, "Norsk Data"},
X  {0x08, 0x00, 0x27, "PCS Computer Systems GmbH"},
X  {0x08, 0x00, 0x28, "Texas Instruments"},
X  {0x08, 0x00, 0x2B, "DEC"},
X  {0x08, 0x00, 0x2E, "Metaphor"},
X  {0x08, 0x00, 0x2F, "Prime Computer"},
X  {0x08, 0x00, 0x36, "Intergraph"},
X  {0x08, 0x00, 0x37, "Fujitsu-Xerox"},
X  {0x08, 0x00, 0x38, "Bull"},
X  {0x08, 0x00, 0x39, "Spider Systems"},
X  {0x08, 0x00, 0x41, "DCA Digital Comm. Assoc."},
X  {0x08, 0x00, 0x45, "Xylogics (?)"},
X  {0x08, 0x00, 0x46, "Sony"},
X  {0x08, 0x00, 0x47, "Sequent"},
X  {0x08, 0x00, 0x49, "Univation"},
X  {0x08, 0x00, 0x4C, "Encore"},
X  {0x08, 0x00, 0x4E, "BICC"},
X  {0x08, 0x00, 0x56, "Stanford University"},
X  {0x08, 0x00, 0x58, "DECsystem 20 (?)"},
X  {0x08, 0x00, 0x5A, "IBM"},
X  {0x08, 0x00, 0x67, "Comdesign"},
X  {0x08, 0x00, 0x68, "Ridge"},
X  {0x08, 0x00, 0x69, "Silicon Graphics"},
X  {0x08, 0x00, 0x6E, "Concurrent"},
X  {0x08, 0x00, 0x75, "DDE"},
X  {0x08, 0x00, 0x7C, "Vitalink"},
X  {0x08, 0x00, 0x80, "XIOS"},
X  {0x08, 0x00, 0x86, "Imagen/QMS"},
X  {0x08, 0x00, 0x87, "Xyplex"},
X  {0x08, 0x00, 0x89, "Kinetics"},
X  {0x08, 0x00, 0x8B, "Pyramid"},
X  {0x08, 0x00, 0x8D, "XyVision"},
X  {0x08, 0x00, 0x90, "Retix Inc"},
X  {0x48, 0x44, 0x53, "HDS (?)"},
X  {0x80, 0x00, 0x10, "AT&T"},
X  {0xAA, 0x00, 0x00, "DEC"},
X  {0xAA, 0x00, 0x01, "DEC"},
X  {0xAA, 0x00, 0x02, "DEC"},
X  {0xAA, 0x00, 0x03, "DEC"},
X  {0xAA, 0x00, 0x04, "DEC"},
X  {0x00, 0x00, 0x00, NULL}
X};
X
X/*
X *    eof
X */
END-of-mac.h
echo x - mac.sql.in
sed 's/^X//' >mac.sql.in << 'END-of-mac.sql.in'
X--
X--    PostgreSQL code for MAC addresses.
X--
X--    $Id: mac.sql.in,v 1.2 1998/09/08 12:11:18 tih Exp $
X--
X
Xload 'TARGET/mac.so';
X
X--
X--    Input and output functions and the type itself:
X--
X
Xcreate function macaddr_in(opaque)
X    returns opaque
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_out(opaque)
X    returns opaque
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate type macaddr (
X    internallength = 6,
X    externallength = variable,
X    input = macaddr_in,
X    output = macaddr_out
X);
X
X--
X--    The boolean tests:
X--
X
Xcreate function macaddr_lt(macaddr, macaddr)
X    returns bool
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_le(macaddr, macaddr)
X    returns bool
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_eq(macaddr, macaddr)
X    returns bool
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_ge(macaddr, macaddr)
X    returns bool
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_gt(macaddr, macaddr)
X    returns bool
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_ne(macaddr, macaddr)
X    returns bool
X    as 'TARGET/mac.so'
X    language 'c';
X
Xcreate function macaddr_cmp(macaddr, macaddr)
X    returns int4
X    as 'TARGET/mac.so'
X    language 'c';
X
X--
X--    Now the operators.  Note how some of the parameters to some
X--    of the 'create operator' commands are commented out.  This
X--    is because they reference as yet undefined operators, and
X--    will be implicitly defined when those are, further down.
X--
X
Xcreate operator < (
X    leftarg = macaddr,
X    rightarg = macaddr,
X--    negator = >=,
X    procedure = macaddr_lt
X);
X
Xcreate operator <= (
X    leftarg = macaddr,
X    rightarg = macaddr,
X--    negator = >,
X    procedure = macaddr_le
X);
X
Xcreate operator = (
X    leftarg = macaddr,
X    rightarg = macaddr,
X    commutator = =,
X--    negator = <>,
X    procedure = macaddr_eq
X);
X
Xcreate operator >= (
X    leftarg = macaddr,
X    rightarg = macaddr,
X    negator = <,
X    procedure = macaddr_ge
X);
X
Xcreate operator > (
X    leftarg = macaddr,
X    rightarg = macaddr,
X    negator = <=,
X    procedure = macaddr_gt
X);
X
Xcreate operator <> (
X    leftarg = macaddr,
X    rightarg = macaddr,
X    negator = =,
X    procedure = macaddr_ne
X);
X
X--
X--    Finally, the special manufacurer matching function:
X--
X
Xcreate function macaddr_manuf(macaddr)
X    returns text
X    as 'TARGET/mac.so'
X    language 'c';
X
X--
X--    Finally, make it possible to do btree indexing on MAC addresses.
X--
X
Xbegin;
X
Xcreate table tmp_op (oprname name, opi int2);
X
Xinsert into tmp_op values ('<',  1);
Xinsert into tmp_op values ('<=', 2);
Xinsert into tmp_op values ('=',  3);
Xinsert into tmp_op values ('>=', 4);
Xinsert into tmp_op values ('>',  5);
X
Xdelete from pg_opclass
X    where opcname = 'macaddr_ops';
X
Xinsert into pg_opclass (opcname, opcdeftype)
X    select 'macaddr_ops', oid from pg_type
X        where typname = 'macaddr';
X
Xselect o.oid as opoid, o.oprname
X    into table macaddr_tmp
X    from pg_operator o, pg_type t
X    where o.oprleft = t.oid and
X          o.oprright = t.oid and
X          t.typname = 'macaddr';
X
Xinsert into pg_amop (amopid, amopclaid, amopopr, amopstrategy,
X             amopselect, amopnpages)
X    select am.oid, opcl.oid, c.opoid, t.opi,
X            'btreesel'::regproc, 'btreenpage'::regproc
X        from pg_am am, pg_opclass opcl, macaddr_tmp c, tmp_op t
X        where t.oprname = c.oprname and
X              amname = 'btree' and opcname = 'macaddr_ops';
X
Xinsert into pg_amproc (amid, amopclaid, amproc, amprocnum)
X    select pgam.oid, opc.oid, prc.oid, '1'::int2
X        from pg_am pgam, pg_opclass opc, pg_proc prc
X        where prc.proname = 'macaddr_cmp' and
X              pgam.amname = 'btree' and
X              opc.opcname = 'macaddr_ops';
X
Xdrop table tmp_op;
Xdrop table macaddr_tmp;
X
Xcommit;
X
X--
X--    eof
X--
END-of-mac.sql.in
echo x - test.sql
sed 's/^X//' >test.sql << 'END-of-test.sql'
X--
X--    A quick test of the IP address code
X--
X--    $Id: test.sql,v 1.2 1998/09/08 12:11:34 tih Exp $
X--
X
X-- temporary table:
Xcreate table addresses (address ipaddr);
X
X-- sample data from two subnets:
Xinsert into addresses values ('158.37.96.15');
Xinsert into addresses values ('158.37.96.16');
Xinsert into addresses values ('158.37.96.17');
Xinsert into addresses values ('158.37.97.15');
Xinsert into addresses values ('158.37.97.16');
Xinsert into addresses values ('158.37.97.17');
Xinsert into addresses values ('158.37.98.15');
Xinsert into addresses values ('158.37.98.16');
Xinsert into addresses values ('158.37.98.17');
Xinsert into addresses values ('158.37.96.150');
Xinsert into addresses values ('158.37.96.160');
Xinsert into addresses values ('158.37.96.170');
Xinsert into addresses values ('158.37.97.150');
Xinsert into addresses values ('158.37.97.160');
Xinsert into addresses values ('158.37.97.170');
Xinsert into addresses values ('158.37.98.150');
Xinsert into addresses values ('158.37.98.160');
Xinsert into addresses values ('158.37.98.170');
X
X-- show them all:
Xselect * from addresses;
X
X-- select the ones in subnet 96:
Xselect * from addresses where address << '158.37.96.0/24';
X
X-- select the ones not in subnet 96:
Xselect * from addresses where not address << '158.37.96.0/24';
X
X-- select the ones in subnet 97:
Xselect * from addresses where address << '158.37.97.0/24';
X
X-- select the ones not in subnet 97:
Xselect * from addresses where not address << '158.37.97.0/24';
X
X-- select the ones in subnet 96 or 97, sorted:
Xselect * from addresses where address << '158.37.96.0/23'
X    order by address;
X
X-- now some networks:
Xcreate table networks (network ipaddr);
X
X-- now the subnets mentioned above:
Xinsert into networks values ('158.37.96.0/24');
Xinsert into networks values ('158.37.97.0/24');
Xinsert into networks values ('158.37.98.0/24');
X
X-- select matching pairs of addresses and containing nets:
Xselect address, network from addresses, networks
X    where address << network;
X
X-- tidy up:
Xdrop table addresses;
Xdrop table networks;
X
X--
X--    eof
X--
END-of-test.sql
exit

Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Bruce Momjian
Дата:
Good.  Keep going and let me know when you want it added.  We need to
fix the other problems first before merging your stuff in, so we have
some time.  I assume you are merging Paul's code with your own, to make
a "best of both worlds" group of types.


> Bruce Momjian wrote:
>
> > When do you think you can you look over both versions, and send me
> > one good version to work with?
>
> I've got something working right now, by taking what I was using, and
> changing it to work the way Paul's code does, with some enhancements:
> My code is ready for storing both IPV4 and IPV6 at the same time with
> variable length storage in the data base, and it's got Aleksei's index
> integration in place.  The type name is still "ipaddr" -- but that's
> easy to change, of course.
>
> > Even if you just say, "Paul's is better, throw out ip_and_mac", that
> > is all we need.
>
> I am definitely *not* going to say "I can do this better than Vixie".
>
> The way I feel about this right now is that Paul's code is better than
> what I originally submitted, and better than Aleksei's improvements on
> that code.  However, what I currently run has certain improvements
> over all of those versions, and I kind of like the way it's going...
>
> I'll append it below.  Take a look, and let me know what you think.
>
> Oh, and a correction:  Paul Vixie wrote:
>
> > the ip_and_mac type is host-only but has an unfortunate bridging
> > between layer 3 and layer 2.
>
> No, it was (and is) two different types, just packaged in the same
> directory because I thought they conceptually belonged together.
>
> Anyway, I'm appending a shar of what I've got right now.  It's only
> minimally tested so far, and I'm *not* a professional programmer.
> I'm basically just having a lot of fun with this, while it is at the
> same time useful for me in my work, and if what I write can be of use
> to others, that's great!  :-)
>
> -tih
> --
> Popularity is the hallmark of mediocrity.  --Niles Crane, "Frasier"
>
> # This is a shell archive.  Save it in a file, remove anything before
> # this line, and then unpack it by entering "sh file".  Note, it may
> # create directories; files and directories will be owned by you and
> # have default permissions.
> #
> # This archive contains:
> #
> #    Makefile
> #    README
> #    inet_net_ntop.c
> #    inet_net_pton.c
> #    ip.c
> #    ip.sql.in
> #    mac.c
> #    mac.h
> #    mac.sql.in
> #    test.sql
> #
> echo x - Makefile
> sed 's/^X//' >Makefile << 'END-of-Makefile'
> X#
> X#    PostgreSQL types for IP and MAC addresses
> X#
> X#    $Id: Makefile,v 1.4 1998/09/08 12:23:30 tih Exp $
> X
> XPGINST=/usr/local/pgsql
> XTARGET=/u/tih/databases
> X
> Xall: ip.so mac.so ip.sql mac.sql
> X
> Xip.so: ip.o inet_net_ntop.o inet_net_pton.o
> X    ld -Bshareable -o ip.so ip.o inet_net_ntop.o inet_net_pton.o
> X
> Xip.o: ip.c
> X    cc -g -O -fPIC -I${PGINST}/include -c ip.c
> X
> Xinet_net_ntop.o: inet_net_ntop.c
> X    cc -g -O -fPIC -c inet_net_ntop.c
> X
> Xinet_net_pton.o: inet_net_pton.c
> X    cc -g -O -fPIC -c inet_net_pton.c
> X
> Xmac.so: mac.o
> X    ld -Bshareable -o mac.so mac.o
> X
> Xmac.o: mac.c mac.h
> X    cc -g -O -fPIC -I${PGINST}/include -c mac.c
> X
> Xip.sql: ip.sql.in
> X    cat ip.sql.in | sed s@TARGET@${TARGET}/modules@ > ip.sql
> X
> Xmac.sql: mac.sql.in
> X    cat mac.sql.in | sed s@TARGET@${TARGET}/modules@ > mac.sql
> X
> Xinstall: ip.so mac.so
> X    install -c ip.sql ip.so mac.sql mac.so ${TARGET}/modules
> X
> Xclean:
> X    rm -f *.o *.so ip.sql mac.sql
> X
> XFILES=Makefile README inet_net_ntop.c inet_net_pton.c \
> X    ip.c ip.sql.in mac.c mac.h mac.sql.in test.sql
> X
> Xip+mac.shar: ${FILES}
> X    shar ${FILES} > ip+mac.shar
> X
> X#
> X#    eof
> X#
> END-of-Makefile
> echo x - README
> sed 's/^X//' >README << 'END-of-README'
> XPostgreSQL type extensions for IP and MAC addresses.
> X---------------------------------------------------
> X
> X$Id: README,v 1.2 1998/09/08 12:10:22 tih Exp $
> X
> XI needed to record IP and MAC level ethernet addresses in a data
> Xbase, and I really didn't want to store them as plain strings, with
> Xno enforced error checking, so I put together the accompanying code
> Xas my first experiment with adding a data type to PostgreSQL.  I
> Xthen thought that this might be useful to others, both directly and
> Xas a very simple example of how to do this sort of thing, so I
> Xsubmitted it to the PostgreSQL project for inclusion in the contrib
> Xdirectory.  Since then, that directory has been modified to contain
> XAleksei Roudnev's implementation, which is based on mine.
> X
> XFor those who have seen my previous contribution of these types, note
> Xthat much has changed: I've modified the IP address type to work the
> Xway Paul Vixie did with his CIDR type.  In fact, I've pretty much just
> Xstolen his solution, modifying it into my framework in such a way as
> Xto facilitate the addition of IPV6 handling code in the future.  I've
> Xpretty much ignored Aleksei's C code, but I've added his SQL code to
> Xenter the necessary operators into the various system tables needed to
> Xmake the types indexable.
> X
> XIP addresses are implemented as a struct of fixed in-memory length,
> Xbut variable on-disk storage size.  For IPV4, it contains the address
> Xfamily (AF_INET), the CIDR prefix length and four byte address.  For
> XIPV6, the address family will be different, and the address longer.
> X
> XThe external representation of an IP address generally looks like
> X'158.37.96.15/32'.  This address happens to be part of a subnet where
> XI work; '158.37.96.0/24', which itself is a part of the larger subnet
> Xallocated to our site, which is '158.37.96.0/21', which again, if you
> Xgo by the old book, is part of the class "B" net '158.37.0.0/16'.
> X
> XInput and output functions are supplied, along with the "normal" <,
> X<=, =, >=, > and <> operators, which all do what you expect.  In
> Xaddition, there are operators to check for networks or addresses being
> Xsubnets of or addresses contained within other networks.  << tests
> Xwhether the left operand is contained within the right, <<= includes
> Xequality, >> and >>= do the same things the opposite way.
> X
> XThe input and output functions use routines from Paul Vixie's BIND,
> Xand I've snarfed the source files inet_net_ntop.c and inet_net_pton.c
> Xdirectly from a recent distribution of that code.  They are included
> Xhere to avoid the need to fetch and install the BIND libraries to be
> Xable to use this code.  IANAL, but it looks from the copyright
> Xmessages in the files as if this should be acceptable.  Read the
> Xdocumentation in inet_net_pton.c to see the legal input formats.
> X
> XMAC level ethernet addresses are implemented as a 6 byte struct that
> Xcontains the address as unsigned chars.  Several input forms are
> Xaccepted; the following are all the same address: '08002b:010203',
> X'08002b-010203', '0800.2b01.0203', '08-00-2b-01-02-03' and
> X'08:00:2b:01:02:03'.  Upper and lower case is accepted for the digits
> X'a' through 'f'.  Output is always in the latter of the given forms.
> X
> XAs with IP addresses, input and output functions are supplied as well
> Xas the "normal" operators, which do what you expect.  As an extra
> Xfeature, a function macaddr_manuf() is defined, which returns the name
> Xof the manufacturer as a string.  This is currently held in a
> Xhard-coded struct internal to the C module -- it might be smarter to
> Xput this information into an actual data base table, and look up the
> Xmanufacturer there.
> X
> XMany thanks to Aleksei Roudnev and Paul Vixie for their fine work!
> X
> XI don't know what changes are needed to the Makefile for other systems
> Xthan the one I'm running (NetBSD 1.3), but anyway: to install on a BSD
> Xsystem: fix the path names in the Makefile if you need to, then make,
> Xmake install, slurp the SQL files into psql or whatever, and you're
> Xoff.  Enjoy!
> X
> XBergen, Norway, 1998-08-09, Tom Ivar Helbekkmo (tih@nhh.no).
> END-of-README
> echo x - inet_net_ntop.c
> sed 's/^X//' >inet_net_ntop.c << 'END-of-inet_net_ntop.c'
> X/*
> X * Copyright (c) 1996 by Internet Software Consortium.
> X *
> X * Permission to use, copy, modify, and distribute this software for any
> X * purpose with or without fee is hereby granted, provided that the above
> X * copyright notice and this permission notice appear in all copies.
> X *
> X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
> X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
> X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
> X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
> X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
> X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
> X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
> X * SOFTWARE.
> X */
> X
> X#if defined(LIBC_SCCS) && !defined(lint)
> Xstatic const char rcsid[] = "$Id: inet_net_ntop.c,v 8.2 1996/08/08 06:54:44 vixie Exp $";
> X#endif
> X
> X#include <sys/types.h>
> X#include <sys/socket.h>
> X#include <netinet/in.h>
> X#include <arpa/inet.h>
> X
> X#include <errno.h>
> X#include <stdio.h>
> X#include <string.h>
> X#include <stdlib.h>
> X
> X#ifdef SPRINTF_CHAR
> X# define SPRINTF(x) strlen(sprintf/**/x)
> X#else
> X# define SPRINTF(x) ((size_t)sprintf x)
> X#endif
> X
> Xstatic char *    inet_net_ntop_ipv4 __P((const u_char *src, int bits,
> X                    char *dst, size_t size));
> X
> X/*
> X * char *
> X * inet_net_ntop(af, src, bits, dst, size)
> X *    convert network number from network to presentation format.
> X *    generates CIDR style result always.
> X * return:
> X *    pointer to dst, or NULL if an error occurred (check errno).
> X * author:
> X *    Paul Vixie (ISC), July 1996
> X */
> Xchar *
> Xinet_net_ntop(af, src, bits, dst, size)
> X    int af;
> X    const void *src;
> X    int bits;
> X    char *dst;
> X    size_t size;
> X{
> X    switch (af) {
> X    case AF_INET:
> X        return (inet_net_ntop_ipv4(src, bits, dst, size));
> X    default:
> X        errno = EAFNOSUPPORT;
> X        return (NULL);
> X    }
> X}
> X
> X/*
> X * static char *
> X * inet_net_ntop_ipv4(src, bits, dst, size)
> X *    convert IPv4 network number from network to presentation format.
> X *    generates CIDR style result always.
> X * return:
> X *    pointer to dst, or NULL if an error occurred (check errno).
> X * note:
> X *    network byte order assumed.  this means 192.5.5.240/28 has
> X *    0x11110000 in its fourth octet.
> X * author:
> X *    Paul Vixie (ISC), July 1996
> X */
> Xstatic char *
> Xinet_net_ntop_ipv4(src, bits, dst, size)
> X    const u_char *src;
> X    int bits;
> X    char *dst;
> X    size_t size;
> X{
> X    char *odst = dst;
> X    char *t;
> X    u_int m;
> X    int b;
> X
> X    if (bits < 0 || bits > 32) {
> X        errno = EINVAL;
> X        return (NULL);
> X    }
> X    if (bits == 0) {
> X        if (size < sizeof "0")
> X            goto emsgsize;
> X        *dst++ = '0';
> X        *dst = '\0';
> X    }
> X
> X    /* Format whole octets. */
> X    for (b = bits / 8; b > 0; b--) {
> X        if (size < sizeof "255.")
> X            goto emsgsize;
> X        t = dst;
> X        dst += SPRINTF((dst, "%u", *src++));
> X        if (b > 1) {
> X            *dst++ = '.';
> X            *dst = '\0';
> X        }
> X        size -= (size_t)(dst - t);
> X    }
> X
> X    /* Format partial octet. */
> X    b = bits % 8;
> X    if (b > 0) {
> X        if (size < sizeof ".255")
> X            goto emsgsize;
> X        t = dst;
> X        if (dst != odst)
> X            *dst++ = '.';
> X        m = ((1 << b) - 1) << (8 - b);
> X        dst += SPRINTF((dst, "%u", *src & m));
> X        size -= (size_t)(dst - t);
> X    }
> X
> X    /* Format CIDR /width. */
> X    if (size < sizeof "/32")
> X        goto emsgsize;
> X    dst += SPRINTF((dst, "/%u", bits));
> X    return (odst);
> X
> X emsgsize:
> X    errno = EMSGSIZE;
> X    return (NULL);
> X}
> END-of-inet_net_ntop.c
> echo x - inet_net_pton.c
> sed 's/^X//' >inet_net_pton.c << 'END-of-inet_net_pton.c'
> X/*
> X * Copyright (c) 1996 by Internet Software Consortium.
> X *
> X * Permission to use, copy, modify, and distribute this software for any
> X * purpose with or without fee is hereby granted, provided that the above
> X * copyright notice and this permission notice appear in all copies.
> X *
> X * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
> X * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
> X * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
> X * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
> X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
> X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
> X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
> X * SOFTWARE.
> X */
> X
> X#if defined(LIBC_SCCS) && !defined(lint)
> Xstatic const char rcsid[] = "$Id: inet_net_pton.c,v 8.3 1996/11/11 06:36:52 vixie Exp $";
> X#endif
> X
> X#include <sys/types.h>
> X#include <sys/socket.h>
> X#include <netinet/in.h>
> X#include <arpa/inet.h>
> X
> X#include <assert.h>
> X#include <ctype.h>
> X#include <errno.h>
> X#include <stdio.h>
> X#include <string.h>
> X#include <stdlib.h>
> X
> X#ifdef SPRINTF_CHAR
> X# define SPRINTF(x) strlen(sprintf/**/x)
> X#else
> X# define SPRINTF(x) ((size_t)sprintf x)
> X#endif
> X
> Xstatic int    inet_net_pton_ipv4 __P((const char *src, u_char *dst,
> X                    size_t size));
> X
> X/*
> X * static int
> X * inet_net_pton(af, src, dst, size)
> X *    convert network number from presentation to network format.
> X *    accepts hex octets, hex strings, decimal octets, and /CIDR.
> X *    "size" is in bytes and describes "dst".
> X * return:
> X *    number of bits, either imputed classfully or specified with /CIDR,
> X *    or -1 if some failure occurred (check errno).  ENOENT means it was
> X *    not a valid network specification.
> X * author:
> X *    Paul Vixie (ISC), June 1996
> X */
> Xint
> Xinet_net_pton(af, src, dst, size)
> X    int af;
> X    const char *src;
> X    void *dst;
> X    size_t size;
> X{
> X    switch (af) {
> X    case AF_INET:
> X        return (inet_net_pton_ipv4(src, dst, size));
> X    default:
> X        errno = EAFNOSUPPORT;
> X        return (-1);
> X    }
> X}
> X
> X/*
> X * static int
> X * inet_net_pton_ipv4(src, dst, size)
> X *    convert IPv4 network number from presentation to network format.
> X *    accepts hex octets, hex strings, decimal octets, and /CIDR.
> X *    "size" is in bytes and describes "dst".
> X * return:
> X *    number of bits, either imputed classfully or specified with /CIDR,
> X *    or -1 if some failure occurred (check errno).  ENOENT means it was
> X *    not an IPv4 network specification.
> X * note:
> X *    network byte order assumed.  this means 192.5.5.240/28 has
> X *    0x11110000 in its fourth octet.
> X * author:
> X *    Paul Vixie (ISC), June 1996
> X */
> Xstatic int
> Xinet_net_pton_ipv4(src, dst, size)
> X    const char *src;
> X    u_char *dst;
> X    size_t size;
> X{
> X    static const char
> X        xdigits[] = "0123456789abcdef",
> X        digits[] = "0123456789";
> X    int n, ch, tmp, dirty, bits;
> X    const u_char *odst = dst;
> X
> X    ch = *src++;
> X    if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
> X        && isascii(src[1]) && isxdigit(src[1])) {
> X        /* Hexadecimal: Eat nybble string. */
> X        if (size <= 0)
> X            goto emsgsize;
> X        *dst = 0, dirty = 0;
> X        src++;    /* skip x or X. */
> X        while ((ch = *src++) != '\0' &&
> X               isascii(ch) && isxdigit(ch)) {
> X            if (isupper(ch))
> X                ch = tolower(ch);
> X            n = strchr(xdigits, ch) - xdigits;
> X            assert(n >= 0 && n <= 15);
> X            *dst |= n;
> X            if (!dirty++)
> X                *dst <<= 4;
> X            else if (size-- > 0)
> X                *++dst = 0, dirty = 0;
> X            else
> X                goto emsgsize;
> X        }
> X        if (dirty)
> X            size--;
> X    } else if (isascii(ch) && isdigit(ch)) {
> X        /* Decimal: eat dotted digit string. */
> X        for (;;) {
> X            tmp = 0;
> X            do {
> X                n = strchr(digits, ch) - digits;
> X                assert(n >= 0 && n <= 9);
> X                tmp *= 10;
> X                tmp += n;
> X                if (tmp > 255)
> X                    goto enoent;
> X            } while ((ch = *src++) != '\0' &&
> X                 isascii(ch) && isdigit(ch));
> X            if (size-- <= 0)
> X                goto emsgsize;
> X            *dst++ = (u_char) tmp;
> X            if (ch == '\0' || ch == '/')
> X                break;
> X            if (ch != '.')
> X                goto enoent;
> X            ch = *src++;
> X            if (!isascii(ch) || !isdigit(ch))
> X                goto enoent;
> X        }
> X    } else
> X        goto enoent;
> X
> X    bits = -1;
> X    if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
> X        /* CIDR width specifier.  Nothing can follow it. */
> X        ch = *src++;    /* Skip over the /. */
> X        bits = 0;
> X        do {
> X            n = strchr(digits, ch) - digits;
> X            assert(n >= 0 && n <= 9);
> X            bits *= 10;
> X            bits += n;
> X        } while ((ch = *src++) != '\0' &&
> X             isascii(ch) && isdigit(ch));
> X        if (ch != '\0')
> X            goto enoent;
> X        if (bits > 32)
> X            goto emsgsize;
> X    }
> X
> X    /* Firey death and destruction unless we prefetched EOS. */
> X    if (ch != '\0')
> X        goto enoent;
> X
> X    /* If nothing was written to the destination, we found no address. */
> X    if (dst == odst)
> X        goto enoent;
> X    /* If no CIDR spec was given, infer width from net class. */
> X    if (bits == -1) {
> X        if (*odst >= 240)    /* Class E */
> X            bits = 32;
> X        else if (*odst >= 224)    /* Class D */
> X            bits = 4;
> X        else if (*odst >= 192)    /* Class C */
> X            bits = 24;
> X        else if (*odst >= 128)    /* Class B */
> X            bits = 16;
> X        else            /* Class A */
> X            bits = 8;
> X        /* If imputed mask is narrower than specified octets, widen. */
> X        if (bits >= 8 && bits < ((dst - odst) * 8))
> X            bits = (dst - odst) * 8;
> X    }
> X    /* Extend network to cover the actual mask. */
> X    while (bits > ((dst - odst) * 8)) {
> X        if (size-- <= 0)
> X            goto emsgsize;
> X        *dst++ = '\0';
> X    }
> X    return (bits);
> X
> X enoent:
> X    errno = ENOENT;
> X    return (-1);
> X
> X emsgsize:
> X    errno = EMSGSIZE;
> X    return (-1);
> X}
> END-of-inet_net_pton.c
> echo x - ip.c
> sed 's/^X//' >ip.c << 'END-of-ip.c'
> X/*
> X *    PostgreSQL type definitions for IP addresses.  This
> X *    is for IP V4 CIDR notation, but prepared for V6: just
> X *    add the necessary bits where the comments indicate.
> X *
> X *    $Id: ip.c,v 1.2 1998/09/08 12:10:36 tih Exp $
> X */
> X
> X#include <sys/types.h>
> X#include <sys/socket.h>
> X
> X#include <stdio.h>
> X#include <errno.h>
> X
> X#include <netinet/in.h>
> X#include <arpa/inet.h>
> X
> X#include <postgres.h>
> X#include <utils/palloc.h>
> X
> X/*
> X *    This is the internal storage format for IP addresses:
> X */
> X
> Xtypedef struct {
> X  unsigned char family;
> X  unsigned char bits;
> X  union {
> X    u_int32_t ipv4_addr;    /* network byte order */
> X                /* add IPV6 address type here */
> X  } addr;
> X} ipaddr_struct;
> X
> Xtypedef struct varlena ipaddr;
> X
> X/*
> X *    Access macros.  Add IPV6 support.
> X */
> X
> X#define ip_addrsize(ipaddrptr) \
> X    (((ipaddr_struct *)VARDATA(ipaddrptr))->family == AF_INET ? 4 : -1)
> X
> X#define ip_family(ipaddrptr) \
> X    (((ipaddr_struct *)VARDATA(ipaddrptr))->family)
> X
> X#define ip_bits(ipaddrptr) \
> X    (((ipaddr_struct *)VARDATA(ipaddrptr))->bits)
> X
> X#define ip_v4addr(ipaddrptr) \
> X    (((ipaddr_struct *)VARDATA(ipaddrptr))->addr.ipv4_addr)
> X
> X/*
> X *    Various forward declarations:
> X */
> X
> Xipaddr *ipaddr_in(char *str);
> Xchar *ipaddr_out(ipaddr *addr);
> X
> Xbool ipaddr_lt(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_le(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_eq(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_ge(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_gt(ipaddr *a1, ipaddr *a2);
> X
> Xbool ipaddr_ne(ipaddr *a1, ipaddr *a2);
> X
> Xbool ipaddr_sub(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_subeq(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_sup(ipaddr *a1, ipaddr *a2);
> Xbool ipaddr_supeq(ipaddr *a1, ipaddr *a2);
> X
> Xint4 ipaddr_cmp(ipaddr *a1, ipaddr *a2);
> X
> Xint v4bitncmp(u_int32_t a1, u_int32_t a2, int bits);
> X
> X/*
> X *    IP address reader.
> X */
> X
> Xipaddr *ipaddr_in(char *src) {
> X  int bits;
> X  ipaddr *dst;
> X
> X  dst = palloc(VARHDRSZ + sizeof(ipaddr_struct));
> X  if (dst == NULL) {
> X    elog(ERROR, "unable to allocate memory in ipaddr_in()");
> X    return(NULL);
> X  }
> X  /* First, try for an IP V4 address: */
> X  ip_family(dst) = AF_INET;
> X  bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst), ip_addrsize(dst));
> X  if ((bits < 0) || (bits > 32)) {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "could not parse \"%s\"", src);
> X    pfree(dst);
> X    return(NULL);
> X  }
> X  VARSIZE(dst) = VARHDRSZ
> X    + ((char *)&ip_v4addr(dst) - (char *)VARDATA(dst))
> X    + ip_addrsize(dst);
> X  ip_bits(dst) = bits;
> X  return(dst);
> X}
> X
> X/*
> X *    IP address output function.
> X */
> X
> Xchar *ipaddr_out(ipaddr *src) {
> X  char *dst, tmp[sizeof("255.255.255.255/32")];
> X
> X  if (ip_family(src) == AF_INET) {
> X    /* It's an IP V4 address: */
> X    if (inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
> X              tmp, sizeof(tmp)) < 0) {
> X      elog(ERROR, "unable to print address (%s)", strerror(errno));
> X      return(NULL);
> X    }
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "unknown address family (%d)", ip_family(src));
> X    return(NULL);
> X  }
> X  dst = palloc(strlen(tmp) + 1);
> X  if (dst == NULL) {
> X    elog(ERROR, "unable to allocate memory in ipaddr_out()");
> X    return(NULL);
> X  }
> X  strcpy(dst, tmp);
> X  return(dst);
> X}
> X
> X/*
> X *    Boolean tests for magnitude.  Add V4/V6 testing!
> X */
> X
> Xbool ipaddr_lt(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
> X    return((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> Xbool ipaddr_le(ipaddr *a1, ipaddr *a2) {
> X  return(ipaddr_lt(a1, a2) || ipaddr_eq(a1, a2));
> X}
> X
> Xbool ipaddr_eq(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    return((ip_bits(a1) == ip_bits(a2))
> X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> Xbool ipaddr_ge(ipaddr *a1, ipaddr *a2) {
> X  return(ipaddr_gt(a1, a2) || ipaddr_eq(a1, a2));
> X}
> X
> Xbool ipaddr_gt(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
> X    return((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> Xbool ipaddr_ne(ipaddr *a1, ipaddr *a2) {
> X  return(!ipaddr_eq(a1, a2));
> X}
> X
> Xbool ipaddr_sub(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    return((ip_bits(a1) > ip_bits(a2))
> X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> Xbool ipaddr_subeq(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    return((ip_bits(a1) >= ip_bits(a2))
> X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> Xbool ipaddr_sup(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    return((ip_bits(a1) < ip_bits(a2))
> X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> Xbool ipaddr_supeq(ipaddr *a1, ipaddr *a2) {
> X  if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET)) {
> X    return((ip_bits(a1) <= ip_bits(a2))
> X       && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
> X  } else {
> X    /* Go for an IPV6 address here, before faulting out: */
> X    elog(ERROR, "cannot compare address families %d and %d",
> X     ip_family(a1), ip_family(a2));
> X    return(FALSE);
> X  }
> X}
> X
> X/*
> X *    Comparison function for sorting.  Add V4/V6 testing!
> X */
> X
> Xint4 ipaddr_cmp(ipaddr *a1, ipaddr *a2) {
> X  if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2))) {
> X    return(-1);
> X  } else if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2))) {
> X    return(1);
> X  }
> X  return 0;
> X}
> X
> X/*
> X *    Bitwise comparison for V4 addresses.  Add V6 implementation!
> X */
> X
> Xint v4bitncmp(u_int32_t a1, u_int32_t a2, int bits) {
> X  unsigned long mask = 0;
> X  int i;
> X  for (i = 0; i < bits; i++) {
> X    mask = (mask >> 1) | 0x80000000;
> X  }
> X  a1 = ntohl(a1);
> X  a2 = ntohl(a2);
> X  if ((a1 & mask) < (a2 & mask)) {
> X    return(-1);
> X  } else if ((a1 & mask) > (a2 & mask)) {
> X    return(1);
> X  }
> X  return(0);
> X}
> X
> X/*
> X *    eof
> X */
> END-of-ip.c
> echo x - ip.sql.in
> sed 's/^X//' >ip.sql.in << 'END-of-ip.sql.in'
> X--
> X--    PostgreSQL code for IP addresses.
> X--
> X--    $Id: ip.sql.in,v 1.2 1998/09/08 12:10:45 tih Exp $
> X--
> X
> Xload 'TARGET/ip.so';
> X
> X--
> X--    Input and output functions and the type itself:
> X--
> X
> Xcreate function ipaddr_in(opaque)
> X    returns opaque
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_out(opaque)
> X    returns opaque
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate type ipaddr (
> X    internallength = variable,
> X    externallength = variable,
> X    input = ipaddr_in,
> X    output = ipaddr_out
> X);
> X
> X--
> X--    The various boolean tests:
> X--
> X
> Xcreate function ipaddr_lt(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_le(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_eq(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_ge(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_gt(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_ne(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_sub(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_subeq(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_sup(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_supeq(ipaddr, ipaddr)
> X    returns bool
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> Xcreate function ipaddr_cmp(ipaddr, ipaddr)
> X    returns int4
> X    as 'TARGET/ip.so'
> X    language 'c';
> X
> X--
> X--    Now the operators.  Note how some of the parameters to some
> X--    of the 'create operator' commands are commented out.  This
> X--    is because they reference as yet undefined operators, and
> X--    will be implicitly defined when those are, further down.
> X--
> X
> Xcreate operator < (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X--    negator = >=,
> X    restrict = intltsel,
> X    join = intltjoinsel,
> X    procedure = ipaddr_lt
> X);
> X
> Xcreate operator <= (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X--    negator = >,
> X    restrict = intltsel,
> X    join = intltjoinsel,
> X    procedure = ipaddr_le
> X);
> X
> Xcreate operator = (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    commutator = =,
> X--    negator = <>,
> X    restrict = eqsel,
> X    join = eqjoinsel,
> X    procedure = ipaddr_eq
> X);
> X
> Xcreate operator >= (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    negator = <,
> X    restrict = intgtsel,
> X    join = intgtjoinsel,
> X    procedure = ipaddr_ge
> X);
> X
> Xcreate operator > (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    negator = <=,
> X    restrict = intgtsel,
> X    join = intgtjoinsel,
> X    procedure = ipaddr_gt
> X);
> X
> Xcreate operator <> (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    negator = =,
> X    restrict = neqsel,
> X    join = neqjoinsel,
> X    procedure = ipaddr_ne
> X);
> X
> Xcreate operator << (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    procedure = ipaddr_sub
> X);
> X
> Xcreate operator <<= (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    procedure = ipaddr_subeq
> X);
> X
> Xcreate operator >> (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    procedure = ipaddr_sup
> X);
> X
> Xcreate operator >>= (
> X    leftarg = ipaddr,
> X    rightarg = ipaddr,
> X    procedure = ipaddr_supeq
> X);
> X
> X--
> X--    Finally, make it possible to do btree indexing on IP addresses.
> X--
> X
> Xbegin;
> X
> Xcreate table tmp_op (oprname name, opi int2);
> X
> Xinsert into tmp_op values ('<',  1);
> Xinsert into tmp_op values ('<=', 2);
> Xinsert into tmp_op values ('=',  3);
> Xinsert into tmp_op values ('>=', 4);
> Xinsert into tmp_op values ('>',  5);
> X
> Xdelete from pg_opclass
> X    where opcname = 'ipaddr_ops';
> X
> Xinsert into pg_opclass (opcname, opcdeftype)
> X    select 'ipaddr_ops', oid from pg_type
> X        where typname = 'ipaddr';
> X
> Xselect o.oid as opoid, o.oprname
> X    into table ipaddr_tmp
> X    from pg_operator o, pg_type t
> X    where o.oprleft = t.oid and
> X          o.oprright = t.oid and
> X          t.typname = 'ipaddr';
> X
> Xinsert into pg_amop (amopid, amopclaid, amopopr, amopstrategy,
> X             amopselect, amopnpages)
> X    select am.oid, opcl.oid, c.opoid, t.opi,
> X            'btreesel'::regproc, 'btreenpage'::regproc
> X        from pg_am am, pg_opclass opcl, ipaddr_tmp c, tmp_op t
> X        where t.oprname = c.oprname and
> X              amname = 'btree' and opcname = 'ipaddr_ops';
> X
> Xinsert into pg_amproc (amid, amopclaid, amproc, amprocnum)
> X    select pgam.oid, opc.oid, prc.oid, '1'::int2
> X        from pg_am pgam, pg_opclass opc, pg_proc prc
> X        where prc.proname = 'ipaddr_cmp' and
> X              pgam.amname = 'btree' and
> X              opc.opcname = 'ipaddr_ops';
> X
> Xdrop table tmp_op;
> Xdrop table ipaddr_tmp;
> X
> Xcommit;
> X
> X--
> X--    eof
> X--
> END-of-ip.sql.in
> echo x - mac.c
> sed 's/^X//' >mac.c << 'END-of-mac.c'
> X/*
> X *    PostgreSQL type definitions for MAC addresses.
> X *
> X *    $Id: mac.c,v 1.1 1998/09/07 12:31:18 tih Exp $
> X */
> X
> X#include <stdio.h>
> X
> X#include <postgres.h>
> X#include <utils/palloc.h>
> X
> X#include "mac.h"
> X
> X/*
> X *    This is the internal storage format for MAC addresses:
> X */
> X
> Xtypedef struct macaddr {
> X  unsigned char a;
> X  unsigned char b;
> X  unsigned char c;
> X  unsigned char d;
> X  unsigned char e;
> X  unsigned char f;
> X} macaddr;
> X
> X/*
> X *    Various forward declarations:
> X */
> X
> Xmacaddr *macaddr_in(char *str);
> Xchar *macaddr_out(macaddr *addr);
> X
> Xbool macaddr_lt(macaddr *a1, macaddr *a2);
> Xbool macaddr_le(macaddr *a1, macaddr *a2);
> Xbool macaddr_eq(macaddr *a1, macaddr *a2);
> Xbool macaddr_ge(macaddr *a1, macaddr *a2);
> Xbool macaddr_gt(macaddr *a1, macaddr *a2);
> X
> Xbool macaddr_ne(macaddr *a1, macaddr *a2);
> X
> Xint4 macaddr_cmp(macaddr *a1, macaddr *a2);
> X
> Xtext *macaddr_manuf(macaddr *addr);
> X
> X/*
> X *    Utility macros used for sorting and comparing:
> X */
> X
> X#define hibits(addr) \
> X  ((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c)))
> X
> X#define lobits(addr) \
> X  ((unsigned long)((addr->c<<16)|(addr->e<<8)|(addr->f)))
> X
> X/*
> X *    MAC address reader.  Accepts several common notations.
> X */
> X
> Xmacaddr *macaddr_in(char *str) {
> X  int a, b, c, d, e, f;
> X  macaddr *result;
> X  int count;
> X
> X  if (strlen(str) > 0) {
> X
> X    count = sscanf(str, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f);
> X    if (count != 6)
> X      count = sscanf(str, "%x-%x-%x-%x-%x-%x", &a, &b, &c, &d, &e, &f);
> X    if (count != 6)
> X      count = sscanf(str, "%2x%2x%2x:%2x%2x%2x", &a, &b, &c, &d, &e, &f);
> X    if (count != 6)
> X      count = sscanf(str, "%2x%2x%2x-%2x%2x%2x", &a, &b, &c, &d, &e, &f);
> X    if (count != 6)
> X      count = sscanf(str, "%2x%2x.%2x%2x.%2x%2x", &a, &b, &c, &d, &e, &f);
> X
> X    if (count != 6) {
> X      elog(ERROR, "macaddr_in: error in parsing \"%s\"", str);
> X      return(NULL);
> X    }
> X
> X    if ((a < 0) || (a > 255) || (b < 0) || (b > 255) ||
> X    (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
> X    (e < 0) || (e > 255) || (f < 0) || (f > 255)) {
> X      elog(ERROR, "macaddr_in: illegal address \"%s\"", str);
> X      return(NULL);
> X    }
> X  } else {
> X    a = b = c = d = e = f = 0;    /* special case for missing address */
> X  }
> X
> X  result = (macaddr *)palloc(sizeof(macaddr));
> X
> X  result->a = a;
> X  result->b = b;
> X  result->c = c;
> X  result->d = d;
> X  result->e = e;
> X  result->f = f;
> X
> X  return(result);
> X}
> X
> X/*
> X *    MAC address output function.  Fixed format.
> X */
> X
> Xchar *macaddr_out(macaddr *addr) {
> X  char *result;
> X
> X  if (addr == NULL)
> X    return(NULL);
> X
> X  result = (char *)palloc(32);
> X
> X  if ((hibits(addr) > 0) || (lobits(addr) > 0)) {
> X    sprintf(result, "%02x:%02x:%02x:%02x:%02x:%02x",
> X        addr->a, addr->b, addr->c, addr->d, addr->e, addr->f);
> X  } else {
> X    result[0] = 0;        /* special case for missing address */
> X  }
> X  return(result);
> X}
> X
> X/*
> X *    Boolean tests.
> X */
> X
> Xbool macaddr_lt(macaddr *a1, macaddr *a2) {
> X  return((hibits(a1) < hibits(a2)) ||
> X     ((hibits(a1) == hibits(a2)) && lobits(a1) < lobits(a2)));
> X};
> X
> Xbool macaddr_le(macaddr *a1, macaddr *a2) {
> X  return((hibits(a1) < hibits(a2)) ||
> X     ((hibits(a1) == hibits(a2)) && lobits(a1) <= lobits(a2)));
> X};
> X
> Xbool macaddr_eq(macaddr *a1, macaddr *a2) {
> X  return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
> X};
> X
> Xbool macaddr_ge(macaddr *a1, macaddr *a2) {
> X  return((hibits(a1) > hibits(a2)) ||
> X     ((hibits(a1) == hibits(a2)) && lobits(a1) >= lobits(a2)));
> X};
> X
> Xbool macaddr_gt(macaddr *a1, macaddr *a2) {
> X  return((hibits(a1) > hibits(a2)) ||
> X     ((hibits(a1) == hibits(a2)) && lobits(a1) > lobits(a2)));
> X};
> X
> Xbool macaddr_ne(macaddr *a1, macaddr *a2) {
> X  return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
> X};
> X
> X/*
> X *    Comparison function for sorting:
> X */
> X
> Xint4 macaddr_cmp(macaddr *a1, macaddr *a2) {
> X  if (hibits(a1) < hibits(a2))
> X    return -1;
> X  else if (hibits(a1) > hibits(a2))
> X    return 1;
> X  else if (lobits(a1) < lobits(a2))
> X    return -1;
> X  else if (lobits(a1) > lobits(a2))
> X    return 1;
> X  else
> X    return 0;
> X}
> X
> X/*
> X *    The special manufacturer fetching function.  See "mac.h".
> X */
> X
> Xtext *macaddr_manuf(macaddr *addr) {
> X  manufacturer *manuf;
> X  int length;
> X  text *result;
> X
> X  for (manuf = manufacturers; manuf->name != NULL; manuf++) {
> X    if ((manuf->a == addr->a) &&
> X    (manuf->b == addr->b) &&
> X    (manuf->c == addr->c))
> X      break;
> X  }
> X  if (manuf->name == NULL) {
> X    result = palloc(VARHDRSZ + 1);
> X    memset(result, 0, VARHDRSZ + 1);
> X    VARSIZE(result) = VARHDRSZ + 1;
> X  } else {
> X    length = strlen(manuf->name) + 1;
> X    result = palloc(length + VARHDRSZ);
> X    memset(result, 0, length + VARHDRSZ);
> X    VARSIZE(result) = length + VARHDRSZ;
> X    memcpy(VARDATA(result), manuf->name, length);
> X  }
> X  return result;
> X}
> X
> X/*
> X *    eof
> X */
> END-of-mac.c
> echo x - mac.h
> sed 's/^X//' >mac.h << 'END-of-mac.h'
> X/*
> X *    PostgreSQL type definitions for MAC addresses.
> X *
> X *    $Id: mac.h,v 1.1 1998/09/07 12:31:22 tih Exp $
> X */
> X
> Xtypedef struct manufacturer {
> X  unsigned char a;
> X  unsigned char b;
> X  unsigned char c;
> X  char *name;
> X} manufacturer;
> X
> Xmanufacturer manufacturers[] = {
> X  {0x00, 0x00, 0x0C, "Cisco"},
> X  {0x00, 0x00, 0x0E, "Fujitsu"},
> X  {0x00, 0x00, 0x0F, "NeXT"},
> X  {0x00, 0x00, 0x10, "Sytek"},
> X  {0x00, 0x00, 0x1D, "Cabletron"},
> X  {0x00, 0x00, 0x20, "DIAB"},
> X  {0x00, 0x00, 0x22, "Visual Technology"},
> X  {0x00, 0x00, 0x2A, "TRW"},
> X  {0x00, 0x00, 0x32, "GPT Limited"},
> X  {0x00, 0x00, 0x5A, "S & Koch"},
> X  {0x00, 0x00, 0x5E, "IANA"},
> X  {0x00, 0x00, 0x65, "Network General"},
> X  {0x00, 0x00, 0x6B, "MIPS"},
> X  {0x00, 0x00, 0x77, "MIPS"},
> X  {0x00, 0x00, 0x7A, "Ardent"},
> X  {0x00, 0x00, 0x89, "Cayman Systems"},
> X  {0x00, 0x00, 0x93, "Proteon"},
> X  {0x00, 0x00, 0x9F, "Ameristar Technology"},
> X  {0x00, 0x00, 0xA2, "Wellfleet"},
> X  {0x00, 0x00, 0xA3, "Network Application Technology"},
> X  {0x00, 0x00, 0xA6, "Network General"},
> X  {0x00, 0x00, 0xA7, "NCD"},
> X  {0x00, 0x00, 0xA9, "Network Systems"},
> X  {0x00, 0x00, 0xAA, "Xerox"},
> X  {0x00, 0x00, 0xB3, "CIMLinc"},
> X  {0x00, 0x00, 0xB7, "Dove Fastnet"},
> X  {0x00, 0x00, 0xBC, "Allen-Bradley"},
> X  {0x00, 0x00, 0xC0, "Western Digital"},
> X  {0x00, 0x00, 0xC5, "Farallon"},
> X  {0x00, 0x00, 0xC6, "Hewlett-Packard"},
> X  {0x00, 0x00, 0xC8, "Altos"},
> X  {0x00, 0x00, 0xC9, "Emulex"},
> X  {0x00, 0x00, 0xD7, "Dartmouth College"},
> X  {0x00, 0x00, 0xD8, "3Com (?)"},
> X  {0x00, 0x00, 0xDD, "Gould"},
> X  {0x00, 0x00, 0xDE, "Unigraph"},
> X  {0x00, 0x00, 0xE2, "Acer Counterpoint"},
> X  {0x00, 0x00, 0xEF, "Alantec"},
> X  {0x00, 0x00, 0xFD, "High Level Hardware"},
> X  {0x00, 0x01, 0x02, "BBN internal usage"},
> X  {0x00, 0x20, 0xAF, "3Com"},
> X  {0x00, 0x17, 0x00, "Kabel"},
> X  {0x00, 0x80, 0x64, "Wyse Technology"},
> X  {0x00, 0x80, 0x2B, "IMAC (?)"},
> X  {0x00, 0x80, 0x2D, "Xylogics, Inc."},
> X  {0x00, 0x80, 0x8C, "Frontier Software Development"},
> X  {0x00, 0x80, 0xC2, "IEEE 802.1 Committee"},
> X  {0x00, 0x80, 0xD3, "Shiva"},
> X  {0x00, 0xAA, 0x00, "Intel"},
> X  {0x00, 0xDD, 0x00, "Ungermann-Bass"},
> X  {0x00, 0xDD, 0x01, "Ungermann-Bass"},
> X  {0x02, 0x07, 0x01, "Racal InterLan"},
> X  {0x02, 0x04, 0x06, "BBN internal usage"},
> X  {0x02, 0x60, 0x86, "Satelcom MegaPac"},
> X  {0x02, 0x60, 0x8C, "3Com"},
> X  {0x02, 0xCF, 0x1F, "CMC"},
> X  {0x08, 0x00, 0x02, "3Com"},
> X  {0x08, 0x00, 0x03, "ACC"},
> X  {0x08, 0x00, 0x05, "Symbolics"},
> X  {0x08, 0x00, 0x08, "BBN"},
> X  {0x08, 0x00, 0x09, "Hewlett-Packard"},
> X  {0x08, 0x00, 0x0A, "Nestar Systems"},
> X  {0x08, 0x00, 0x0B, "Unisys"},
> X  {0x08, 0x00, 0x11, "Tektronix"},
> X  {0x08, 0x00, 0x14, "Excelan"},
> X  {0x08, 0x00, 0x17, "NSC"},
> X  {0x08, 0x00, 0x1A, "Data General"},
> X  {0x08, 0x00, 0x1B, "Data General"},
> X  {0x08, 0x00, 0x1E, "Apollo"},
> X  {0x08, 0x00, 0x20, "Sun"},
> X  {0x08, 0x00, 0x22, "NBI"},
> X  {0x08, 0x00, 0x25, "CDC"},
> X  {0x08, 0x00, 0x26, "Norsk Data"},
> X  {0x08, 0x00, 0x27, "PCS Computer Systems GmbH"},
> X  {0x08, 0x00, 0x28, "Texas Instruments"},
> X  {0x08, 0x00, 0x2B, "DEC"},
> X  {0x08, 0x00, 0x2E, "Metaphor"},
> X  {0x08, 0x00, 0x2F, "Prime Computer"},
> X  {0x08, 0x00, 0x36, "Intergraph"},
> X  {0x08, 0x00, 0x37, "Fujitsu-Xerox"},
> X  {0x08, 0x00, 0x38, "Bull"},
> X  {0x08, 0x00, 0x39, "Spider Systems"},
> X  {0x08, 0x00, 0x41, "DCA Digital Comm. Assoc."},
> X  {0x08, 0x00, 0x45, "Xylogics (?)"},
> X  {0x08, 0x00, 0x46, "Sony"},
> X  {0x08, 0x00, 0x47, "Sequent"},
> X  {0x08, 0x00, 0x49, "Univation"},
> X  {0x08, 0x00, 0x4C, "Encore"},
> X  {0x08, 0x00, 0x4E, "BICC"},
> X  {0x08, 0x00, 0x56, "Stanford University"},
> X  {0x08, 0x00, 0x58, "DECsystem 20 (?)"},
> X  {0x08, 0x00, 0x5A, "IBM"},
> X  {0x08, 0x00, 0x67, "Comdesign"},
> X  {0x08, 0x00, 0x68, "Ridge"},
> X  {0x08, 0x00, 0x69, "Silicon Graphics"},
> X  {0x08, 0x00, 0x6E, "Concurrent"},
> X  {0x08, 0x00, 0x75, "DDE"},
> X  {0x08, 0x00, 0x7C, "Vitalink"},
> X  {0x08, 0x00, 0x80, "XIOS"},
> X  {0x08, 0x00, 0x86, "Imagen/QMS"},
> X  {0x08, 0x00, 0x87, "Xyplex"},
> X  {0x08, 0x00, 0x89, "Kinetics"},
> X  {0x08, 0x00, 0x8B, "Pyramid"},
> X  {0x08, 0x00, 0x8D, "XyVision"},
> X  {0x08, 0x00, 0x90, "Retix Inc"},
> X  {0x48, 0x44, 0x53, "HDS (?)"},
> X  {0x80, 0x00, 0x10, "AT&T"},
> X  {0xAA, 0x00, 0x00, "DEC"},
> X  {0xAA, 0x00, 0x01, "DEC"},
> X  {0xAA, 0x00, 0x02, "DEC"},
> X  {0xAA, 0x00, 0x03, "DEC"},
> X  {0xAA, 0x00, 0x04, "DEC"},
> X  {0x00, 0x00, 0x00, NULL}
> X};
> X
> X/*
> X *    eof
> X */
> END-of-mac.h
> echo x - mac.sql.in
> sed 's/^X//' >mac.sql.in << 'END-of-mac.sql.in'
> X--
> X--    PostgreSQL code for MAC addresses.
> X--
> X--    $Id: mac.sql.in,v 1.2 1998/09/08 12:11:18 tih Exp $
> X--
> X
> Xload 'TARGET/mac.so';
> X
> X--
> X--    Input and output functions and the type itself:
> X--
> X
> Xcreate function macaddr_in(opaque)
> X    returns opaque
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_out(opaque)
> X    returns opaque
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate type macaddr (
> X    internallength = 6,
> X    externallength = variable,
> X    input = macaddr_in,
> X    output = macaddr_out
> X);
> X
> X--
> X--    The boolean tests:
> X--
> X
> Xcreate function macaddr_lt(macaddr, macaddr)
> X    returns bool
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_le(macaddr, macaddr)
> X    returns bool
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_eq(macaddr, macaddr)
> X    returns bool
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_ge(macaddr, macaddr)
> X    returns bool
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_gt(macaddr, macaddr)
> X    returns bool
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_ne(macaddr, macaddr)
> X    returns bool
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> Xcreate function macaddr_cmp(macaddr, macaddr)
> X    returns int4
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> X--
> X--    Now the operators.  Note how some of the parameters to some
> X--    of the 'create operator' commands are commented out.  This
> X--    is because they reference as yet undefined operators, and
> X--    will be implicitly defined when those are, further down.
> X--
> X
> Xcreate operator < (
> X    leftarg = macaddr,
> X    rightarg = macaddr,
> X--    negator = >=,
> X    procedure = macaddr_lt
> X);
> X
> Xcreate operator <= (
> X    leftarg = macaddr,
> X    rightarg = macaddr,
> X--    negator = >,
> X    procedure = macaddr_le
> X);
> X
> Xcreate operator = (
> X    leftarg = macaddr,
> X    rightarg = macaddr,
> X    commutator = =,
> X--    negator = <>,
> X    procedure = macaddr_eq
> X);
> X
> Xcreate operator >= (
> X    leftarg = macaddr,
> X    rightarg = macaddr,
> X    negator = <,
> X    procedure = macaddr_ge
> X);
> X
> Xcreate operator > (
> X    leftarg = macaddr,
> X    rightarg = macaddr,
> X    negator = <=,
> X    procedure = macaddr_gt
> X);
> X
> Xcreate operator <> (
> X    leftarg = macaddr,
> X    rightarg = macaddr,
> X    negator = =,
> X    procedure = macaddr_ne
> X);
> X
> X--
> X--    Finally, the special manufacurer matching function:
> X--
> X
> Xcreate function macaddr_manuf(macaddr)
> X    returns text
> X    as 'TARGET/mac.so'
> X    language 'c';
> X
> X--
> X--    Finally, make it possible to do btree indexing on MAC addresses.
> X--
> X
> Xbegin;
> X
> Xcreate table tmp_op (oprname name, opi int2);
> X
> Xinsert into tmp_op values ('<',  1);
> Xinsert into tmp_op values ('<=', 2);
> Xinsert into tmp_op values ('=',  3);
> Xinsert into tmp_op values ('>=', 4);
> Xinsert into tmp_op values ('>',  5);
> X
> Xdelete from pg_opclass
> X    where opcname = 'macaddr_ops';
> X
> Xinsert into pg_opclass (opcname, opcdeftype)
> X    select 'macaddr_ops', oid from pg_type
> X        where typname = 'macaddr';
> X
> Xselect o.oid as opoid, o.oprname
> X    into table macaddr_tmp
> X    from pg_operator o, pg_type t
> X    where o.oprleft = t.oid and
> X          o.oprright = t.oid and
> X          t.typname = 'macaddr';
> X
> Xinsert into pg_amop (amopid, amopclaid, amopopr, amopstrategy,
> X             amopselect, amopnpages)
> X    select am.oid, opcl.oid, c.opoid, t.opi,
> X            'btreesel'::regproc, 'btreenpage'::regproc
> X        from pg_am am, pg_opclass opcl, macaddr_tmp c, tmp_op t
> X        where t.oprname = c.oprname and
> X              amname = 'btree' and opcname = 'macaddr_ops';
> X
> Xinsert into pg_amproc (amid, amopclaid, amproc, amprocnum)
> X    select pgam.oid, opc.oid, prc.oid, '1'::int2
> X        from pg_am pgam, pg_opclass opc, pg_proc prc
> X        where prc.proname = 'macaddr_cmp' and
> X              pgam.amname = 'btree' and
> X              opc.opcname = 'macaddr_ops';
> X
> Xdrop table tmp_op;
> Xdrop table macaddr_tmp;
> X
> Xcommit;
> X
> X--
> X--    eof
> X--
> END-of-mac.sql.in
> echo x - test.sql
> sed 's/^X//' >test.sql << 'END-of-test.sql'
> X--
> X--    A quick test of the IP address code
> X--
> X--    $Id: test.sql,v 1.2 1998/09/08 12:11:34 tih Exp $
> X--
> X
> X-- temporary table:
> Xcreate table addresses (address ipaddr);
> X
> X-- sample data from two subnets:
> Xinsert into addresses values ('158.37.96.15');
> Xinsert into addresses values ('158.37.96.16');
> Xinsert into addresses values ('158.37.96.17');
> Xinsert into addresses values ('158.37.97.15');
> Xinsert into addresses values ('158.37.97.16');
> Xinsert into addresses values ('158.37.97.17');
> Xinsert into addresses values ('158.37.98.15');
> Xinsert into addresses values ('158.37.98.16');
> Xinsert into addresses values ('158.37.98.17');
> Xinsert into addresses values ('158.37.96.150');
> Xinsert into addresses values ('158.37.96.160');
> Xinsert into addresses values ('158.37.96.170');
> Xinsert into addresses values ('158.37.97.150');
> Xinsert into addresses values ('158.37.97.160');
> Xinsert into addresses values ('158.37.97.170');
> Xinsert into addresses values ('158.37.98.150');
> Xinsert into addresses values ('158.37.98.160');
> Xinsert into addresses values ('158.37.98.170');
> X
> X-- show them all:
> Xselect * from addresses;
> X
> X-- select the ones in subnet 96:
> Xselect * from addresses where address << '158.37.96.0/24';
> X
> X-- select the ones not in subnet 96:
> Xselect * from addresses where not address << '158.37.96.0/24';
> X
> X-- select the ones in subnet 97:
> Xselect * from addresses where address << '158.37.97.0/24';
> X
> X-- select the ones not in subnet 97:
> Xselect * from addresses where not address << '158.37.97.0/24';
> X
> X-- select the ones in subnet 96 or 97, sorted:
> Xselect * from addresses where address << '158.37.96.0/23'
> X    order by address;
> X
> X-- now some networks:
> Xcreate table networks (network ipaddr);
> X
> X-- now the subnets mentioned above:
> Xinsert into networks values ('158.37.96.0/24');
> Xinsert into networks values ('158.37.97.0/24');
> Xinsert into networks values ('158.37.98.0/24');
> X
> X-- select matching pairs of addresses and containing nets:
> Xselect address, network from addresses, networks
> X    where address << network;
> X
> X-- tidy up:
> Xdrop table addresses;
> Xdrop table networks;
> X
> X--
> X--    eof
> X--
> END-of-test.sql
> exit
>


--
Bruce Momjian                          |  830 Blythe Avenue
maillist@candle.pha.pa.us              |  Drexel Hill, Pennsylvania 19026
  +  If your life is a hard drive,     |  (610) 353-9879(w)
  +  Christ can be your backup.        |  (610) 853-3000(h)

Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Paul A Vixie
Дата:
golden!  ship that puppy!

Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Bruce Momjian
Дата:
Merged into the current source tree.  Please test.


> Bruce Momjian <maillist@candle.pha.pa.us> writes:
>
> > Is this the version you want me to install in the current source tree?
>
> Yup.  It seems to work right, so it's what I'm using right now.  As
> soon as I've got an IPV6 kit installed here, I'll expand it with code
> to handle that data type -- as you can see, I've left comments all
> over the code showing what needs to be done for that.  I reckon the
> thing to do is for you to get it properly into the tree, and then I'll
> do further maintenance on that code, and send patches.
>
> The SQL code to set up indexing capability doesn't work after your
> changes to add OIDs to various names, but I guess that's irrelevant
> when you integrate it into the base system, right?  As for the MAC
> level ethernet address stuff, if you want to add that as well, I guess
> we should consider replacing the hard-coded table of manufacturers
> with a table in template1 -- that is the SQL way, after all.  Also,
> the names of these types should maybe be changed?  I use "ipaddr" and
> "macaddr", but I can't remember if consensus was reached on whether
> the IP address data type should be "cidr", or "inet", or what...  If
> you want me to go through the code and change that before you do the
> integration, just let me know.
>
> -tih
> --
> Popularity is the hallmark of mediocrity.  --Niles Crane, "Frasier"
>


--
  Bruce Momjian                        |  http://www.op.net/~candle
  maillist@candle.pha.pa.us            |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026


Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
"Marc G. Fournier"
Дата:
On Sat, 3 Oct 1998, Bruce Momjian wrote:

> Merged into the current source tree.  Please test.
>
>
> > Bruce Momjian <maillist@candle.pha.pa.us> writes:
> >
> > > Is this the version you want me to install in the current source tree?
> >
> > Yup.  It seems to work right, so it's what I'm using right now.  As
> > soon as I've got an IPV6 kit installed here, I'll expand it with code
> > to handle that data type -- as you can see, I've left comments all
> > over the code showing what needs to be done for that.  I reckon the
> > thing to do is for you to get it properly into the tree, and then I'll
> > do further maintenance on that code, and send patches.
> >
> > The SQL code to set up indexing capability doesn't work after your
> > changes to add OIDs to various names, but I guess that's irrelevant
> > when you integrate it into the base system, right?  As for the MAC
> > level ethernet address stuff, if you want to add that as well, I guess
> > we should consider replacing the hard-coded table of manufacturers
> > with a table in template1 -- that is the SQL way, after all.  Also,
> > the names of these types should maybe be changed?  I use "ipaddr" and
> > "macaddr", but I can't remember if consensus was reached on whether
> > the IP address data type should be "cidr", or "inet", or what...  If

    *Please* make the appropriate changes and submit a patch...it
should be listed as CIDR, not as IPADDR.  MACADDR, IMHO, is okay, as its
the only way I've ever heard of it being referred...but I do not consider
IPADDR to be correct terminology...


Marc G. Fournier                               scrappy@hub.org
Systems Administrator @ hub.org
scrappy@{postgresql|isc}.org                       ICQ#7615664


Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Bruce Momjian
Дата:
>     *Please* make the appropriate changes and submit a patch...it
> should be listed as CIDR, not as IPADDR.  MACADDR, IMHO, is okay, as its
> the only way I've ever heard of it being referred...but I do not consider
> IPADDR to be correct terminology...

That is OK, but just let me that CIDR is for networks addresses, and
this type supports both host and network addresses.

Attached is a message from Paul Vixie mentioning this issue.  It argues
for the use of INET, rather than CIDR or IPADDR.

---------------------------------------------------------------------------


Replies to three messages here.

> From: Bruce Momjian <maillist@candle.pha.pa.us>
> Date: Tue, 21 Jul 1998 01:13:34 -0400 (EDT)
>
> The only problem is that if we assume /32, how do we auto-netmask class
> A/B/C addresses?  I guess we don't.  If they want a netmask, they are
> going to have to specify it in cidr format.

Right.  But read on -- what you're calling a netmask is really a
prefix length, and I think there's some confusion as to what it is.

> I will be honest.  I always found the network/host IP address
> distinction to be very unclearly outlined in old/non-cidr address
> displays, and this causes major confusion for me when trying to figure
> out how things are configured.

Me too.

> I like INET too.  It is up to you.

How do folks feel about polymorphism between IPv4 and IPv6?  Should we (a)
make it work (either by making internal_length=10 or going variable length)
or (b) just make this thing IPv4 only and take care of IPv6 separately/later?

I've started to wonder if we ought to call the type INET and limit it to V4.
(In the C socket bindings, IPv6 addresses are in_addr6 / sockaddr_in6, and
the address family is AF_INET6 -- I don't know whether to plan on reflecting
this in the postgres types, i.e., use a separate one for IPv6, or not.)

> From: Bruce Momjian <maillist@candle.pha.pa.us>
> Date: Tue, 21 Jul 1998 01:30:05 -0400 (EDT)
>
> > ...  but why would you want to know the mantissa without the scale?
>
> I guess I thought someone might want to have ipaddr() and netmask()
> functions so they can do:
>
>     x = 192.7.34.21/24
>     ipaddr(x)  -> 192.7.34.21
>     netmask(x) -> 255.255.255.0

This is the downreference from above.  It does not work that way.  /24 is
not a shorthand for specifying a netmask -- in CIDR, it's a "prefix length".
That means "192.7.34.21/24" is either (a) a syntax error or (b) equivilent
to "192.7.34/24".

Btw, it appears from my research that the BIND functions *do* impute a "class"
if (a) no "/width" is specified and (b) the classful interpretation would be
longer than the classless interpretation.  No big deal but it qualifies
something I said earlier so I thought I'd mention it.

>     x = 192.7.0.0/16
>     ipaddr(x)  -> 192.7.0.0
>     netmask(x) -> 255.255.0.0
>
> These function are defined on the cidr type, and can be called if
> someone wants the old output format.

Can we wait and see if someone misses / asks for these before we make them?

> ..., the 127.1 ambiguity was very strange.  netstat -rn is very hard to
> understand using the old format.

I was amazed at the number of people who had hardwired "127.1" though :-(.

> From: Bruce Momjian <maillist@candle.pha.pa.us>
> Date: Tue, 21 Jul 1998 01:33:41 -0400 (EDT)
>
> Doing complex stuff like indexing with contrib stuff is tricky, and one
> reason we want to move stuff out of there as it becomes popular.  It is
> just too hard for someone not experienced with the code to implement.
> Add to this the fact that the oid at the time of contrib installation
> will change every time you install it, so it is even harder/impossible
> to automate.

Perhaps we ought to make new type insertion easier since it's so cool?




--
  Bruce Momjian                        |  http://www.op.net/~candle
  maillist@candle.pha.pa.us            |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026


Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Tom Ivar Helbekkmo
Дата:
"Marc G. Fournier" <scrappy@hub.org> writes:

>     *Please* make the appropriate changes and submit a patch...it
> should be listed as CIDR, not as IPADDR.  MACADDR, IMHO, is okay, as its
> the only way I've ever heard of it being referred...but I do not consider
> IPADDR to be correct terminology...

I agree.  I think, though, that the best argument presented in the
debate was from Paul Vixie, who wanted INET to be the name covering
both IPV4 and IPV6.  The following kit makes the needed changes:

WARNING!  This posting contains two separate patch kits, to be applied
at different times, renaming a couple of files in between them!  The
steps to be taken are marked with "[***]".

[***] First apply these patches to change ipaddr to inet.  Affected files are:

- src/backend/utils/adt/ip.c
- src/include/catalog/pg_opclass.h
- src/include/catalog/pg_operator.h
- src/include/catalog/pg_proc.h
- src/include/catalog/pg_type.h
- src/include/utils/builtins.h
- src/include/utils/mac.h
- src/tools/pgindent/pgindent

Index: src/backend/utils/adt/ip.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/utils/adt/ip.c,v
retrieving revision 1.4
diff -r1.4 ip.c
2c2
<  *    PostgreSQL type definitions for IP addresses.  This
---
>  *    PostgreSQL type definitions for the INET type.  This
23a24,25
> static int v4bitncmp(unsigned int a1, unsigned int a2, int bits);
>
28,29c30,31
< #define ip_addrsize(ipaddrptr) \
<     (((ipaddr_struct *)VARDATA(ipaddrptr))->family == AF_INET ? 4 : -1)
---
> #define ip_addrsize(inetptr) \
>     (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1)
31,32c33,34
< #define ip_family(ipaddrptr) \
<     (((ipaddr_struct *)VARDATA(ipaddrptr))->family)
---
> #define ip_family(inetptr) \
>     (((inet_struct *)VARDATA(inetptr))->family)
34,35c36,37
< #define ip_bits(ipaddrptr) \
<     (((ipaddr_struct *)VARDATA(ipaddrptr))->bits)
---
> #define ip_bits(inetptr) \
>     (((inet_struct *)VARDATA(inetptr))->bits)
37,38c39,40
< #define ip_v4addr(ipaddrptr) \
<     (((ipaddr_struct *)VARDATA(ipaddrptr))->addr.ipv4_addr)
---
> #define ip_v4addr(inetptr) \
>     (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
44,45c46,47
< ipaddr *
< ipaddr_in(char *src)
---
> inet *
> inet_in(char *src)
48c50
<     ipaddr       *dst;
---
>     inet       *dst;
50c52
<     dst = palloc(VARHDRSZ + sizeof(ipaddr_struct));
---
>     dst = palloc(VARHDRSZ + sizeof(inet_struct));
53c55
<         elog(ERROR, "unable to allocate memory in ipaddr_in()");
---
>         elog(ERROR, "unable to allocate memory in inet_in()");
78c80
< ipaddr_out(ipaddr *src)
---
> inet_out(inet *src)
102c104
<         elog(ERROR, "unable to allocate memory in ipaddr_out()");
---
>         elog(ERROR, "unable to allocate memory in inet_out()");
114c116
< ipaddr_lt(ipaddr *a1, ipaddr *a2)
---
> inet_lt(inet *a1, inet *a2)
132c134
< ipaddr_le(ipaddr *a1, ipaddr *a2)
---
> inet_le(inet *a1, inet *a2)
134c136
<     return (ipaddr_lt(a1, a2) || ipaddr_eq(a1, a2));
---
>     return (inet_lt(a1, a2) || inet_eq(a1, a2));
138c140
< ipaddr_eq(ipaddr *a1, ipaddr *a2)
---
> inet_eq(inet *a1, inet *a2)
155c157
< ipaddr_ge(ipaddr *a1, ipaddr *a2)
---
> inet_ge(inet *a1, inet *a2)
157c159
<     return (ipaddr_gt(a1, a2) || ipaddr_eq(a1, a2));
---
>     return (inet_gt(a1, a2) || inet_eq(a1, a2));
161c163
< ipaddr_gt(ipaddr *a1, ipaddr *a2)
---
> inet_gt(inet *a1, inet *a2)
179c181
< ipaddr_ne(ipaddr *a1, ipaddr *a2)
---
> inet_ne(inet *a1, inet *a2)
181c183
<     return (!ipaddr_eq(a1, a2));
---
>     return (!inet_eq(a1, a2));
185c187
< ipaddr_sub(ipaddr *a1, ipaddr *a2)
---
> inet_sub(inet *a1, inet *a2)
202c204
< ipaddr_subeq(ipaddr *a1, ipaddr *a2)
---
> inet_subeq(inet *a1, inet *a2)
219c221
< ipaddr_sup(ipaddr *a1, ipaddr *a2)
---
> inet_sup(inet *a1, inet *a2)
236c238
< ipaddr_supeq(ipaddr *a1, ipaddr *a2)
---
> inet_supeq(inet *a1, inet *a2)
257c259
< ipaddr_cmp(ipaddr *a1, ipaddr *a2)
---
> inet_cmp(inet *a1, inet *a2)
270c272
< int
---
> static int
Index: src/include/catalog/pg_opclass.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_opclass.h,v
retrieving revision 1.12
diff -r1.12 pg_opclass.h
112c112
< DATA(insert OID = 935  (    ipaddr_ops   869   ));
---
> DATA(insert OID = 935  (    inet_ops   869   ));
Index: src/include/catalog/pg_operator.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_operator.h,v
retrieving revision 1.39
diff -r1.39 pg_operator.h
647,656c647,656
< DATA(insert OID = 1201 (  "="       PGUID 0 b t t 869 869     16 1201 1202 0 0 ipaddr_eq eqsel eqjoinsel ));
< DATA(insert OID = 1202 (  "<>"       PGUID 0 b t f 869 869     16 1202 1201 0 0 ipaddr_ne neqsel neqjoinsel ));
< DATA(insert OID = 1203 (  "<"       PGUID 0 b t f 869 869     16 1205 1206 0 0 ipaddr_lt intltsel intltjoinsel ));
< DATA(insert OID = 1204 (  "<="       PGUID 0 b t f 869 869     16 1206 1205 0 0 ipaddr_le intltsel intltjoinsel ));
< DATA(insert OID = 1205 (  ">"       PGUID 0 b t f 869 869     16 1203 1204 0 0 ipaddr_gt intltsel intltjoinsel ));
< DATA(insert OID = 1206 (  ">="       PGUID 0 b t f 869 869     16 1204 1203 0 0 ipaddr_ge intltsel intltjoinsel ));
< DATA(insert OID = 931  (  "<<"       PGUID 0 b t f 869 869     16 933  934  0 0 ipaddr_sub intltsel intltjoinsel ));
< DATA(insert OID = 932  (  "<<="       PGUID 0 b t f 869 869     16 934  933  0 0 ipaddr_subeq intltsel intltjoinsel
));
< DATA(insert OID = 933  (  ">>"       PGUID 0 b t f 869 869     16 931  932  0 0 ipaddr_sup intltsel intltjoinsel ));
< DATA(insert OID = 934  (  ">>="       PGUID 0 b t f 869 869     16 932  931  0 0 ipaddr_supeq intltsel intltjoinsel
));
---
> DATA(insert OID = 1201 (  "="       PGUID 0 b t t 869 869     16 1201 1202 0 0 inet_eq eqsel eqjoinsel ));
> DATA(insert OID = 1202 (  "<>"       PGUID 0 b t f 869 869     16 1202 1201 0 0 inet_ne neqsel neqjoinsel ));
> DATA(insert OID = 1203 (  "<"       PGUID 0 b t f 869 869     16 1205 1206 0 0 inet_lt intltsel intltjoinsel ));
> DATA(insert OID = 1204 (  "<="       PGUID 0 b t f 869 869     16 1206 1205 0 0 inet_le intltsel intltjoinsel ));
> DATA(insert OID = 1205 (  ">"       PGUID 0 b t f 869 869     16 1203 1204 0 0 inet_gt intltsel intltjoinsel ));
> DATA(insert OID = 1206 (  ">="       PGUID 0 b t f 869 869     16 1204 1203 0 0 inet_ge intltsel intltjoinsel ));
> DATA(insert OID = 931  (  "<<"       PGUID 0 b t f 869 869     16 933  934  0 0 inet_sub intltsel intltjoinsel ));
> DATA(insert OID = 932  (  "<<="       PGUID 0 b t f 869 869     16 934  933  0 0 inet_subeq intltsel intltjoinsel ));
> DATA(insert OID = 933  (  ">>"       PGUID 0 b t f 869 869     16 931  932  0 0 inet_sup intltsel intltjoinsel ));
> DATA(insert OID = 934  (  ">>="       PGUID 0 b t f 869 869     16 932  931  0 0 inet_supeq intltsel intltjoinsel ));
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.71
diff -r1.71 pg_proc.h
2072c2072
< DATA(insert OID = 910 (  ipaddr_in            PGUID 11 f t f 1 f 869 "0" 100 0 0 100    foo bar ));
---
> DATA(insert OID = 910 (  inet_in            PGUID 11 f t f 1 f 869 "0" 100 0 0 100    foo bar ));
2074c2074
< DATA(insert OID = 911 (  ipaddr_out            PGUID 11 f t f 1 f 23 "0" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 911 (  inet_out            PGUID 11 f t f 1 f 23 "0" 100 0 0 100  foo bar ));
2077c2077
< DATA(insert OID = 920 (  ipaddr_eq           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 920 (  inet_eq           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2079c2079
< DATA(insert OID = 921 (  ipaddr_lt           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 921 (  inet_lt           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2081c2081
< DATA(insert OID = 922 (  ipaddr_le           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 922 (  inet_le           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2083c2083
< DATA(insert OID = 923 (  ipaddr_gt           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 923 (  inet_gt           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2085c2085
< DATA(insert OID = 924 (  ipaddr_ge           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 924 (  inet_ge           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2087c2087
< DATA(insert OID = 925 (  ipaddr_ne           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 925 (  inet_ne           PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2089c2089
< DATA(insert OID = 926 (  ipaddr_cmp              PGUID 11 f t f 2 f 23 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 926 (  inet_cmp              PGUID 11 f t f 2 f 23 "869 869" 100 0 0 100  foo bar ));
2091c2091
< DATA(insert OID = 927 (  ipaddr_sub              PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 927 (  inet_sub              PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2093c2093
< DATA(insert OID = 928 (  ipaddr_subeq         PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 928 (  inet_subeq         PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2095c2095
< DATA(insert OID = 929 (  ipaddr_sup              PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 929 (  inet_sup              PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
2097c2097
< DATA(insert OID = 930 (  ipaddr_supeq         PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
---
> DATA(insert OID = 930 (  inet_supeq         PGUID 11 f t f 2 f 16 "869 869" 100 0 0 100  foo bar ));
Index: src/include/catalog/pg_type.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/catalog/pg_type.h,v
retrieving revision 1.48
diff -r1.48 pg_type.h
303c303
< DATA(insert OID = 869 ( ipaddr       PGUID  -1 -1 f b t \054 0 0 ipaddr_in ipaddr_out ipaddr_in ipaddr_out i _null_
));
---
> DATA(insert OID = 869 ( inet       PGUID  -1 -1 f b t \054 0 0 inet_in inet_out inet_in inet_out i _null_ ));
342c342
< DATA(insert OID = 1041 (  _ipaddr    PGUID -1 -1 f b t \054 0  869 array_in array_out array_in array_out i _null_ ));
---
> DATA(insert OID = 1041 (  _inet    PGUID -1 -1 f b t \054 0  869 array_in array_out array_in array_out i _null_ ));
Index: src/include/utils/builtins.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.57
diff -r1.57 builtins.h
522,535c522,534
< ipaddr       *ipaddr_in(char *str);
< char       *ipaddr_out(ipaddr * addr);
< bool        ipaddr_lt(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_le(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_eq(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_ge(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_gt(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_ne(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_sub(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_subeq(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_sup(ipaddr * a1, ipaddr * a2);
< bool        ipaddr_supeq(ipaddr * a1, ipaddr * a2);
< int4        ipaddr_cmp(ipaddr * a1, ipaddr * a2);
< int            v4bitncmp(unsigned int a1, unsigned int a2, int bits);
---
> inet       *inet_in(char *str);
> char       *inet_out(inet * addr);
> bool        inet_lt(inet * a1, inet * a2);
> bool        inet_le(inet * a1, inet * a2);
> bool        inet_eq(inet * a1, inet * a2);
> bool        inet_ge(inet * a1, inet * a2);
> bool        inet_gt(inet * a1, inet * a2);
> bool        inet_ne(inet * a1, inet * a2);
> bool        inet_sub(inet * a1, inet * a2);
> bool        inet_subeq(inet * a1, inet * a2);
> bool        inet_sup(inet * a1, inet * a2);
> bool        inet_supeq(inet * a1, inet * a2);
> int4        inet_cmp(inet * a1, inet * a2);
Index: src/include/utils/mac.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/utils/mac.h,v
retrieving revision 1.2
diff -r1.2 mac.h
29c29
< }            ipaddr_struct;
---
> }            inet_struct;
31c31
< typedef struct varlena ipaddr;
---
> typedef struct varlena inet;
Index: src/tools/pgindent/pgindent
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/tools/pgindent/pgindent,v
retrieving revision 1.11
diff -r1.11 pgindent
789c789
< -Tipaddr \
---
> -Tinet \

[***] Then, some renaming is in order:

- rename doc/README.ipaddr to doc/README.inet
- rename src/backend/utils/adt/ip.c to src/backend/utils/adt/inet.c
- rename src/include/utils/mac.h to src/include/utils/network.h

[***] Finally, apply these patches to reflect the renaming.  Files are:

- src/backend/utils/adt/Makefile
- src/backend/utils/adt/inet.c
- src/backend/utils/adt/mac.c
- src/include/utils/builtins.h

*** src/backend/utils/adt/Makefile.old    Wed Oct  7 10:45:34 1998
--- src/backend/utils/adt/Makefile    Wed Oct  7 10:46:38 1998
***************
*** 24,30 ****
      oid.o oracle_compat.o \
      regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
      tid.o timestamp.o varchar.o varlena.o version.o \
!     ip.o mac.o inet_net_ntop.o inet_net_pton.o

  all: SUBSYS.o

--- 24,30 ----
      oid.o oracle_compat.o \
      regexp.o regproc.o ruleutils.o selfuncs.o sets.o \
      tid.o timestamp.o varchar.o varlena.o version.o \
!     inet.o mac.o inet_net_ntop.o inet_net_pton.o

  all: SUBSYS.o

*** src/backend/utils/adt/inet.c.old    Wed Oct  7 10:45:38 1998
--- src/backend/utils/adt/inet.c    Wed Oct  7 10:46:52 1998
***************
*** 19,25 ****
  #include <postgres.h>
  #include <utils/palloc.h>
  #include <utils/builtins.h>
! #include <utils/mac.h>

  static int v4bitncmp(unsigned int a1, unsigned int a2, int bits);

--- 19,25 ----
  #include <postgres.h>
  #include <utils/palloc.h>
  #include <utils/builtins.h>
! #include <utils/network.h>

  static int v4bitncmp(unsigned int a1, unsigned int a2, int bits);

*** src/backend/utils/adt/mac.c.old    Wed Oct  7 10:45:43 1998
--- src/backend/utils/adt/mac.c    Wed Oct  7 10:47:11 1998
***************
*** 10,16 ****
  #include <postgres.h>
  #include <utils/palloc.h>
  #include <utils/builtins.h>
! #include <utils/mac.h>

  manufacturer manufacturers[] = {
    {0x00, 0x00, 0x0C, "Cisco"},
--- 10,16 ----
  #include <postgres.h>
  #include <utils/palloc.h>
  #include <utils/builtins.h>
! #include <utils/network.h>

  manufacturer manufacturers[] = {
    {0x00, 0x00, 0x0C, "Cisco"},
*** src/include/utils/builtins.h.old    Wed Oct  7 10:45:54 1998
--- src/include/utils/builtins.h    Wed Oct  7 10:47:28 1998
***************
*** 28,34 ****
  #include <utils/nabstime.h>
  #include <utils/int8.h>
  #include <utils/cash.h>
! #include <utils/mac.h>
  #include <utils/rel.h>

  /*
--- 28,34 ----
  #include <utils/nabstime.h>
  #include <utils/int8.h>
  #include <utils/cash.h>
! #include <utils/network.h>
  #include <utils/rel.h>

  /*
***************
*** 518,524 ****
  /* inet_net_pton.c */
  int inet_net_pton(int af, const char *src, void *dst, size_t size);

! /* ip.c */
  inet       *inet_in(char *str);
  char       *inet_out(inet * addr);
  bool        inet_lt(inet * a1, inet * a2);
--- 518,524 ----
  /* inet_net_pton.c */
  int inet_net_pton(int af, const char *src, void *dst, size_t size);

! /* inet.c */
  inet       *inet_in(char *str);
  char       *inet_out(inet * addr);
  bool        inet_lt(inet * a1, inet * a2);

[***] Hope that I got it right!  "It works for me."  :-)

-tih
--
Popularity is the hallmark of mediocrity.  --Niles Crane, "Frasier"

Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
Bruce Momjian
Дата:
Applied.

Thomas, did remove the README.ip, or did you leave it when you decided
to merge it into the docs.  I still show it here, so I am renaming it.



> "Marc G. Fournier" <scrappy@hub.org> writes:
>
> >     *Please* make the appropriate changes and submit a patch...it
> > should be listed as CIDR, not as IPADDR.  MACADDR, IMHO, is okay, as its
> > the only way I've ever heard of it being referred...but I do not consider
> > IPADDR to be correct terminology...
>
> I agree.  I think, though, that the best argument presented in the
> debate was from Paul Vixie, who wanted INET to be the name covering
> both IPV4 and IPV6.  The following kit makes the needed changes:
>
> WARNING!  This posting contains two separate patch kits, to be applied
> at different times, renaming a couple of files in between them!  The
> steps to be taken are marked with "[***]".
>
> [***] First apply these patches to change ipaddr to inet.  Affected files are:


--
  Bruce Momjian                        |  http://www.op.net/~candle
  maillist@candle.pha.pa.us            |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026


Re: [HACKERS] Re: CIDR/IP types. Was: [GENERAL] big numbers

От
"Thomas G. Lockhart"
Дата:
> Thomas, did remove the README.ip, or did you leave it when you decided
> to merge it into the docs.  I still show it here, so I am renaming it.

I have not yet merged it; it is on my ToDo list for documenting along
with the other new datatypes INT8 and SERIAL. We should leave it in the
README until I do the merge, just in case...

                   - Tom