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.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index 3a705da6197..1f8469a2cbc 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -888,6 +888,58 @@ network_hostmask(PG_FUNCTION_ARGS)
}
/*
+ * Returns true if the addresses are from the same family, or false. Used to
+ * check that we can create a network which contains both of the networks.
+ */
+Datum
+inet_same_family(PG_FUNCTION_ARGS)
+{
+ inet *a1 = PG_GETARG_INET_PP(0);
+ inet *a2 = PG_GETARG_INET_PP(1);
+
+ PG_RETURN_BOOL(ip_family(a1) == ip_family(a2));
+}
+
+/*
+ * Returns the smallest CIDR which contains both of the inputs.
+ */
+Datum
+inet_merge(PG_FUNCTION_ARGS)
+{
+ inet *a1 = PG_GETARG_INET_PP(0),
+ *a2 = PG_GETARG_INET_PP(1),
+ *result;
+ int commonbits;
+
+ if (ip_family(a1) != ip_family(a2))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot merge addresses from different families")));
+
+ commonbits = bitncommon(ip_addr(a1), ip_addr(a2),
+ Min(ip_bits(a1), ip_bits(a2)));
+
+ /* Make sure any unused bits are zeroed. */
+ result = (inet *) palloc0(sizeof(inet));
+
+ ip_family(result) = ip_family(a1);
+ ip_bits(result) = commonbits;
+
+ /* Clone appropriate bytes of the address. */
+ if (commonbits > 0)
+ memcpy(ip_addr(result), ip_addr(a1), (commonbits + 7) / 8);
+
+ /* Clean any unwanted bits in the last partial byte. */
+ if (commonbits % 8 != 0)
+ ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8));
+
+ /* Set varlena header correctly. */
+ SET_INET_VARSIZE(result);
+
+ PG_RETURN_INET_P(result);
+}
+
+/*
* Convert a value of a network datatype to an approximate scalar value.
* This is used for estimating selectivities of inequality operators
* involving network types.