diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 6e2fbda..4787519 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -8434,8 +8434,9 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple shows the operators available for the cidr and inet types. The operators <<, - <<=, >>, and - >>= test for subnet inclusion. They + <<=, >>, + >>= and && + test for subnet inclusion. They consider only the network parts of the two addresses (ignoring any host part) and determine whether one network is identical to or a subnet of the other. @@ -8503,6 +8504,11 @@ 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.80/28' + + ~ bitwise NOT ~ inet '192.168.1.6' @@ -8537,6 +8543,18 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple + GiST operator class is included for the cidr and + inet types, which support indexed queries using + <, <=, + =, >=, >, + <>, <<, + <<=, >>, + >>= and && + operators. The operator class considers only the network parts + of the addresses while creating and using the tree. + + + shows the functions available for use with the cidr and inet types. The abbrev, host, diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 6b23069..722830a 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -23,7 +23,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \ geo_ops.o geo_selfuncs.o inet_cidr_ntop.o inet_net_pton.o int.o \ int8.o json.o jsonb.o jsonb_gin.o jsonb_op.o jsonb_util.o \ jsonfuncs.o like.o lockfuncs.o mac.o misc.o nabstime.o name.o \ - network.o numeric.o numutils.o oid.o oracle_compat.o \ + network.o network_gist.o numeric.o numutils.o oid.o oracle_compat.o \ orderedsetaggs.o pg_lzcompress.o pg_locale.o pg_lsn.o \ pgstatfuncs.o pseudotypes.o quote.o rangetypes.o rangetypes_gist.o \ rangetypes_selfuncs.o rangetypes_spgist.o rangetypes_typanalyze.o \ diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 5e837fa..4f40fbf 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,21 @@ 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); +} + /* * Extract data from a network datatype. */ @@ -962,7 +946,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 +975,44 @@ 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. 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; + + nbits = n % 8; + + for (byte = 0; byte < n / 8; byte++) + if (l[byte] != r[byte]) + { + /* At least one more bit in the last byte is not common */ + nbits = 7; + break; + } + + /* 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..d41dd19 --- /dev/null +++ b/src/backend/utils/adt/network_gist.c @@ -0,0 +1,582 @@ +/*------------------------------------------------------------------------- + * + * network_gist.c + * GiST support for network types. + * + * Portions Copyright (c) 1996-2014, 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 + +#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; + + case INETSTRAT_NE: + PG_RETURN_BOOL(true); + } + + 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: + case INETSTRAT_EQ: + 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; + + case INETSTRAT_NE: + 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; + + case INETSTRAT_NE: + if (ip_bits(orig) != ip_bits(query)) + PG_RETURN_BOOL(true); + 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); + + case INETSTRAT_NE: + 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 important part of calculating the union is to find that how many + * bits they have in common on the network part of their addresses. + * After finding 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, + *result; + 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. */ + result = (inet *) palloc0(sizeof(inet)); + + /* Initilize the union as inet. */ + ip_family(result) = family; + ip_bits(result) = bits; + + /* Clone maximum bytes of the address. */ + if (bits != 0) + memcpy(ip_addr(result), addr, (bits + 7) / 8); + + /* Clean the partial byte. */ + if (bits % 8 != 0) + ip_addr(result)[bits / 8] &= ~(0xFF >> (bits % 8)); + + SET_INET_VARSIZE(result); + + PG_RETURN_INET_P(result); +} + +/* + * 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 inverse of the common IP bits of the two addresses. Values + * bigger than 1 are used when the common bits cannot be 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 regular way is to split by the network part of the + * keys. To achieve this, the union of the keys calculated with the method + * on the inet_gist_union function. The first and the last biggest subnets + * created from the calculated union. Keys contained by the first subnet put + * to the left bucket, keys contained by the last subnet 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) && + memcmp(ip_addr(left), ip_addr(right), ip_maxbytes(left)) == 0); + + PG_RETURN_POINTER(result); +} diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 2623113..b8e8750 100644 --- a/src/include/catalog/pg_amop.h +++ b/src/include/catalog/pg_amop.h @@ -818,4 +818,19 @@ 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 ( 4060 869 869 3 s 4052 783 0 )); +DATA(insert ( 4060 869 869 7 s 933 783 0 )); +DATA(insert ( 4060 869 869 8 s 931 783 0 )); +DATA(insert ( 4060 869 869 9 s 934 783 0 )); +DATA(insert ( 4060 869 869 10 s 932 783 0 )); +DATA(insert ( 4060 869 869 11 s 1203 783 0 )); +DATA(insert ( 4060 869 869 12 s 1204 783 0 )); +DATA(insert ( 4060 869 869 14 s 1206 783 0 )); +DATA(insert ( 4060 869 869 15 s 1205 783 0 )); +DATA(insert ( 4060 869 869 18 s 1201 783 0 )); +DATA(insert ( 4060 869 869 19 s 1202 783 0 )); + #endif /* PG_AMOP_H */ diff --git a/src/include/catalog/pg_amproc.h b/src/include/catalog/pg_amproc.h index b28dd56..a47ce9f 100644 --- a/src/include/catalog/pg_amproc.h +++ b/src/include/catalog/pg_amproc.h @@ -399,6 +399,13 @@ DATA(insert ( 4037 3802 3802 2 3485 )); DATA(insert ( 4037 3802 3802 3 3486 )); DATA(insert ( 4037 3802 3802 4 3487 )); DATA(insert ( 4037 3802 3802 6 3489 )); +DATA(insert ( 4060 869 869 1 4053 )); +DATA(insert ( 4060 869 869 2 4054 )); +DATA(insert ( 4060 869 869 3 4055 )); +DATA(insert ( 4060 869 869 4 4056 )); +DATA(insert ( 4060 869 869 5 4057 )); +DATA(insert ( 4060 869 869 6 4058 )); +DATA(insert ( 4060 869 869 7 4059 )); /* sp-gist */ DATA(insert ( 3474 3831 3831 1 3469 )); diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opclass.h index 63a40a8..22098de 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 4060 869 f 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 ac09034..ce179ae 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -1140,18 +1140,21 @@ DATA(insert OID = 1205 ( ">" PGNSP PGUID b f f 869 869 16 1203 1204 network DESCR("greater than"); DATA(insert OID = 1206 ( ">=" PGNSP PGUID b f f 869 869 16 1204 1203 network_ge scalargtsel scalargtjoinsel )); DESCR("greater than or equal"); -DATA(insert OID = 931 ( "<<" PGNSP PGUID b f f 869 869 16 933 0 network_sub - - )); +DATA(insert OID = 931 ( "<<" PGNSP PGUID b f f 869 869 16 933 0 network_sub contsel contjoinsel )); DESCR("is subnet"); #define OID_INET_SUB_OP 931 -DATA(insert OID = 932 ( "<<=" PGNSP PGUID b f f 869 869 16 934 0 network_subeq - - )); +DATA(insert OID = 932 ( "<<=" PGNSP PGUID b f f 869 869 16 934 0 network_subeq contsel contjoinsel )); DESCR("is subnet or equal"); #define OID_INET_SUBEQ_OP 932 -DATA(insert OID = 933 ( ">>" PGNSP PGUID b f f 869 869 16 931 0 network_sup - - )); +DATA(insert OID = 933 ( ">>" PGNSP PGUID b f f 869 869 16 931 0 network_sup contsel contjoinsel )); DESCR("is supernet"); #define OID_INET_SUP_OP 933 -DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq - - )); +DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f f 869 869 16 932 0 network_supeq contsel contjoinsel )); DESCR("is supernet or equal"); -#define OID_INET_SUPEQ_OP 934 +#define OID_INET_SUPEQ_OP 94 +DATA(insert OID = 4052 ( "&&" PGNSP PGUID b f f 869 869 16 4052 0 network_overlap areasel areajoinsel)); +DESCR("overlaps (is subnet or supernet)"); +#define OID_INET_OVERLAP_OP 4052 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 775be86..db0c6df 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 = 4060 ( 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 334e6b8..4d7d0ef 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2118,6 +2118,23 @@ 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 = 4051 ( 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_ )); + +/* GiST support for inet and cidr */ +DATA(insert OID = 4053 ( 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 = 4054 ( 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 = 4055 ( 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 = 4056 ( 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 = 4057 ( 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 = 4058 ( 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 = 4059 ( 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 031a43a..beec002 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -902,6 +902,7 @@ 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_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 330f32d..008197c 100644 --- a/src/include/utils/inet.h +++ b/src/include/utils/inet.h @@ -82,4 +82,71 @@ 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(), ip_maxbytes() 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 ip_maxbytes(inetptr) \ + (ip_family(inetptr) == PGSQL_AF_INET ? 4 : 16) + +#define SET_INET_VARSIZE(inetptr) \ + SET_VARSIZE(inetptr, VARHDRSZ + offsetof(inet_struct, ipaddr) + \ + ip_maxbytes(inetptr)) + +/* + * Operator strategy numbers used in the GiST network opclass + */ +#define INETSTRAT_SUB 8 +#define INETSTRAT_SUBEQ 10 +#define INETSTRAT_OVERLAPS 3 +#define INETSTRAT_SUPEQ 9 +#define INETSTRAT_SUP 7 +#define INETSTRAT_LT 11 +#define INETSTRAT_LE 12 +#define INETSTRAT_EQ 18 +#define INETSTRAT_GE 14 +#define INETSTRAT_GT 15 +#define INETSTRAT_NE 19 + +/* + * 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..d8a6232 100644 --- a/src/test/regress/expected/inet.out +++ b/src/test/regress/expected/inet.out @@ -179,28 +179,28 @@ SELECT '' AS six, c AS cidr, i AS inet FROM INET_TBL 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 sb, i <<= c AS sbe, i >> c AS sup, + i >>= c AS spe, i && c AS ovr 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 +-----+------------------+--------------------+----+----+----+----+----+----+----+-----+-----+-----+----- + | 192.168.1.226/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t | t + | 192.168.1.226 | 192.168.1.0/26 | f | f | f | t | t | t | f | f | f | f | f + | 192.168.1.0/24 | 192.168.1.0/24 | f | t | t | t | f | f | f | t | f | t | t + | 192.168.1.0/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f | t + | 192.168.1.255/24 | 192.168.1.0/24 | f | f | f | t | t | t | f | t | f | t | t + | 192.168.1.255/25 | 192.168.1.0/24 | f | f | f | t | t | t | t | t | f | f | t + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t | t + | 10.1.2.3/8 | 10.0.0.0/32 | t | t | f | f | f | t | f | f | t | t | t + | 10.1.2.3 | 10.1.2.3/32 | f | t | t | t | f | f | f | t | f | t | t + | 10.1.2.3/24 | 10.1.2.0/24 | f | f | f | t | t | t | f | t | f | t | t + | 10.1.2.3/16 | 10.1.0.0/16 | f | f | f | t | t | t | f | t | f | t | t + | 10.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | t | f | t | t + | 11.1.2.3/8 | 10.0.0.0/8 | f | f | f | t | t | t | f | f | f | f | f + | 9.1.2.3/8 | 10.0.0.0/8 | t | t | f | f | f | t | f | f | f | f | f + | 10:23::f1/64 | 10:23::f1/128 | t | t | f | f | f | t | f | f | t | t | t + | 10:23::ffff | 10:23::8000/113 | f | f | f | t | t | t | t | t | f | f | t + | ::4.3.2.1/24 | ::ffff:1.2.3.4/128 | t | t | f | f | f | t | f | f | t | t | t (17 rows) -- check the conversion to/from text and set_netmask @@ -226,7 +226,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 +250,135 @@ 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 inet_ops); +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) + +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.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 +(16 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/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index bf76501..2428a2c 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -1105,19 +1105,28 @@ ORDER BY 1, 2, 3; 783 | 5 | >> 783 | 6 | -|- 783 | 6 | ~= + 783 | 7 | >> 783 | 7 | @> + 783 | 8 | << 783 | 8 | <@ 783 | 9 | &<| + 783 | 9 | >>= + 783 | 10 | <<= 783 | 10 | <<| 783 | 10 | <^ + 783 | 11 | < 783 | 11 | >^ 783 | 11 | |>> + 783 | 12 | <= 783 | 12 | |&> 783 | 13 | ~ + 783 | 14 | >= 783 | 14 | @ 783 | 15 | <-> + 783 | 15 | > 783 | 16 | @> 783 | 18 | = + 783 | 19 | <> 783 | 28 | <@ 783 | 48 | <@ 783 | 68 | <@ @@ -1153,7 +1162,7 @@ ORDER BY 1, 2, 3; 4000 | 15 | > 4000 | 16 | @> 4000 | 18 | = -(71 rows) +(80 rows) -- Check that all opclass search operators have selectivity estimators. -- This is not absolutely required, but it seems a reasonable thing diff --git a/src/test/regress/sql/inet.sql b/src/test/regress/sql/inet.sql index 328f149..850a319 100644 --- a/src/test/regress/sql/inet.sql +++ b/src/test/regress/sql/inet.sql @@ -51,13 +51,14 @@ SELECT '' AS six, c AS cidr, i AS inet FROM INET_TBL 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 sb, i <<= c AS sbe, i >> c AS sup, + i >>= c AS spe, i && c AS ovr 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 +66,23 @@ 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 inet_ops); +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; +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;