On Mon, Sep 05, 2005 at 08:10:16PM +0100, Patrick Welche wrote: > On Mon, Sep 05, 2005 at 03:02:55PM -0400, Tom Lane wrote: > > Patrick Welche <[EMAIL PROTECTED]> writes: > > > * Allow INET + INT4 to increment the host part of the address, or > > > throw an error on overflow > > > > > I think that the naively coded function attached does what is needed, > > > e.g., > > > > What happened to the IPv6 case? > > My take on the thread is that the IPv6 case doesn't make sense, and the > int8 part was dropped from the TODO. > > > Also, I think you need to reject CIDR inputs. > > OK
Now with: test=# select '192.168.0.0/24'::inet + 1; ERROR: Trying to increment a network (192.168.0.0/24) rather than a host test=# select '192.168.0.1/24'::inet + -1; ERROR: Increment returns a network (192.168.0.0/24) rather than a host Cheers, Patrick
/* From the TODO: * Allow INET + INT4 to increment the host part of the address, or * throw an error on overflow */ #include "postgres.h" #include <sys/socket.h> #include "fmgr.h" #include "utils/inet.h" PG_FUNCTION_INFO_V1(inet_inc); Datum inet_inc(PG_FUNCTION_ARGS) { inet *in = PG_GETARG_INET_P(0), *out; int32 inc = PG_GETARG_INT32(1); inet_struct *src, *dst; uint32 netmask, host, newhost; int i; src = (inet_struct *)VARDATA(in); if (src->family != PGSQL_AF_INET) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Function \"inet_inc\" only supports AF_INET " "addresses"))); /* avoid int32 overflow when bits == 0 */ netmask = (src->bits == 0) ? 0 : (~((1 << (32 - src->bits)) - 1)); /* if (inc doesn't fit in src->bits) overflow */ if ((abs(inc) & ~netmask) != abs(inc)) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Increment (%d) too big for network (/%d)", inc, src->bits))); /* can do this with htonl/ntohl */ host = 0; for (i=0; i<4; ++i) host |= src->ipaddr[i] << (8 * (3-i)); if ((host & ~netmask) == 0) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Trying to increment a network (%d.%d.%d.%d/%d) rather " "than a host", src->ipaddr[0], src->ipaddr[1], src->ipaddr[2], src->ipaddr[3], src->bits))); newhost = host + inc; if (((host & netmask) != (newhost & netmask)) || (inc>0 && newhost<host) || (inc<0 && newhost>host)) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Increment (%d) takes address (%d.%d.%d.%d) out of its " "network (/%d)", inc, src->ipaddr[0], src->ipaddr[1], src->ipaddr[2], src->ipaddr[3], src->bits))); out = (inet *)palloc0(VARHDRSZ + sizeof(inet_struct)); dst = (inet_struct *)VARDATA(out); dst->family = src->family; dst->bits = src->bits; dst->type = src->type; for (i=0; i<4; ++i) dst->ipaddr[i] = (newhost >> (8 * (3-i))) & 0xff; for (i=4; i<16; ++i) dst->ipaddr[i] = 0; if ((inc < 0) && (newhost & ~netmask) == 0) ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION), errmsg("Increment returns a network (%d.%d.%d.%d/%d) rather " "than a host", dst->ipaddr[0], dst->ipaddr[1], dst->ipaddr[2], dst->ipaddr[3], dst->bits))); VARATT_SIZEP(out) = VARHDRSZ + sizeof(dst->family) + sizeof(dst->bits) + sizeof(dst->type) + 4; PG_RETURN_INET_P(out); }
---------------------------(end of broadcast)--------------------------- TIP 9: In versions below 8.0, the planner will ignore your desire to choose an index scan if your joining column's datatypes do not match