Datum ipaddr_send(PG_FUNCTION_ARGS) { IP_P arg1 = PG_GETARG_IP_P(0); StringInfoData buf; IP ip; int af = ip_unpack(arg1, &ip); pq_begintypsend(&buf); pq_sendbyte(&buf, af); pq_sendbyte(&buf, ip_maxbits(af)); pq_sendbyte(&buf, 1); pq_sendbyte(&buf, ip_sizeof(af)); switch (af) { case PGSQL_AF_INET: pq_sendint(&buf, ip.ip4, sizeof(IP4)); break; case PGSQL_AF_INET6: pq_sendint64(&buf, ip.ip6.bits[0]); pq_sendint64(&buf, ip.ip6.bits[1]); break; } PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); }
/* * Calculate node number (within a 4-node, single-family inner index tuple) * * The value must have the same family as the node's prefix, and * commonbits is the mask length of the prefix. We use even or odd * nodes according to the next address bit after the commonbits, * and low or high nodes according to whether the value's mask length * is larger than commonbits. */ static int inet_spg_node_number(const inet *val, int commonbits) { int nodeN = 0; if (commonbits < ip_maxbits(val) && ip_addr(val)[commonbits / 8] & (1 << (7 - commonbits % 8))) nodeN |= 1; if (commonbits < ip_bits(val)) nodeN |= 2; return nodeN; }
Datum ipaddr_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); IP ip; int af, bits, flag, nbytes; /* we copy the external format used by inet/cidr, just because. */ af = pq_getmsgbyte(buf); if (af != PGSQL_AF_INET && af != PGSQL_AF_INET6) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid address family in external IP value"))); bits = pq_getmsgbyte(buf); if (bits != ip_maxbits(af)) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid bit length in external IP value"))); flag = pq_getmsgbyte(buf); /* ignored */ nbytes = pq_getmsgbyte(buf); if (nbytes*8 != bits) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid address length in external IP value"))); switch (af) { case PGSQL_AF_INET: ip.ip4 = (IP4) pq_getmsgint(buf, sizeof(IP4)); break; case PGSQL_AF_INET6: ip.ip6.bits[0] = pq_getmsgint64(buf); ip.ip6.bits[1] = pq_getmsgint64(buf); break; } PG_RETURN_IP_P(ip_pack(af, &ip)); }
/* * Calculate bitmap of node numbers that are consistent with the query * * This can be used either at a 4-way inner tuple, or at a leaf tuple. * In the latter case, we should return a boolean result (0 or 1) * not a bitmap. * * This definition is pretty odd, but the inner and leaf consistency checks * are mostly common and it seems best to keep them in one function. */ static int inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys, bool leaf) { int bitmap; int commonbits, i; /* Initialize result to allow visiting all children */ if (leaf) bitmap = 1; else bitmap = 1 | (1 << 1) | (1 << 2) | (1 << 3); commonbits = ip_bits(prefix); for (i = 0; i < nkeys; i++) { inet *argument = DatumGetInetPP(scankeys[i].sk_argument); StrategyNumber strategy = scankeys[i].sk_strategy; int order; /* * Check 0: different families * * Matching families do not help any of the strategies. */ if (ip_family(argument) != ip_family(prefix)) { switch (strategy) { case RTLessStrategyNumber: case RTLessEqualStrategyNumber: if (ip_family(argument) < ip_family(prefix)) bitmap = 0; break; case RTGreaterEqualStrategyNumber: case RTGreaterStrategyNumber: if (ip_family(argument) > ip_family(prefix)) bitmap = 0; break; case RTNotEqualStrategyNumber: break; default: /* For all other cases, we can be sure there is no match */ bitmap = 0; break; } if (!bitmap) break; /* Other checks make no sense with different families. */ continue; } /* * Check 1: network bit count * * Network bit count (ip_bits) helps to check leaves for sub network * and sup network operators. At non-leaf nodes, we know every child * value has greater ip_bits, so we can avoid descending in some cases * too. * * This check is less expensive than checking the address bits, so we * are doing this before, but it has to be done after for the basic * comparison strategies, because ip_bits only affect their results * when the common network bits are the same. */ switch (strategy) { case RTSubStrategyNumber: if (commonbits <= ip_bits(argument)) bitmap &= (1 << 2) | (1 << 3); break; case RTSubEqualStrategyNumber: if (commonbits < ip_bits(argument)) bitmap &= (1 << 2) | (1 << 3); break; case RTSuperStrategyNumber: if (commonbits == ip_bits(argument) - 1) bitmap &= 1 | (1 << 1); else if (commonbits >= ip_bits(argument)) bitmap = 0; break; case RTSuperEqualStrategyNumber: if (commonbits == ip_bits(argument)) bitmap &= 1 | (1 << 1); else if (commonbits > ip_bits(argument)) bitmap = 0; break; case RTEqualStrategyNumber: if (commonbits < ip_bits(argument)) bitmap &= (1 << 2) | (1 << 3); else if (commonbits == ip_bits(argument)) bitmap &= 1 | (1 << 1); else bitmap = 0; break; } if (!bitmap) break; /* * Check 2: common network bits * * Compare available common prefix bits to the query, but not beyond * either the query's netmask or the minimum netmask among the * represented values. If these bits don't match the query, we can * eliminate some cases. */ order = bitncmp(ip_addr(prefix), ip_addr(argument), Min(commonbits, ip_bits(argument))); if (order != 0) { switch (strategy) { case RTLessStrategyNumber: case RTLessEqualStrategyNumber: if (order > 0) bitmap = 0; break; case RTGreaterEqualStrategyNumber: case RTGreaterStrategyNumber: if (order < 0) bitmap = 0; break; case RTNotEqualStrategyNumber: break; default: /* For all other cases, we can be sure there is no match */ bitmap = 0; break; } if (!bitmap) break; /* * Remaining checks make no sense when common bits don't match. */ continue; } /* * Check 3: next network bit * * We can filter out branch 2 or 3 using the next network bit of the * argument, if it is available. * * This check matters for the performance of the search. The results * would be correct without it. */ if (bitmap & ((1 << 2) | (1 << 3)) && commonbits < ip_bits(argument)) { int nextbit; nextbit = ip_addr(argument)[commonbits / 8] & (1 << (7 - commonbits % 8)); switch (strategy) { case RTLessStrategyNumber: case RTLessEqualStrategyNumber: if (!nextbit) bitmap &= 1 | (1 << 1) | (1 << 2); break; case RTGreaterEqualStrategyNumber: case RTGreaterStrategyNumber: if (nextbit) bitmap &= 1 | (1 << 1) | (1 << 3); break; case RTNotEqualStrategyNumber: break; default: if (!nextbit) bitmap &= 1 | (1 << 1) | (1 << 2); else bitmap &= 1 | (1 << 1) | (1 << 3); break; } if (!bitmap) break; } /* * Remaining checks are only for the basic comparison strategies. This * test relies on the strategy number ordering defined in stratnum.h. */ if (strategy < RTEqualStrategyNumber || strategy > RTGreaterEqualStrategyNumber) continue; /* * Check 4: network bit count * * At this point, we know that the common network bits of the prefix * and the argument are the same, so we can go forward and check the * ip_bits. */ switch (strategy) { case RTLessStrategyNumber: case RTLessEqualStrategyNumber: if (commonbits == ip_bits(argument)) bitmap &= 1 | (1 << 1); else if (commonbits > ip_bits(argument)) bitmap = 0; break; case RTGreaterEqualStrategyNumber: case RTGreaterStrategyNumber: if (commonbits < ip_bits(argument)) bitmap &= (1 << 2) | (1 << 3); break; } if (!bitmap) break; /* Remaining checks don't make sense with different ip_bits. */ if (commonbits != ip_bits(argument)) continue; /* * Check 5: next host bit * * We can filter out branch 0 or 1 using the next host bit of the * argument, if it is available. * * This check matters for the performance of the search. The results * would be correct without it. There is no point in running it for * leafs as we have to check the whole address on the next step. */ if (!leaf && bitmap & (1 | (1 << 1)) && commonbits < ip_maxbits(argument)) { int nextbit; nextbit = ip_addr(argument)[commonbits / 8] & (1 << (7 - commonbits % 8)); switch (strategy) { case RTLessStrategyNumber: case RTLessEqualStrategyNumber: if (!nextbit) bitmap &= 1 | (1 << 2) | (1 << 3); break; case RTGreaterEqualStrategyNumber: case RTGreaterStrategyNumber: if (nextbit) bitmap &= (1 << 1) | (1 << 2) | (1 << 3); break; case RTNotEqualStrategyNumber: break; default: if (!nextbit) bitmap &= 1 | (1 << 2) | (1 << 3); else bitmap &= (1 << 1) | (1 << 2) | (1 << 3); break; } if (!bitmap) break; } /* * Check 6: whole address * * This is the last check for correctness of the basic comparison * strategies. It's only appropriate at leaf entries. */ if (leaf) { /* Redo ordering comparison using all address bits */ order = bitncmp(ip_addr(prefix), ip_addr(argument), ip_maxbits(prefix)); switch (strategy) { case RTLessStrategyNumber: if (order >= 0) bitmap = 0; break; case RTLessEqualStrategyNumber: if (order > 0) bitmap = 0; break; case RTEqualStrategyNumber: if (order != 0) bitmap = 0; break; case RTGreaterEqualStrategyNumber: if (order < 0) bitmap = 0; break; case RTGreaterStrategyNumber: if (order <= 0) bitmap = 0; break; case RTNotEqualStrategyNumber: if (order == 0) bitmap = 0; break; } if (!bitmap) break; } } return bitmap; }