1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-09 06:21:09 +03:00

Add INET/CIDR operators: and, or, not, plus int8, minus int8, and inet

minus inet.

Stephen R. van den Berg
This commit is contained in:
Bruce Momjian
2006-02-11 03:32:41 +00:00
parent 9bf2ac2a40
commit 1372515271
7 changed files with 411 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
/*
* PostgreSQL type definitions for the INET and CIDR types.
*
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.63 2006/02/07 17:04:04 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.64 2006/02/11 03:32:39 momjian Exp $
*
* Jon Postel RIP 16 Oct 1998
*/
@@ -27,6 +27,7 @@ static int32 network_cmp_internal(inet *a1, inet *a2);
static int bitncmp(void *l, void *r, int n);
static bool addressOK(unsigned char *a, int bits, int family);
static int ip_addrsize(inet *inetptr);
static Datum internal_inetpl(inet *ip, int64 iarg);
/*
* Access macros.
@@ -1250,3 +1251,208 @@ inet_server_port(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port)));
}
Datum
inetnot(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
inet *dst;
dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
{
int nb = ip_addrsize(ip);
unsigned char *pip = ip_addr(ip);
unsigned char *pdst = ip_addr(dst);
while (nb-- > 0)
pdst[nb] = ~pip[nb];
}
ip_bits(dst) = ip_bits(ip);
ip_family(dst) = ip_family(ip);
VARATT_SIZEP(dst) = VARHDRSZ +
((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
ip_addrsize(dst);
PG_RETURN_INET_P(dst);
}
Datum
inetand(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
inet *ip2 = PG_GETARG_INET_P(1);
inet *dst;
dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
if (ip_family(ip) != ip_family(ip2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("mismatch in address family (%d) != (%d)",
ip_family(ip), ip_family(ip2))));
else
{
int nb = ip_addrsize(ip);
unsigned char *pip = ip_addr(ip);
unsigned char *pip2 = ip_addr(ip2);
unsigned char *pdst = ip_addr(dst);
while (nb-- > 0)
pdst[nb] = pip[nb] & pip2[nb];
}
ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
ip_family(dst) = ip_family(ip);
VARATT_SIZEP(dst) = VARHDRSZ +
((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
ip_addrsize(dst);
PG_RETURN_INET_P(dst);
}
Datum
inetor(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
inet *ip2 = PG_GETARG_INET_P(1);
inet *dst;
dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
if (ip_family(ip) != ip_family(ip2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("mismatch in address family (%d) != (%d)",
ip_family(ip), ip_family(ip2))));
else
{
int nb = ip_addrsize(ip);
unsigned char *pip = ip_addr(ip);
unsigned char *pip2 = ip_addr(ip2);
unsigned char *pdst = ip_addr(dst);
while (nb-- > 0)
pdst[nb] = pip[nb] | pip2[nb];
}
ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
ip_family(dst) = ip_family(ip);
VARATT_SIZEP(dst) = VARHDRSZ +
((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
ip_addrsize(dst);
PG_RETURN_INET_P(dst);
}
static Datum
internal_inetpl(inet *ip, int64 plus)
{
inet *dst;
dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct));
{
int nb = ip_addrsize(ip);
unsigned char *pip = ip_addr(ip);
unsigned char *pdst = ip_addr(dst);
int carry = 0;
while (nb-- > 0)
{
pdst[nb] = carry = pip[nb] + plus + carry;
plus /= 0x100; /* process next byte */
carry /= 0x100; /* remove low byte */
/* Overflow on high byte? */
if (nb == 0 && (plus != 0 || carry != 0))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result out of range")));
}
}
ip_bits(dst) = ip_bits(ip);
ip_family(dst) = ip_family(ip);
VARATT_SIZEP(dst) = VARHDRSZ +
((char *) ip_addr(dst) - (char *) VARDATA(dst)) +
ip_addrsize(dst);
PG_RETURN_INET_P(dst);
}
Datum
inetpl(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
int64 plus = PG_GETARG_INT64(1);
return internal_inetpl(ip, plus);
}
Datum
inetmi_int8(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
int64 plus = PG_GETARG_INT64(1);
return internal_inetpl(ip, -plus);
}
Datum
inetmi(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
inet *ip2 = PG_GETARG_INET_P(1);
int64 res = 0;
if (ip_family(ip) != ip_family(ip2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("mismatch in address family (%d) != (%d)",
ip_family(ip), ip_family(ip2))));
else
{
int nb = ip_addrsize(ip);
int byte = 0;
unsigned char *pip = ip_addr(ip);
unsigned char *pip2 = ip_addr(ip2);
while (nb-- > 0)
{
/*
* Error if overflow on last byte. This test is tricky
* because if the subtraction == 128 and res is negative, or
* if subtraction == -128 and res is positive, the result
* would still fit in int64.
*/
if (byte + 1 == sizeof(int64) &&
(pip[nb] - pip2[nb] >= 128 + (res < 0) ||
pip[nb] - pip2[nb] <= -128 - (res > 0)))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result out of range")));
if (byte >= sizeof(int64))
{
/* Error if bytes beyond int64 length differ. */
if (pip[nb] != pip2[nb])
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("result out of range")));
}
else
res += (int64)(pip[nb] - pip2[nb]) << (byte * 8);
byte++;
}
}
PG_RETURN_INT64(res);
}