Re: CIDR/IP types. Was: [GENERAL] big numbers - Mailing list pgsql-hackers
From | Bruce Momjian |
---|---|
Subject | Re: CIDR/IP types. Was: [GENERAL] big numbers |
Date | |
Msg-id | 199809081507.LAA10039@candle.pha.pa.us Whole thread Raw |
In response to | Re: CIDR/IP types. Was: [GENERAL] big numbers (Tom Ivar Helbekkmo <tih@nhh.no>) |
List | pgsql-hackers |
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)
pgsql-hackers by date: