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:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user