diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index a411e3a..7f1212d 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -8396,6 +8396,16 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
inet '192.168.1/24' >>= inet '192.168.1/24'
+ &&
+ overlaps
+ inet '192.168.1/24' && inet '192.168.1/24'
+
+
+ -|-
+ is adjacent to
+ inet '192.168.1/24' -|- inet '192.168.1/24'
+
+
~
bitwise NOT
~ inet '192.168.1.6'
diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile
index 41a8982..31590e3 100644
--- a/src/backend/utils/adt/Makefile
+++ b/src/backend/utils/adt/Makefile
@@ -24,7 +24,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \
oid.o oracle_compat.o pseudotypes.o rangetypes.o rangetypes_gist.o \
rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \
tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
- network.o mac.o inet_cidr_ntop.o inet_net_pton.o \
+ network.o network_gist.o mac.o inet_cidr_ntop.o inet_net_pton.o \
ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o trigfuncs.o \
tsginidx.o tsgistidx.o tsquery.o tsquery_cleanup.o tsquery_gist.o \
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index f2c337c..fd81815 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -23,41 +23,10 @@
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 inet *internal_inetpl(inet *ip, int64 addend);
-/*
- * Access macros. We use VARDATA_ANY so that we can process short-header
- * varlena values without detoasting them. This requires a trick:
- * VARDATA_ANY assumes the varlena header is already filled in, which is
- * not the case when constructing a new value (until SET_INET_VARSIZE is
- * called, which we typically can't do till the end). Therefore, we
- * always initialize the newly-allocated value to zeroes (using palloc0).
- * A zero length word will look like the not-1-byte case to VARDATA_ANY,
- * and so we correctly construct an uncompressed value.
- *
- * Note that ip_maxbits() and SET_INET_VARSIZE() require
- * the family field to be set correctly.
- */
-
-#define ip_family(inetptr) \
- (((inet_struct *) VARDATA_ANY(inetptr))->family)
-
-#define ip_bits(inetptr) \
- (((inet_struct *) VARDATA_ANY(inetptr))->bits)
-
-#define ip_addr(inetptr) \
- (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr)
-
-#define ip_maxbits(inetptr) \
- (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)
-
-#define SET_INET_VARSIZE(dst) \
- SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \
- ip_addrsize(dst))
-
/*
* Return the number of bytes of address storage needed for this data type.
@@ -596,6 +565,36 @@ network_supeq(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
}
+Datum
+network_overlap(PG_FUNCTION_ARGS)
+{
+ inet *a1 = PG_GETARG_INET_PP(0);
+ inet *a2 = PG_GETARG_INET_PP(1);
+
+ if (ip_family(a1) == ip_family(a2))
+ {
+ PG_RETURN_BOOL(bitncmp(ip_addr(a1), ip_addr(a2),
+ Min(ip_bits(a1), ip_bits(a2))) == 0);
+ }
+
+ PG_RETURN_BOOL(false);
+}
+
+Datum
+network_adjacent(PG_FUNCTION_ARGS)
+{
+ inet *a1 = PG_GETARG_INET_PP(0);
+ inet *a2 = PG_GETARG_INET_PP(1);
+
+ if (ip_family(a1) == ip_family(a2))
+ {
+ PG_RETURN_BOOL(bitncmp(ip_addr(a1), ip_addr(a2),
+ Min(ip_bits(a1), ip_bits(a2))) != 0);
+ }
+
+ PG_RETURN_BOOL(true);
+}
+
/*
* Extract data from a network datatype.
*/
@@ -962,7 +961,7 @@ convert_network_to_scalar(Datum value, Oid typid)
* author:
* Paul Vixie (ISC), June 1996
*/
-static int
+int
bitncmp(void *l, void *r, int n)
{
u_int lb,
@@ -991,6 +990,49 @@ bitncmp(void *l, void *r, int n)
return 0;
}
+/*
+ * Compare bit masks l and r for n bits
+ *
+ * Return the common bit count from the beginning. In contrast to
+ * it's purpose, it checks the bits from the end to the beggining
+ * to be more effective on modern computers based on the assumption
+ * that the inputs will usually be similar. Additional bits on the
+ * right would not effect the return value as expected. The return
+ * value is always less than the input n.
+ */
+int
+bitncommon(unsigned char *l, unsigned char *r, int n)
+{
+ int byte,
+ nbits;
+ unsigned char diff;
+
+ byte = n / 8;
+ nbits = n % 8;
+
+ /* Compare bytes from the most to the least */
+ while (byte != 0 && memcmp(l, r, byte) != 0)
+ {
+ byte--;
+
+ /* At least one more bit in the last byte is not common */
+ nbits = 7;
+ }
+
+ /* Set the bits to discard */
+ if (nbits != 0)
+ {
+ /* Set the diff for the first byte which is not common */
+ diff = l[byte] ^ r[byte];
+
+ /* Compare the bits from the most to the least */
+ while (diff >> (8 - nbits) != 0)
+ nbits--;
+ }
+
+ return (8 * byte) + nbits;
+}
+
static bool
addressOK(unsigned char *a, int bits, int family)
{
diff --git a/src/backend/utils/adt/network_gist.c b/src/backend/utils/adt/network_gist.c
new file mode 100644
index 0000000..3af56dc
--- /dev/null
+++ b/src/backend/utils/adt/network_gist.c
@@ -0,0 +1,563 @@
+/*-------------------------------------------------------------------------
+ *
+ * network_gist.c
+ * GiST support for network types.
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/utils/adt/network_gist.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/gist.h"
+#include "access/skey.h"
+#include "utils/inet.h"
+
+/*
+ * The GiST query consistency check
+ */
+Datum
+inet_gist_consistent(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
+ inet *orig = DatumGetInetP(ent->key),
+ *query = PG_GETARG_INET_PP(1);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+ /* Oid subtype = PG_GETARG_OID(3); */
+ bool *recheck = (bool *) PG_GETARG_POINTER(4);
+ int minbits,
+ order;
+
+ /* All operators served by this function are exact. */
+ *recheck = false;
+
+ /*
+ * Check 0: different families
+ *
+ * 0 is the special number for the family field. It means sub nodes
+ * include networks with different address families. The index should
+ * only have this node on the top. Proper inet type has no chance
+ * to have 0 on the family field.
+ */
+ if (ip_family(orig) == 0)
+ PG_RETURN_BOOL(true);
+
+ /*
+ * Check 1: different families
+ *
+ * Matching families do not help any of the strategies.
+ */
+ if (ip_family(orig) != ip_family(query))
+ {
+ switch (strategy)
+ {
+ case INETSTRAT_LT:
+ case INETSTRAT_LE:
+ if (ip_family(orig) < ip_family(query))
+ PG_RETURN_BOOL(true);
+ break;
+
+ case INETSTRAT_GE:
+ case INETSTRAT_GT:
+ if (ip_family(orig) > ip_family(query))
+ PG_RETURN_BOOL(true);
+ break;
+ }
+
+ PG_RETURN_BOOL(false);
+ }
+
+ /*
+ * Check 2: network bit count
+ *
+ * Network bit count (ip_bits) helps to check leaves for sub network
+ * and sup network operators.
+ */
+ switch (strategy)
+ {
+ case INETSTRAT_SUB:
+ if (GIST_LEAF(ent) && ip_bits(orig) <= ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+
+ case INETSTRAT_SUBEQ:
+ if (GIST_LEAF(ent) && ip_bits(orig) < ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+
+ case INETSTRAT_SUPEQ:
+ if (ip_bits(orig) > ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+
+ case INETSTRAT_SUP:
+ if (ip_bits(orig) >= ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+ }
+
+ /*
+ * Check 3: empty address
+ *
+ * If there are not any possible common bits, do not go futher
+ * return true as the leaves under this node can contain any address.
+ */
+ minbits = Min(ip_bits(orig), ip_bits(query));
+
+ if (minbits == 0)
+ {
+ switch (strategy)
+ {
+ case INETSTRAT_SUB:
+ case INETSTRAT_SUBEQ:
+ case INETSTRAT_OVERLAPS:
+ case INETSTRAT_SUPEQ:
+ case INETSTRAT_SUP:
+ PG_RETURN_BOOL(true);
+ }
+
+ if (!GIST_LEAF(ent))
+ PG_RETURN_BOOL(true);
+ }
+
+ /*
+ * Check 4: common network bits
+ *
+ * Common network bits is the final check for operators which
+ * only consider the network part of the address.
+ */
+ if (minbits > 0)
+ {
+ order = bitncmp(ip_addr(orig), ip_addr(query), minbits);
+
+ switch (strategy)
+ {
+ case INETSTRAT_SUB:
+ case INETSTRAT_SUBEQ:
+ case INETSTRAT_OVERLAPS:
+ case INETSTRAT_SUPEQ:
+ case INETSTRAT_SUP:
+ PG_RETURN_BOOL(order == 0);
+
+ case INETSTRAT_LT:
+ case INETSTRAT_LE:
+ if (order > 0)
+ PG_RETURN_BOOL(false);
+ if (order < 0 || !GIST_LEAF(ent))
+ PG_RETURN_BOOL(true);
+ break;
+
+ case INETSTRAT_EQ:
+ if (order != 0)
+ PG_RETURN_BOOL(false);
+ if (!GIST_LEAF(ent))
+ PG_RETURN_BOOL(true);
+ break;
+
+ case INETSTRAT_GE:
+ case INETSTRAT_GT:
+ if (order < 0)
+ PG_RETURN_BOOL(false);
+ if (order > 0 || !GIST_LEAF(ent))
+ PG_RETURN_BOOL(true);
+ break;
+ }
+ }
+
+ /* Remaining checks are only for leaves and basic comparison strategies. */
+ Assert(GIST_LEAF(ent));
+
+ /*
+ * Check 5: network bit count
+ *
+ * Bits are used on the basic comparison of the addresses. Whole
+ * addresses only compared if their network bits are the same.
+ * See backend/utils/adt/network.c:network_cmp_internal for
+ * the original comparison.
+ */
+ switch (strategy)
+ {
+ case INETSTRAT_LT:
+ case INETSTRAT_LE:
+ if (ip_bits(orig) < ip_bits(query))
+ PG_RETURN_BOOL(true);
+ if (ip_bits(orig) > ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+
+ case INETSTRAT_EQ:
+ if (ip_bits(orig) != ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+
+ case INETSTRAT_GE:
+ case INETSTRAT_GT:
+ if (ip_bits(orig) > ip_bits(query))
+ PG_RETURN_BOOL(true);
+ if (ip_bits(orig) < ip_bits(query))
+ PG_RETURN_BOOL(false);
+ break;
+ }
+
+ order = bitncmp(ip_addr(orig), ip_addr(query), ip_maxbits(orig));
+
+ /*
+ * Check 6: whole address
+ *
+ * Whole address check would not be required for most of the
+ * strategies.
+ */
+ switch (strategy)
+ {
+ case INETSTRAT_LT:
+ PG_RETURN_BOOL(order < 0);
+
+ case INETSTRAT_LE:
+ PG_RETURN_BOOL(order <= 0);
+
+ case INETSTRAT_EQ:
+ PG_RETURN_BOOL(order == 0);
+
+ case INETSTRAT_GE:
+ PG_RETURN_BOOL(order >= 0);
+
+ case INETSTRAT_GT:
+ PG_RETURN_BOOL(order > 0);
+ }
+
+ elog(ERROR, "unknown strategy for inet GiST");
+}
+
+/*
+ * The GiST union function
+ *
+ * The union of the networks is the network which contain all of them.
+ * The main question to calculate the union is that they have how many
+ * bits in common. After calculating the common bits, address of any of
+ * them can be used as the union by discarding the host bits.
+ */
+Datum
+inet_gist_union(PG_FUNCTION_ARGS)
+{
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ GISTENTRY *ent = entryvec->vector;
+ int family,
+ bits;
+ unsigned char *addr;
+ inet *tmp;
+ OffsetNumber i,
+ numranges = entryvec->n;
+
+ /* Initilize variables using the first key. */
+ tmp = DatumGetInetP(ent[0].key);
+ family = ip_family(tmp);
+ bits = ip_bits(tmp);
+ addr = ip_addr(tmp);
+
+ for (i = 1; i < numranges; i++)
+ {
+ tmp = DatumGetInetP(ent[i].key);
+
+ /*
+ * Return a network with the special number 0 on the family field
+ * for addresses from different familes.
+ */
+ if (ip_family(tmp) != family)
+ {
+ family = 0;
+ bits = 0;
+ break;
+ }
+
+ if (bits > ip_bits(tmp))
+ bits = ip_bits(tmp);
+
+ if (bits != 0)
+ bits = bitncommon(addr, ip_addr(tmp), bits);
+ }
+
+ /* Make sure any unused bits are zeroed. */
+ tmp = (inet *) palloc0(sizeof(inet));
+
+ /* Initilize the union as inet. */
+ ip_family(tmp) = family;
+ ip_bits(tmp) = bits;
+
+ /* Clone maximum bytes of the address. */
+ if (bits != 0)
+ memcpy(ip_addr(tmp), addr, (bits + 7) / 8);
+
+ /* Clean the partial byte. */
+ if (bits % 8 != 0)
+ ip_addr(tmp)[bits / 8] &= ~(0xFF >> (bits % 8));
+
+ SET_INET_VARSIZE(tmp);
+
+ PG_RETURN_INET_P(tmp);
+}
+
+/*
+ * The GiST compress function
+ */
+Datum
+inet_gist_compress(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+ PG_RETURN_POINTER(ent);
+}
+
+/*
+ * The GiST decompress function
+ */
+Datum
+inet_gist_decompress(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+ PG_RETURN_POINTER(ent);
+}
+
+/*
+ * The GiST page split penalty function
+ *
+ * Penalty is reverse of the common IP bits of the two addresses.
+ * Values bigger than 1 are used when the common IP bits cannot
+ * calculated.
+ */
+Datum
+inet_gist_penalty(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *origent = (GISTENTRY *) PG_GETARG_POINTER(0);
+ GISTENTRY *newent = (GISTENTRY *) PG_GETARG_POINTER(1);
+ float *penalty = (float *) PG_GETARG_POINTER(2);
+ inet *orig = DatumGetInetP(origent->key),
+ *new = DatumGetInetP(newent->key);
+ unsigned int minbits,
+ commonbits;
+
+ if (ip_family(orig) == ip_family(new))
+ {
+ minbits = Min(ip_bits(orig), ip_bits(new));
+
+ if (minbits > 0)
+ {
+ commonbits = bitncommon(ip_addr(orig), ip_addr(new), minbits);
+
+ if (commonbits > 0)
+ *penalty = ((float) 1) / commonbits;
+ else
+ *penalty = 2;
+ }
+ else
+ *penalty = 3;
+ }
+ else
+ *penalty = 4;
+
+ PG_RETURN_POINTER(penalty);
+}
+
+/*
+ * The GiST PickSplit method
+ *
+ * There are two ways to split. First one is to split by address families.
+ * In this case, addresses of one first appeared family will be put to the
+ * left bucket, addresses of the other family will be put to right bucket.
+ * Only the root should contain addresses from different families, so only
+ * the root should be split this way.
+ *
+ * The second and the important way is to split by the union of the keys.
+ * Union of the keys calculated same way with the inet_gist_union function.
+ * The first and the last biggest subnets created from the calculated
+ * union. In this case addresses contained by the first subnet will be put
+ * to the left bucket, address contained by the last subnet will be put to
+ * the right bucket.
+ */
+Datum
+inet_gist_picksplit(PG_FUNCTION_ARGS)
+{
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ GISTENTRY *ent = entryvec->vector;
+ GIST_SPLITVEC *splitvec = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+ int minfamily,
+ maxfamily,
+ minbits,
+ commonbits,
+ real_index;
+ unsigned char *addr;
+ inet *tmp,
+ *left_union,
+ *right_union;
+ OffsetNumber maxoff,
+ nbytes,
+ i,
+ *left,
+ *right;
+ GISTENTRY **raw_entryvec;
+
+ maxoff = entryvec->n - 1;
+ nbytes = (maxoff + 1) * sizeof(OffsetNumber);
+
+ left = (OffsetNumber *) palloc(nbytes);
+ right = (OffsetNumber *) palloc(nbytes);
+
+ splitvec->spl_left = left;
+ splitvec->spl_right = right;
+
+ splitvec->spl_nleft = 0;
+ splitvec->spl_nright = 0;
+
+ /* Initialize the raw entry vector. */
+ raw_entryvec = (GISTENTRY **) malloc(entryvec->n * sizeof(void *));
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ raw_entryvec[i] = &(entryvec->vector[i]);
+
+ /* Initilize variables using the first key. */
+ tmp = DatumGetInetP(ent[FirstOffsetNumber].key);
+ minfamily = ip_family(tmp);
+ maxfamily = minfamily;
+ commonbits = ip_bits(tmp);
+ minbits = commonbits;
+ addr = ip_addr(tmp);
+
+ /* Start comparing from the second one to find the common bit count. */
+ for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff;
+ i = OffsetNumberNext(i))
+ {
+ real_index = raw_entryvec[i] - entryvec->vector;
+
+ tmp = DatumGetInetP(entryvec->vector[real_index].key);
+ Assert(tmp != NULL);
+
+ /*
+ * If there are networks from different address families the split
+ * will be based on the family. So, first set the common bit count
+ * to 0. Then, update the minfamily and the maxfamily variables.
+ */
+ if (ip_family(tmp) != minfamily && ip_family(tmp) != maxfamily)
+ {
+ commonbits = 0;
+
+ if (ip_family(tmp) < minfamily)
+ minfamily = ip_family(tmp);
+
+ if (ip_family(tmp) > maxfamily)
+ maxfamily = ip_family(tmp);
+ }
+
+ if (minbits > ip_bits(tmp))
+ minbits = ip_bits(tmp);
+
+ if (commonbits > ip_bits(tmp))
+ commonbits = ip_bits(tmp);
+
+ if (commonbits != 0)
+ commonbits = bitncommon(addr, ip_addr(tmp), commonbits);
+ }
+
+ /* Make sure any unused bits are zeroed. */
+ left_union = (inet *) palloc0(sizeof(inet));
+ right_union = (inet *) palloc0(sizeof(inet));
+
+ ip_family(left_union) = minfamily;
+ ip_family(right_union) = maxfamily;
+
+ if (minfamily != maxfamily)
+ {
+ Assert(minfamily < maxfamily);
+
+ for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
+ {
+ real_index = raw_entryvec[i] - entryvec->vector;
+ tmp = DatumGetInetP(entryvec->vector[real_index].key);
+
+ if (ip_family(tmp) != maxfamily)
+ {
+ if (ip_family(tmp) != minfamily)
+ ip_family(left_union) = 0;
+
+ left[splitvec->spl_nleft++] = real_index;
+ }
+ else
+ right[splitvec->spl_nright++] = real_index;
+ }
+ }
+ else
+ {
+ Assert(minfamily > 0);
+
+ /*
+ * If all of the bits are common; there is no chance to split
+ * properly. It should mean that all of the elements have the same
+ * network address.
+ */
+ if (commonbits != minbits)
+ ++commonbits;
+ else
+ ereport(DEBUG1,
+ (errmsg("inet GiST cannot pict to split"),
+ errmsg_internal("all %d bits are the same for all items",
+ commonbits)));
+
+ ip_bits(left_union) = commonbits;
+ ip_bits(right_union) = commonbits;
+
+ /* Clone maximum bytes of the address to the left side. */
+ memcpy(ip_addr(left_union), addr, (commonbits + 6) / 8);
+ addr = ip_addr(left_union);
+
+ /* Clean the partial byte on the left side. */
+ if ((commonbits - 1) % 8 != 0)
+ addr[(commonbits - 1) / 8] &= ~(0xFF >> ((commonbits - 1) % 8));
+
+ /* Clone maximum bytes of the address to the right side. */
+ memcpy(ip_addr(right_union), addr, (commonbits + 6) / 8);
+ addr = ip_addr(right_union);
+
+ /* Set the last network bit of the address for the one on the right side. */
+ addr[(commonbits - 1) / 8] |= 1 << ((8 - (commonbits % 8)) % 8);
+
+ for (i = FirstOffsetNumber; i < entryvec->n; i = OffsetNumberNext(i))
+ {
+ real_index = raw_entryvec[i] - entryvec->vector;
+ tmp = DatumGetInetP(entryvec->vector[real_index].key);
+
+ if (bitncmp(addr, ip_addr(tmp), commonbits) != 0)
+ left[splitvec->spl_nleft++] = real_index;
+ else
+ right[splitvec->spl_nright++] = real_index;
+ }
+ }
+
+ SET_INET_VARSIZE(left_union);
+ SET_INET_VARSIZE(right_union);
+
+ splitvec->spl_ldatum = InetPGetDatum(left_union);
+ splitvec->spl_rdatum = InetPGetDatum(right_union);
+
+ PG_RETURN_POINTER(splitvec);
+}
+
+/*
+ * The GiST equality function
+ */
+Datum
+inet_gist_same(PG_FUNCTION_ARGS)
+{
+ inet *left = PG_GETARG_INET_P(0);
+ inet *right = PG_GETARG_INET_P(1);
+ bool *result = (bool *) PG_GETARG_POINTER(2);
+
+ *result = (ip_family(right) == ip_family(left) &&
+ ip_bits(right) == ip_bits(left) &&
+ bitncmp(ip_addr(left), ip_addr(right), ip_maxbits(left)) == 0);
+
+ PG_RETURN_POINTER(result);
+}
+
diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h
index c8a548c..6c65e14 100644
--- a/src/include/catalog/pg_amop.h
+++ b/src/include/catalog/pg_amop.h
@@ -791,4 +791,18 @@ DATA(insert ( 3474 3831 3831 8 s 3892 4000 0 ));
DATA(insert ( 3474 3831 2283 16 s 3889 4000 0 ));
DATA(insert ( 3474 3831 3831 18 s 3882 4000 0 ));
+/*
+ * GiST inet_ops
+ */
+DATA(insert ( 4049 869 869 3 s 4050 783 0 ));
+DATA(insert ( 4049 869 869 7 s 934 783 0 ));
+DATA(insert ( 4049 869 869 8 s 932 783 0 ));
+DATA(insert ( 4049 869 869 10 s 933 783 0 ));
+DATA(insert ( 4049 869 869 11 s 931 783 0 ));
+DATA(insert ( 4049 869 869 16 s 1203 783 0 ));
+DATA(insert ( 4049 869 869 17 s 1204 783 0 ));
+DATA(insert ( 4049 869 869 18 s 1201 783 0 ));
+DATA(insert ( 4049 869 869 19 s 1206 783 0 ));
+DATA(insert ( 4049 869 869 20 s 1205 783 0 ));
+
#endif /* PG_AMOP_H */
diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h
index 53a3a7a..1a7fc7a 100644
--- a/src/include/catalog/pg_amproc.h
+++ b/src/include/catalog/pg_amproc.h
@@ -356,6 +356,13 @@ DATA(insert ( 3919 3831 3831 4 3878 ));
DATA(insert ( 3919 3831 3831 5 3879 ));
DATA(insert ( 3919 3831 3831 6 3880 ));
DATA(insert ( 3919 3831 3831 7 3881 ));
+DATA(insert ( 4049 869 869 1 4042 ));
+DATA(insert ( 4049 869 869 2 4043 ));
+DATA(insert ( 4049 869 869 3 4044 ));
+DATA(insert ( 4049 869 869 4 4045 ));
+DATA(insert ( 4049 869 869 5 4046 ));
+DATA(insert ( 4049 869 869 6 4047 ));
+DATA(insert ( 4049 869 869 7 4048 ));
/* sp-gist */
diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h
index 0a3eb3e..dbef182 100644
--- a/src/include/catalog/pg_opclass.h
+++ b/src/include/catalog/pg_opclass.h
@@ -112,6 +112,7 @@ DATA(insert OID = 3123 ( 403 float8_ops PGNSP PGUID 1970 701 t 0 ));
DATA(insert ( 405 float8_ops PGNSP PGUID 1971 701 t 0 ));
DATA(insert ( 403 inet_ops PGNSP PGUID 1974 869 t 0 ));
DATA(insert ( 405 inet_ops PGNSP PGUID 1975 869 t 0 ));
+DATA(insert ( 783 inet_ops PGNSP PGUID 4049 869 t 869 ));
DATA(insert OID = 1979 ( 403 int2_ops PGNSP PGUID 1976 21 t 0 ));
#define INT2_BTREE_OPS_OID 1979
DATA(insert ( 405 int2_ops PGNSP PGUID 1977 21 t 0 ));
diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h
index 78efaa5..7d9bdb7 100644
--- a/src/include/catalog/pg_operator.h
+++ b/src/include/catalog/pg_operator.h
@@ -1150,6 +1150,12 @@ DESCR("is supernet");
DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq - - ));
DESCR("is supernet or equal");
#define OID_INET_SUPEQ_OP 934
+DATA(insert OID = 4050 ( "&&" PGNSP PGUID b f f 869 869 16 4050 4051 network_overlap - - ));
+DESCR("overlaps (is subnet or supernet)");
+#define OID_INET_OVERLAP_OP 4050
+DATA(insert OID = 4051 ( "-|-" PGNSP PGUID b f f 869 869 16 4051 4050 network_adjacent - - ));
+DESCR("is adjacent to");
+#define OID_INET_ADJACENT_OP 4051
DATA(insert OID = 2634 ( "~" PGNSP PGUID l f f 0 869 869 0 0 inetnot - - ));
DESCR("bitwise not");
diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opfamily.h
index 12ba456..e62b3f1 100644
--- a/src/include/catalog/pg_opfamily.h
+++ b/src/include/catalog/pg_opfamily.h
@@ -78,6 +78,7 @@ DATA(insert OID = 1971 ( 405 float_ops PGNSP PGUID ));
DATA(insert OID = 1974 ( 403 network_ops PGNSP PGUID ));
#define NETWORK_BTREE_FAM_OID 1974
DATA(insert OID = 1975 ( 405 network_ops PGNSP PGUID ));
+DATA(insert OID = 4049 ( 783 network_ops PGNSP PGUID ));
DATA(insert OID = 1976 ( 403 integer_ops PGNSP PGUID ));
#define INTEGER_BTREE_FAM_OID 1976
DATA(insert OID = 1977 ( 405 integer_ops PGNSP PGUID ));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 0117500..623d010 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2116,6 +2116,26 @@ DATA(insert OID = 927 ( network_sub PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 1
DATA(insert OID = 928 ( network_subeq PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_subeq _null_ _null_ _null_ ));
DATA(insert OID = 929 ( network_sup PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_sup _null_ _null_ _null_ ));
DATA(insert OID = 930 ( network_supeq PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_supeq _null_ _null_ _null_ ));
+DATA(insert OID = 4040 ( network_overlap PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_overlap _null_ _null_ _null_ ));
+DATA(insert OID = 4041 ( network_adjacent PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "869 869" _null_ _null_ _null_ _null_ network_adjacent _null_ _null_ _null_ ));
+
+/*
+ * GiST support for inet and cidr
+ */
+DATA(insert OID = 4042 ( inet_gist_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i 5 0 16 "2281 869 23 26 2281" _null_ _null_ _null_ _null_ inet_gist_consistent _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4043 ( inet_gist_union PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_union _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4044 ( inet_gist_compress PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_compress _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4045 ( inet_gist_decompress PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ inet_gist_decompress _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4046 ( inet_gist_penalty PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ inet_gist_penalty _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4047 ( inet_gist_picksplit PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ inet_gist_picksplit _null_ _null_ _null_ ));
+DESCR("GiST support");
+DATA(insert OID = 4048 ( inet_gist_same PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 2281 "869 869 2281" _null_ _null_ _null_ _null_ inet_gist_same _null_ _null_ _null_ ));
+DESCR("GiST support");
/* inet/cidr functions */
DATA(insert OID = 598 ( abbrev PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 25 "869" _null_ _null_ _null_ _null_ inet_abbrev _null_ _null_ _null_ ));
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 1bfd145..dd0d355 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -887,6 +887,8 @@ extern Datum network_sub(PG_FUNCTION_ARGS);
extern Datum network_subeq(PG_FUNCTION_ARGS);
extern Datum network_sup(PG_FUNCTION_ARGS);
extern Datum network_supeq(PG_FUNCTION_ARGS);
+extern Datum network_overlap(PG_FUNCTION_ARGS);
+extern Datum network_adjacent(PG_FUNCTION_ARGS);
extern Datum network_network(PG_FUNCTION_ARGS);
extern Datum network_netmask(PG_FUNCTION_ARGS);
extern Datum network_hostmask(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/inet.h b/src/include/utils/inet.h
index 3d8e31c..e7964bc 100644
--- a/src/include/utils/inet.h
+++ b/src/include/utils/inet.h
@@ -82,4 +82,67 @@ typedef struct macaddr
#define PG_GETARG_MACADDR_P(n) DatumGetMacaddrP(PG_GETARG_DATUM(n))
#define PG_RETURN_MACADDR_P(x) return MacaddrPGetDatum(x)
+/*
+ * Access macros
+ *
+ * We use VARDATA_ANY so that we can process short-header varlena values
+ * without detoasting them. This requires a trick: VARDATA_ANY assumes
+ * the varlena header is already filled in, which is not the case when
+ * constructing a new value (until SET_INET_VARSIZE is called, which we
+ * typically can't do till the end). Therefore, we always initialize
+ * the newly-allocated value to zeroes (using palloc0). A zero length
+ * word look like the not-1-byte case to VARDATA_ANY, and so we correctly
+ * construct an uncompressed value.
+ *
+ * Note that ip_maxbits() and SET_INET_VARSIZE() require the family
+ * field to be set correctly.
+ */
+
+#define ip_family(inetptr) \
+ (((inet_struct *) VARDATA_ANY(inetptr))->family)
+
+#define ip_bits(inetptr) \
+ (((inet_struct *) VARDATA_ANY(inetptr))->bits)
+
+#define ip_addr(inetptr) \
+ (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr)
+
+#define ip_maxbits(inetptr) \
+ (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)
+
+#define SET_INET_VARSIZE(inetptr) \
+ SET_VARSIZE(inetptr, VARHDRSZ + offsetof(inet_struct, ipaddr) + \
+ (ip_family(inetptr) == PGSQL_AF_INET ? 4 : 16))
+
+/*
+ * Operator strategy numbers used in the GiST network opclass
+ */
+#define INETSTRAT_SUB 11
+#define INETSTRAT_SUBEQ 8
+#define INETSTRAT_OVERLAPS 3
+#define INETSTRAT_SUPEQ 7
+#define INETSTRAT_SUP 10
+#define INETSTRAT_LT 16
+#define INETSTRAT_LE 17
+#define INETSTRAT_EQ 18
+#define INETSTRAT_GE 19
+#define INETSTRAT_GT 20
+
+/*
+ * Static functions in network.c
+ */
+extern int bitncmp(void *l, void *r, int n);
+extern int bitncommon(unsigned char *l, unsigned char *r, int n);
+
+/*
+ * GiST support functions in network_gist.c
+ */
+extern Datum inet_gist_consistent(PG_FUNCTION_ARGS);
+extern Datum inet_gist_compress(PG_FUNCTION_ARGS);
+extern Datum inet_gist_decompress(PG_FUNCTION_ARGS);
+extern Datum inet_gist_union(PG_FUNCTION_ARGS);
+extern Datum inet_gist_penalty(PG_FUNCTION_ARGS);
+extern Datum inet_gist_picksplit(PG_FUNCTION_ARGS);
+extern Datum inet_gist_same(PG_FUNCTION_ARGS);
+
#endif /* INET_H */
diff --git a/src/test/regress/expected/inet.out b/src/test/regress/expected/inet.out
index 356a397..d9fef4e 100644
--- a/src/test/regress/expected/inet.out
+++ b/src/test/regress/expected/inet.out
@@ -180,27 +180,28 @@ SELECT '' AS ten, i, c,
i < c AS lt, i <= c AS le, i = c AS eq,
i >= c AS ge, i > c AS gt, i <> c AS ne,
i << c AS sb, i <<= c AS sbe,
- i >> c AS sup, i >>= c AS spe
+ i >> c AS sup, i >>= c AS spe,
+ i && c AS ovr, i -|- c AS adj
FROM INET_TBL;
- ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe
------+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----
- | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t
- | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f
- | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t
- | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
- | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t
- | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f
- | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t
- | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t
- | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t
- | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t
- | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t
- | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t
- | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f
- | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f
- | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t
- | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f
- | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t
+ ten | i | c | lt | le | eq | ge | gt | ne | sb | sbe | sup | spe | ovr | adj
+-----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----+-----+-----
+ | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t | t | f
+ | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f | f | t
+ | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t | t | f
+ | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f | t | f
+ | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t | t | f
+ | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f | t | f
+ | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t | t | f
+ | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t | t | f
+ | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t | t | f
+ | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t | t | f
+ | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t | t | f
+ | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t | t | f
+ | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f | f | t
+ | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f | f | t
+ | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t | t | f
+ | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f | t | f
+ | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t | t | f
(17 rows)
-- check the conversion to/from text and set_netmask
@@ -226,7 +227,7 @@ SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
| ::4.3.2.1/24
(17 rows)
--- check that index works correctly
+-- check that btree index works correctly
CREATE INDEX inet_idx1 ON inet_tbl(i);
SET enable_seqscan TO off;
SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr;
@@ -250,6 +251,114 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
SET enable_seqscan TO on;
DROP INDEX inet_idx1;
+-- check that gist index works correctly
+CREATE INDEX inet_idx2 ON inet_tbl using gist (i);
+SET enable_seqscan TO off;
+SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+(3 rows)
+
+SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+(6 rows)
+
+SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+(6 rows)
+
+SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+----------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+(3 rows)
+
+SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+---+---
+(0 rows)
+
+SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+-------------+-------------
+ 10.0.0.0/8 | 9.1.2.3/8
+ 10.0.0.0/32 | 10.1.2.3/8
+ 10.0.0.0/8 | 10.1.2.3/8
+ 10.0.0.0/8 | 10.1.2.3/8
+ 10.1.0.0/16 | 10.1.2.3/16
+ 10.1.2.0/24 | 10.1.2.3/24
+ 10.1.2.3/32 | 10.1.2.3
+ 10.0.0.0/8 | 11.1.2.3/8
+(8 rows)
+
+SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+----------------+----------------
+ 10.0.0.0/8 | 9.1.2.3/8
+ 10.0.0.0/8 | 10.1.2.3/8
+ 10.0.0.0/32 | 10.1.2.3/8
+ 10.0.0.0/8 | 10.1.2.3/8
+ 10.1.0.0/16 | 10.1.2.3/16
+ 10.1.2.0/24 | 10.1.2.3/24
+ 10.1.2.3/32 | 10.1.2.3
+ 10.0.0.0/8 | 11.1.2.3/8
+ 192.168.1.0/24 | 192.168.1.0/24
+(9 rows)
+
+SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+----------------+----------------
+ 192.168.1.0/24 | 192.168.1.0/24
+(1 row)
+
+SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+--------------------+------------------
+ 192.168.1.0/24 | 192.168.1.0/24
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+ ::ffff:1.2.3.4/128 | ::4.3.2.1/24
+ 10:23::f1/128 | 10:23::f1/64
+ 10:23::8000/113 | 10:23::ffff
+(9 rows)
+
+SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i;
+ c | i
+--------------------+------------------
+ 192.168.1.0/24 | 192.168.1.226/24
+ 192.168.1.0/24 | 192.168.1.255/24
+ 192.168.1.0/24 | 192.168.1.0/25
+ 192.168.1.0/24 | 192.168.1.255/25
+ 192.168.1.0/26 | 192.168.1.226
+ ::ffff:1.2.3.4/128 | ::4.3.2.1/24
+ 10:23::f1/128 | 10:23::f1/64
+ 10:23::8000/113 | 10:23::ffff
+(8 rows)
+
+SET enable_seqscan TO on;
+DROP INDEX inet_idx2;
-- simple tests of inet boolean and arithmetic operators
SELECT i, ~i AS "~i" FROM inet_tbl;
i | ~i
diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql
index 328f149..b88f95b 100644
--- a/src/test/regress/sql/inet.sql
+++ b/src/test/regress/sql/inet.sql
@@ -52,12 +52,14 @@ SELECT '' AS ten, i, c,
i < c AS lt, i <= c AS le, i = c AS eq,
i >= c AS ge, i > c AS gt, i <> c AS ne,
i << c AS sb, i <<= c AS sbe,
- i >> c AS sup, i >>= c AS spe
+ i >> c AS sup, i >>= c AS spe,
+ i && c AS ovr, i -|- c AS adj
FROM INET_TBL;
-- check the conversion to/from text and set_netmask
SELECT '' AS ten, set_masklen(inet(text(i)), 24) FROM INET_TBL;
--- check that index works correctly
+
+-- check that btree index works correctly
CREATE INDEX inet_idx1 ON inet_tbl(i);
SET enable_seqscan TO off;
SELECT * FROM inet_tbl WHERE i<<'192.168.1.0/24'::cidr;
@@ -65,6 +67,22 @@ SELECT * FROM inet_tbl WHERE i<<='192.168.1.0/24'::cidr;
SET enable_seqscan TO on;
DROP INDEX inet_idx1;
+-- check that gist index works correctly
+CREATE INDEX inet_idx2 ON inet_tbl using gist (i);
+SET enable_seqscan TO off;
+SELECT * FROM inet_tbl WHERE i << '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i <<= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i && '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i >>= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i >> '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i < '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i <= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i = '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i >= '192.168.1.0/24'::cidr ORDER BY i;
+SELECT * FROM inet_tbl WHERE i > '192.168.1.0/24'::cidr ORDER BY i;
+SET enable_seqscan TO on;
+DROP INDEX inet_idx2;
+
-- simple tests of inet boolean and arithmetic operators
SELECT i, ~i AS "~i" FROM inet_tbl;
SELECT i, c, i & c AS "and" FROM inet_tbl;