static inline IP_P ipaddr_transform_2(Datum d1, Datum d2, PGFunction ip4func, PGFunction ip6func) { IP_P ipp1 = DatumGetIP_P(d1); IP_P ipp2 = DatumGetIP_P(d2); IP ip1; IP ip2; IP out; int af1 = ip_unpack(ipp1, &ip1); int af2 = ip_unpack(ipp2, &ip2); if (af1 != af2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid mixing of IP address families"))); switch (af1) { case PGSQL_AF_INET: out.ip4 = DatumGetIP4(DirectFunctionCall2(ip4func, IP4GetDatum(ip1.ip4), IP4GetDatum(ip2.ip4))); break; case PGSQL_AF_INET6: out.ip6 = *(DatumGetIP6P(DirectFunctionCall2(ip6func, IP6PGetDatum(&ip1.ip6), IP6PGetDatum(&ip2.ip6)))); break; default: ipaddr_internal_error(); } return ip_pack(af1, &out); }
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)); }
static inline bool ipaddr_comparison_bool(Datum d1, Datum d2, bool mismatch_af1, bool mismatch_af2, PGFunction ip4func, PGFunction ip6func) { IP_P ipp1 = DatumGetIP_P(d1); IP_P ipp2 = DatumGetIP_P(d2); IP ip1; IP ip2; int af1 = ip_unpack(ipp1, &ip1); int af2 = ip_unpack(ipp2, &ip2); bool retval; if (af1 != af2) { retval = (af1 > af2) ? mismatch_af1 : mismatch_af2; } else { switch (af1) { case PGSQL_AF_INET: retval = DatumGetBool(DirectFunctionCall2(ip4func, IP4GetDatum(ip1.ip4), IP4GetDatum(ip2.ip4))); break; case PGSQL_AF_INET6: retval = DatumGetBool(DirectFunctionCall2(ip6func, IP6PGetDatum(&ip1.ip6), IP6PGetDatum(&ip2.ip6))); break; default: ipaddr_internal_error(); } } if ((Pointer)ipp1 != DatumGetPointer(d1)) pfree(ipp1); if ((Pointer)ipp2 != DatumGetPointer(d2)) pfree(ipp2); return retval; }
/* return 0 on success, -1 on failure. */ static int ipport_unpack(IP_Port *target, const uint8_t *data, unsigned int data_size, _Bool disable_family_check) { if (data_size < (SIZE_IP + SIZE_PORT)) return -1; if (ip_unpack(&target->ip, data, data_size, disable_family_check) == -1) return -1; memcpy(&target->port, data + SIZE_IP, SIZE_PORT); return 0; }
Datum ipaddr_family(PG_FUNCTION_ARGS) { IP_P ipp = PG_GETARG_IP_P(0); IP ip; if (ip_unpack(ipp, &ip) == PGSQL_AF_INET6) PG_RETURN_INT32(6); else PG_RETURN_INT32(4); }
Datum ipaddr_cmp(PG_FUNCTION_ARGS) { IP_P ipp1 = PG_GETARG_IP_P(0); IP_P ipp2 = PG_GETARG_IP_P(1); IP ip1; IP ip2; int af1 = ip_unpack(ipp1, &ip1); int af2 = ip_unpack(ipp2, &ip2); int32 retval; if (af1 != af2) { retval = (af1 > af2) ? 1 : -1; } else { switch (af1) { case PGSQL_AF_INET: retval = DatumGetInt32(DirectFunctionCall2(ip4_cmp, IP4GetDatum(ip1.ip4), IP4GetDatum(ip2.ip4))); break; case PGSQL_AF_INET6: retval = DatumGetInt32(DirectFunctionCall2(ip6_cmp, IP6PGetDatum(&ip1.ip6), IP6PGetDatum(&ip2.ip6))); break; default: ipaddr_internal_error(); } } PG_FREE_IF_COPY(ipp1,0); PG_FREE_IF_COPY(ipp2,1); PG_RETURN_INT32(retval); }
Datum ipaddr_minus_ipaddr(PG_FUNCTION_ARGS) { Datum minuend = PG_GETARG_DATUM(0); Datum subtrahend = PG_GETARG_DATUM(1); Datum res; IP ip1; IP ip2; int af1 = ip_unpack(DatumGetIP_P(minuend), &ip1); int af2 = ip_unpack(DatumGetIP_P(subtrahend), &ip2); if (af1 != af2) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid mixing of IP address families"))); switch (af1) { case PGSQL_AF_INET: res = DirectFunctionCall2(numeric_sub, DirectFunctionCall1(ip4_cast_to_numeric,IP4GetDatum(ip1.ip4)), DirectFunctionCall1(ip4_cast_to_numeric,IP4GetDatum(ip2.ip4))); break; case PGSQL_AF_INET6: res = DirectFunctionCall2(numeric_sub, DirectFunctionCall1(ip6_cast_to_numeric,IP6PGetDatum(&ip1.ip6)), DirectFunctionCall1(ip6_cast_to_numeric,IP6PGetDatum(&ip2.ip6))); break; default: ipaddr_internal_error(); } PG_RETURN_DATUM(res); }
Datum ipaddr_cast_to_ip4(PG_FUNCTION_ARGS) { IP_P ipp = PG_GETARG_IP_P(0); IP ip; if (ip_unpack(ipp, &ip) == PGSQL_AF_INET) { PG_RETURN_IP4(ip.ip4); } ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid IP value in cast to IP4"))); PG_RETURN_NULL(); }
Datum ipaddr_cast_to_ip6(PG_FUNCTION_ARGS) { IP_P ipp = PG_GETARG_IP_P(0); IP ip; if (ip_unpack(ipp, &ip) == PGSQL_AF_INET6) { IP6 *out = palloc(sizeof(IP6)); *out = ip.ip6; PG_RETURN_IP6_P(out); } ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid IP value in cast to IP4"))); PG_RETURN_NULL(); }
static inline Datum ipaddr_transform_1d(Datum d, PGFunction ip4func, PGFunction ip6func) { IP_P ipp = DatumGetIP_P(d); IP ip; int af = ip_unpack(ipp, &ip); switch (af) { case PGSQL_AF_INET: return DirectFunctionCall1(ip4func, IP4GetDatum(ip.ip4)); case PGSQL_AF_INET6: return DirectFunctionCall1(ip6func, IP6PGetDatum(&ip.ip6)); } ipaddr_internal_error(); }
Datum ipaddr_out(PG_FUNCTION_ARGS) { IP_P ipp = PG_GETARG_IP_P(0); char *out = palloc(IP6_STRING_MAX); IP ip; switch (ip_unpack(ipp, &ip)) { case PGSQL_AF_INET: ip4_raw_output(ip.ip4, out, IP6_STRING_MAX); break; case PGSQL_AF_INET6: ip6_raw_output(ip.ip6.bits, out, IP6_STRING_MAX); break; } PG_RETURN_CSTRING(out); }
Datum ipaddr_cast_to_text(PG_FUNCTION_ARGS) { IP_P ipp = PG_GETARG_IP_P(0); IP ip; int af = ip_unpack(ipp, &ip); text *out = NULL; switch (af) { case PGSQL_AF_INET: out = make_text(NULL, IP4_STRING_MAX); set_text_len(out, ip4_raw_output(ip.ip4, VARDATA(out), IP4_STRING_MAX)); break; case PGSQL_AF_INET6: out = make_text(NULL, IP6_STRING_MAX); set_text_len(out, ip6_raw_output(ip.ip6.bits, VARDATA(out), IP6_STRING_MAX)); break; } PG_RETURN_TEXT_P(out); }
static inline IP_P ipaddr_transform_2d(Datum d1, Datum d2, PGFunction ip4func, PGFunction ip6func) { IP_P ipp = DatumGetIP_P(d1); IP ip; int af = ip_unpack(ipp, &ip); switch (af) { case PGSQL_AF_INET: ip.ip4 = DatumGetIP4(DirectFunctionCall2(ip4func, IP4GetDatum(ip.ip4), d2)); break; case PGSQL_AF_INET6: ip.ip6 = *(DatumGetIP6P(DirectFunctionCall2(ip6func, IP6PGetDatum(&ip.ip6), d2))); break; default: ipaddr_internal_error(); } return ip_pack(af, &ip); }