aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/network.c')
-rw-r--r--src/backend/utils/adt/network.c208
1 files changed, 207 insertions, 1 deletions
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index c7ce7b6a307..64daefa0294 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -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);
+}