1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00

Convert inet-related functions to new fmgr style. I have also taken it

on myself to do something about the non-self-consistency of the inet
comparison functions.  The results are probably still semantically wrong
(inet and cidr should have different comparison semantics, I think)
but at least the boolean operators now agree with each other and with
the sort order of indexes on inet/cidr.
This commit is contained in:
Tom Lane
2000-08-03 23:07:51 +00:00
parent 61aca818c4
commit ed9ca68758
6 changed files with 329 additions and 318 deletions

View File

@@ -1,20 +1,18 @@
/*
* PostgreSQL type definitions for MAC addresses.
*
* $Header: /cvsroot/pgsql/src/backend/utils/adt/mac.c,v 1.16 2000/07/06 05:48:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/mac.c,v 1.17 2000/08/03 23:07:46 tgl Exp $
*/
#include "postgres.h"
#include "utils/builtins.h"
#include "utils/inet.h"
/*
* macaddr is a pass-by-reference datatype.
* XXX this table of manufacturers is long out of date, and should never
* have been wired into the code in the first place.
*/
#define PG_GETARG_MACADDR_P(n) ((macaddr *) PG_GETARG_POINTER(n))
#define PG_RETURN_MACADDR_P(x) return PointerGetDatum(x)
typedef struct manufacturer
{
@@ -145,18 +143,18 @@ static manufacturer manufacturers[] = {
*/
#define hibits(addr) \
((unsigned long)((addr->a<<16)|(addr->b<<8)|(addr->c)))
((unsigned long)(((addr)->a<<16)|((addr)->b<<8)|((addr)->c)))
#define lobits(addr) \
((unsigned long)((addr->d<<16)|(addr->e<<8)|(addr->f)))
((unsigned long)(((addr)->d<<16)|((addr)->e<<8)|((addr)->f)))
/*
* MAC address reader. Accepts several common notations.
*/
macaddr *
macaddr_in(char *str)
Datum
macaddr_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
int a,
b,
c,
@@ -201,21 +199,18 @@ macaddr_in(char *str)
result->e = e;
result->f = f;
return (result);
PG_RETURN_MACADDR_P(result);
}
/*
* MAC address output function. Fixed format.
*/
char *
macaddr_out(macaddr *addr)
Datum
macaddr_out(PG_FUNCTION_ARGS)
{
macaddr *addr = PG_GETARG_MACADDR_P(0);
char *result;
if (addr == NULL)
return (NULL);
result = (char *) palloc(32);
if ((hibits(addr) > 0) || (lobits(addr) > 0))
@@ -225,73 +220,18 @@ macaddr_out(macaddr *addr)
}
else
{
result[0] = 0; /* special case for missing address */
result[0] = '\0'; /* special case for missing address */
}
return (result);
}
/*
* Boolean tests.
*/
bool
macaddr_lt(macaddr *a1, macaddr *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return ((hibits(a1) < hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) < lobits(a2)));
}
bool
macaddr_le(macaddr *a1, macaddr *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return ((hibits(a1) < hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) <= lobits(a2)));
}
bool
macaddr_eq(macaddr *a1, macaddr *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return ((hibits(a1) == hibits(a2)) && (lobits(a1) == lobits(a2)));
}
bool
macaddr_ge(macaddr *a1, macaddr *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return ((hibits(a1) > hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) >= lobits(a2)));
}
bool
macaddr_gt(macaddr *a1, macaddr *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return ((hibits(a1) > hibits(a2)) ||
((hibits(a1) == hibits(a2)) && lobits(a1) > lobits(a2)));
}
bool
macaddr_ne(macaddr *a1, macaddr *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return ((hibits(a1) != hibits(a2)) || (lobits(a1) != lobits(a2)));
PG_RETURN_CSTRING(result);
}
/*
* Comparison function for sorting:
*/
int4
macaddr_cmp(macaddr *a1, macaddr *a2)
static int32
macaddr_cmp_internal(macaddr *a1, macaddr *a2)
{
if (hibits(a1) < hibits(a2))
return -1;
@@ -305,6 +245,72 @@ macaddr_cmp(macaddr *a1, macaddr *a2)
return 0;
}
Datum
macaddr_cmp(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_INT32(macaddr_cmp_internal(a1, a2));
}
/*
* Boolean comparisons.
*/
Datum
macaddr_lt(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) < 0);
}
Datum
macaddr_le(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) <= 0);
}
Datum
macaddr_eq(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) == 0);
}
Datum
macaddr_ge(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) >= 0);
}
Datum
macaddr_gt(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) > 0);
}
Datum
macaddr_ne(PG_FUNCTION_ARGS)
{
macaddr *a1 = PG_GETARG_MACADDR_P(0);
macaddr *a2 = PG_GETARG_MACADDR_P(1);
PG_RETURN_BOOL(macaddr_cmp_internal(a1, a2) != 0);
}
/*
* The special manufacturer fetching function.
*/

View File

@@ -3,7 +3,7 @@
* is for IP V4 CIDR notation, but prepared for V6: just
* add the necessary bits where the comments indicate.
*
* $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.23 2000/07/06 05:48:11 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.24 2000/08/03 23:07:46 tgl Exp $
*
* Jon Postel RIP 16 Oct 1998
*/
@@ -17,16 +17,11 @@
#include <arpa/inet.h>
#include "utils/builtins.h"
/*
* inet is a pass-by-reference datatype. It's not toastable, and we
* don't try to hide the pass-by-refness, so these macros are simple.
*/
#define PG_GETARG_INET_P(n) ((inet *) PG_GETARG_POINTER(n))
#define PG_RETURN_INET_P(x) return PointerGetDatum(x)
#include "utils/inet.h"
static int v4bitncmp(unsigned int a1, unsigned int a2, int bits);
static int32 network_cmp_internal(inet *a1, inet *a2);
/*
* Access macros. Add IPV6 support.
@@ -54,12 +49,7 @@ network_in(char *src, int type)
int bits;
inet *dst;
if (!src)
return NULL;
dst = palloc(VARHDRSZ + sizeof(inet_struct));
if (dst == NULL)
elog(ERROR, "unable to allocate memory in network_in()");
dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
/* First, try for an IP V4 address: */
ip_family(dst) = AF_INET;
@@ -74,32 +64,37 @@ network_in(char *src, int type)
+ ip_addrsize(dst);
ip_bits(dst) = bits;
ip_type(dst) = type;
return dst;
}
/* INET address reader. */
inet *
inet_in(char *src)
Datum
inet_in(PG_FUNCTION_ARGS)
{
return network_in(src, 0);
char *src = PG_GETARG_CSTRING(0);
PG_RETURN_INET_P(network_in(src, 0));
}
/* CIDR address reader. */
inet *
cidr_in(char *src)
Datum
cidr_in(PG_FUNCTION_ARGS)
{
return network_in(src, 1);
char *src = PG_GETARG_CSTRING(0);
PG_RETURN_INET_P(network_in(src, 1));
}
/*
* INET address output function.
*/
char *
inet_out(inet *src)
Datum
inet_out(PG_FUNCTION_ARGS)
{
char *dst,
tmp[sizeof("255.255.255.255/32")];
inet *src = PG_GETARG_INET_P(0);
char tmp[sizeof("255.255.255.255/32")];
char *dst;
if (ip_family(src) == AF_INET)
{
@@ -118,211 +113,201 @@ inet_out(inet *src)
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "unknown address family (%d)", ip_family(src));
dst = palloc(strlen(tmp) + 1);
if (dst == NULL)
elog(ERROR, "unable to allocate memory in inet_out()");
strcpy(dst, tmp);
return dst;
PG_RETURN_CSTRING(pstrdup(tmp));
}
/* just a stub */
char *
cidr_out(inet *src)
/* share code with INET case */
Datum
cidr_out(PG_FUNCTION_ARGS)
{
return inet_out(src);
return inet_out(fcinfo);
}
/*
* Basic comparison function for sorting and inet/cidr comparisons.
*
* XXX this ignores bits to the right of the mask. That's probably
* correct for CIDR, almost certainly wrong for INET. We need to have
* two sets of comparator routines, not just one. Note that suggests
* that CIDR and INET should not be considered binary-equivalent by
* the parser?
*/
static int32
network_cmp_internal(inet *a1, inet *a2)
{
if (ip_family(a1) == AF_INET && ip_family(a2) == AF_INET)
{
int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2),
Min(ip_bits(a1), ip_bits(a2)));
if (order != 0)
return order;
return ((int32) ip_bits(a1)) - ((int32) ip_bits(a2));
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return 0; /* keep compiler quiet */
}
}
Datum
network_cmp(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_INT32(network_cmp_internal(a1, a2));
}
/*
* Boolean tests for magnitude. Add V4/V6 testing!
* Boolean ordering tests.
*/
bool
network_lt(inet *a1, inet *a2)
Datum
network_lt(PG_FUNCTION_ARGS)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_BOOL(network_cmp_internal(a1, a2) < 0);
}
Datum
network_le(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_BOOL(network_cmp_internal(a1, a2) <= 0);
}
Datum
network_eq(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_BOOL(network_cmp_internal(a1, a2) == 0);
}
Datum
network_ge(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_BOOL(network_cmp_internal(a1, a2) >= 0);
}
Datum
network_gt(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_BOOL(network_cmp_internal(a1, a2) > 0);
}
Datum
network_ne(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
PG_RETURN_BOOL(network_cmp_internal(a1, a2) != 0);
}
/*
* Boolean network-inclusion tests.
*/
Datum
network_sub(PG_FUNCTION_ARGS)
{
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
return ((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
&& v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
PG_RETURN_BOOL(false);
}
}
bool
network_le(inet *a1, inet *a2)
Datum
network_subeq(PG_FUNCTION_ARGS)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return (network_lt(a1, a2) || network_eq(a1, a2));
}
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
bool
network_eq(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
return ((ip_bits(a1) == ip_bits(a2))
&& (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
&& v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0);
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
PG_RETURN_BOOL(false);
}
}
bool
network_ge(inet *a1, inet *a2)
Datum
network_sup(PG_FUNCTION_ARGS)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return (network_gt(a1, a2) || network_eq(a1, a2));
}
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
bool
network_gt(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
return ((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
&& v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
PG_RETURN_BOOL(false);
}
}
bool
network_ne(inet *a1, inet *a2)
Datum
network_supeq(PG_FUNCTION_ARGS)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
return (!network_eq(a1, a2));
}
bool
network_sub(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
inet *a1 = PG_GETARG_INET_P(0);
inet *a2 = PG_GETARG_INET_P(1);
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
return ((ip_bits(a1) > ip_bits(a2))
&& (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
&& v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0);
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
}
}
bool
network_subeq(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
return ((ip_bits(a1) >= ip_bits(a2))
&& (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
}
}
bool
network_sup(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
return ((ip_bits(a1) < ip_bits(a2))
&& (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
}
}
bool
network_supeq(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
return ((ip_bits(a1) <= ip_bits(a2))
&& (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
return FALSE;
PG_RETURN_BOOL(false);
}
}
/*
* Comparison function for sorting. Add V4/V6 testing!
* Extract data from a network datatype.
*/
int4
network_cmp(inet *a1, inet *a2)
{
if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2)))
return (-1);
if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2)))
return (1);
if (ip_bits(a1) < ip_bits(a2))
return (-1);
if (ip_bits(a1) > ip_bits(a2))
return (1);
return 0;
}
Datum
network_host(PG_FUNCTION_ARGS)
{
@@ -357,13 +342,12 @@ network_host(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(ret);
}
int4
network_masklen(inet *ip)
Datum
network_masklen(PG_FUNCTION_ARGS)
{
if (!PointerIsValid(ip))
return 0;
inet *ip = PG_GETARG_INET_P(0);
return ip_bits(ip);
PG_RETURN_INT32(ip_bits(ip));
}
Datum