Clean up the INET-vs-CIDR situation. Get rid of the internal is_cidr flag

and rely exclusively on the SQL type system to tell the difference between
the types.  Prevent creation of invalid CIDR values via casting from INET
or set_masklen() --- both of these operations now silently zero any bits
to the right of the netmask.  Remove duplicate CIDR comparison operators,
letting the type rely on the INET operators instead.
REL8_2_STABLE
Tom Lane 20 years ago
parent 5997386a0a
commit 8d8bf12760
  1. 36
      doc/src/sgml/func.sgml
  2. 22
      src/backend/optimizer/path/indxpath.c
  3. 275
      src/backend/utils/adt/network.c
  4. 4
      src/include/catalog/catversion.h
  5. 14
      src/include/catalog/pg_amop.h
  6. 4
      src/include/catalog/pg_cast.h
  7. 20
      src/include/catalog/pg_operator.h
  8. 18
      src/include/catalog/pg_proc.h
  9. 7
      src/include/utils/builtins.h
  10. 3
      src/include/utils/inet.h
  11. 5
      src/test/regress/expected/opr_sanity.out
  12. 3
      src/test/regress/sql/opr_sanity.sql

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.302 2006/01/11 20:12:38 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.303 2006/01/26 02:35:48 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -6797,9 +6797,7 @@ SELECT pg_sleep(1.5);
types. The <function>host</function>, types. The <function>host</function>,
<function>text</function>, and <function>abbrev</function> <function>text</function>, and <function>abbrev</function>
functions are primarily intended to offer alternative display functions are primarily intended to offer alternative display
formats. You can cast a text value to <type>inet</> using normal casting formats.
syntax: <literal>inet(<replaceable>expression</>)</literal> or
<literal><replaceable>colname</>::inet</literal>.
</para> </para>
<table id="cidr-inet-functions-table"> <table id="cidr-inet-functions-table">
@ -6843,6 +6841,13 @@ SELECT pg_sleep(1.5);
<entry><literal>set_masklen('192.168.1.5/24', 16)</literal></entry> <entry><literal>set_masklen('192.168.1.5/24', 16)</literal></entry>
<entry><literal>192.168.1.5/16</literal></entry> <entry><literal>192.168.1.5/16</literal></entry>
</row> </row>
<row>
<entry><literal><function>set_masklen</function>(<type>cidr</type>, <type>int</type>)</literal></entry>
<entry><type>cidr</type></entry>
<entry>set netmask length for <type>cidr</type> value</entry>
<entry><literal>set_masklen('192.168.1.0/24'::cidr, 16)</literal></entry>
<entry><literal>192.168.0.0/16</literal></entry>
</row>
<row> <row>
<entry><literal><function>netmask</function>(<type>inet</type>)</literal></entry> <entry><literal><function>netmask</function>(<type>inet</type>)</literal></entry>
<entry><type>inet</type></entry> <entry><type>inet</type></entry>
@ -6875,6 +6880,13 @@ SELECT pg_sleep(1.5);
<entry><literal><function>abbrev</function>(<type>inet</type>)</literal></entry> <entry><literal><function>abbrev</function>(<type>inet</type>)</literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>abbreviated display format as text</entry> <entry>abbreviated display format as text</entry>
<entry><literal>abbrev(inet '10.1.0.0/16')</literal></entry>
<entry><literal>10.1.0.0/16</literal></entry>
</row>
<row>
<entry><literal><function>abbrev</function>(<type>cidr</type>)</literal></entry>
<entry><type>text</type></entry>
<entry>abbreviated display format as text</entry>
<entry><literal>abbrev(cidr '10.1.0.0/16')</literal></entry> <entry><literal>abbrev(cidr '10.1.0.0/16')</literal></entry>
<entry><literal>10.1/16</literal></entry> <entry><literal>10.1/16</literal></entry>
</row> </row>
@ -6890,6 +6902,22 @@ SELECT pg_sleep(1.5);
</tgroup> </tgroup>
</table> </table>
<para>
Any <type>cidr</> value can be cast to <type>inet</> implicitly
or explicitly; therefore, the functions shown above as operating on
<type>inet</> also work on <type>cidr</> values. (Where there are
separate functions for <type>inet</> and <type>cidr</>, it is because
the behavior should be different for the two cases.)
Also, it is permitted to cast an <type>inet</> value to <type>cidr</>.
When this is done, any bits to the right of the netmask are silently zeroed
to create a valid <type>cidr</> value.
In addition,
you can cast a text value to <type>inet</> or <type>cidr</>
using normal casting syntax: for example,
<literal>inet(<replaceable>expression</>)</literal> or
<literal><replaceable>colname</>::cidr</literal>.
</para>
<para> <para>
<xref linkend="macaddr-functions-table"> shows the functions <xref linkend="macaddr-functions-table"> shows the functions
available for use with the <type>macaddr</type> type. The function available for use with the <type>macaddr</type> type. The function

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.197 2006/01/25 20:29:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.198 2006/01/26 02:35:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -2024,8 +2024,6 @@ match_special_index_operator(Expr *clause, Oid opclass,
case OID_INET_SUB_OP: case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP: case OID_INET_SUBEQ_OP:
case OID_CIDR_SUB_OP:
case OID_CIDR_SUBEQ_OP:
isIndexable = true; isIndexable = true;
break; break;
} }
@ -2087,12 +2085,8 @@ match_special_index_operator(Expr *clause, Oid opclass,
case OID_INET_SUB_OP: case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP: case OID_INET_SUBEQ_OP:
isIndexable = (opclass == INET_BTREE_OPS_OID); isIndexable = (opclass == INET_BTREE_OPS_OID ||
break; opclass == CIDR_BTREE_OPS_OID);
case OID_CIDR_SUB_OP:
case OID_CIDR_SUBEQ_OP:
isIndexable = (opclass == CIDR_BTREE_OPS_OID);
break; break;
} }
@ -2317,8 +2311,6 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opclass)
case OID_INET_SUB_OP: case OID_INET_SUB_OP:
case OID_INET_SUBEQ_OP: case OID_INET_SUBEQ_OP:
case OID_CIDR_SUB_OP:
case OID_CIDR_SUBEQ_OP:
result = network_prefix_quals(leftop, expr_op, opclass, result = network_prefix_quals(leftop, expr_op, opclass,
patt->constvalue); patt->constvalue);
break; break;
@ -2681,14 +2673,6 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
datatype = INETOID; datatype = INETOID;
is_eq = true; is_eq = true;
break; break;
case OID_CIDR_SUB_OP:
datatype = CIDROID;
is_eq = false;
break;
case OID_CIDR_SUBEQ_OP:
datatype = CIDROID;
is_eq = true;
break;
default: default:
elog(ERROR, "unexpected operator: %u", expr_op); elog(ERROR, "unexpected operator: %u", expr_op);
return NIL; return NIL;

@ -1,7 +1,7 @@
/* /*
* PostgreSQL type definitions for the INET and CIDR types. * PostgreSQL type definitions for the INET and CIDR types.
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.60 2006/01/23 21:49:39 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.61 2006/01/26 02:35:49 tgl Exp $
* *
* Jon Postel RIP 16 Oct 1998 * Jon Postel RIP 16 Oct 1998
*/ */
@ -22,7 +22,7 @@
#include "utils/inet.h" #include "utils/inet.h"
static Datum text_network(text *src, bool is_cidr); static inet *text_network(text *src, bool is_cidr);
static int32 network_cmp_internal(inet *a1, inet *a2); static int32 network_cmp_internal(inet *a1, inet *a2);
static int bitncmp(void *l, void *r, int n); static int bitncmp(void *l, void *r, int n);
static bool addressOK(unsigned char *a, int bits, int family); static bool addressOK(unsigned char *a, int bits, int family);
@ -38,9 +38,6 @@ static int ip_addrsize(inet *inetptr);
#define ip_bits(inetptr) \ #define ip_bits(inetptr) \
(((inet_struct *)VARDATA(inetptr))->bits) (((inet_struct *)VARDATA(inetptr))->bits)
#define ip_is_cidr(inetptr) \
(((inet_struct *)VARDATA(inetptr))->is_cidr)
#define ip_addr(inetptr) \ #define ip_addr(inetptr) \
(((inet_struct *)VARDATA(inetptr))->ipaddr) (((inet_struct *)VARDATA(inetptr))->ipaddr)
@ -64,7 +61,9 @@ ip_addrsize(inet *inetptr)
} }
} }
/* Common input routine */ /*
* Common INET/CIDR input routine
*/
static inet * static inet *
network_in(char *src, bool is_cidr) network_in(char *src, bool is_cidr)
{ {
@ -109,37 +108,33 @@ network_in(char *src, bool is_cidr)
+ ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ((char *) ip_addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst); + ip_addrsize(dst);
ip_bits(dst) = bits; ip_bits(dst) = bits;
ip_is_cidr(dst) = is_cidr;
return dst; return dst;
} }
/* INET address reader. */
Datum Datum
inet_in(PG_FUNCTION_ARGS) inet_in(PG_FUNCTION_ARGS)
{ {
char *src = PG_GETARG_CSTRING(0); char *src = PG_GETARG_CSTRING(0);
PG_RETURN_INET_P(network_in(src, 0)); PG_RETURN_INET_P(network_in(src, false));
} }
/* CIDR address reader. */
Datum Datum
cidr_in(PG_FUNCTION_ARGS) cidr_in(PG_FUNCTION_ARGS)
{ {
char *src = PG_GETARG_CSTRING(0); char *src = PG_GETARG_CSTRING(0);
PG_RETURN_INET_P(network_in(src, 1)); PG_RETURN_INET_P(network_in(src, true));
} }
/* /*
* INET address output function. * Common INET/CIDR output routine
*/ */
Datum static char *
inet_out(PG_FUNCTION_ARGS) network_out(inet *src, bool is_cidr)
{ {
inet *src = PG_GETARG_INET_P(0);
char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
char *dst; char *dst;
int len; int len;
@ -152,34 +147,45 @@ inet_out(PG_FUNCTION_ARGS)
errmsg("could not format inet value: %m"))); errmsg("could not format inet value: %m")));
/* For CIDR, add /n if not present */ /* For CIDR, add /n if not present */
if (ip_is_cidr(src) && strchr(tmp, '/') == NULL) if (is_cidr && strchr(tmp, '/') == NULL)
{ {
len = strlen(tmp); len = strlen(tmp);
snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src)); snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src));
} }
PG_RETURN_CSTRING(pstrdup(tmp)); return pstrdup(tmp);
} }
Datum
inet_out(PG_FUNCTION_ARGS)
{
inet *src = PG_GETARG_INET_P(0);
PG_RETURN_CSTRING(network_out(src, false));
}
/* share code with INET case */
Datum Datum
cidr_out(PG_FUNCTION_ARGS) cidr_out(PG_FUNCTION_ARGS)
{ {
return inet_out(fcinfo); inet *src = PG_GETARG_INET_P(0);
PG_RETURN_CSTRING(network_out(src, true));
} }
/* /*
* inet_recv - converts external binary format to inet * network_recv - converts external binary format to inet
* *
* The external representation is (one byte apiece for) * The external representation is (one byte apiece for)
* family, bits, is_cidr, address length, address in network byte order. * family, bits, is_cidr, address length, address in network byte order.
*
* Presence of is_cidr is largely for historical reasons, though it might
* allow some code-sharing on the client side. We send it correctly on
* output, but ignore the value on input.
*/ */
Datum static inet *
inet_recv(PG_FUNCTION_ARGS) network_recv(StringInfo buf, bool is_cidr)
{ {
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
inet *addr; inet *addr;
char *addrptr; char *addrptr;
int bits; int bits;
@ -194,23 +200,25 @@ inet_recv(PG_FUNCTION_ARGS)
ip_family(addr) != PGSQL_AF_INET6) ip_family(addr) != PGSQL_AF_INET6)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid address family in external \"inet\" value"))); /* translator: %s is inet or cidr */
errmsg("invalid address family in external \"%s\" value",
is_cidr ? "cidr" : "inet")));
bits = pq_getmsgbyte(buf); bits = pq_getmsgbyte(buf);
if (bits < 0 || bits > ip_maxbits(addr)) if (bits < 0 || bits > ip_maxbits(addr))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid bits in external \"inet\" value"))); /* translator: %s is inet or cidr */
errmsg("invalid bits in external \"%s\" value",
is_cidr ? "cidr" : "inet")));
ip_bits(addr) = bits; ip_bits(addr) = bits;
ip_is_cidr(addr) = pq_getmsgbyte(buf); i = pq_getmsgbyte(buf); /* ignore is_cidr */
if (ip_is_cidr(addr) != false && ip_is_cidr(addr) != true)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid type in external \"inet\" value")));
nb = pq_getmsgbyte(buf); nb = pq_getmsgbyte(buf);
if (nb != ip_addrsize(addr)) if (nb != ip_addrsize(addr))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid length in external \"inet\" value"))); /* translator: %s is inet or cidr */
errmsg("invalid length in external \"%s\" value",
is_cidr ? "cidr" : "inet")));
VARATT_SIZEP(addr) = VARHDRSZ VARATT_SIZEP(addr) = VARHDRSZ
+ ((char *) ip_addr(addr) - (char *) VARDATA(addr)) + ((char *) ip_addr(addr) - (char *) VARDATA(addr))
+ ip_addrsize(addr); + ip_addrsize(addr);
@ -222,7 +230,7 @@ inet_recv(PG_FUNCTION_ARGS)
/* /*
* Error check: CIDR values must not have any bits set beyond the masklen. * Error check: CIDR values must not have any bits set beyond the masklen.
*/ */
if (ip_is_cidr(addr)) if (is_cidr)
{ {
if (!addressOK(ip_addr(addr), bits, ip_family(addr))) if (!addressOK(ip_addr(addr), bits, ip_family(addr)))
ereport(ERROR, ereport(ERROR,
@ -231,23 +239,32 @@ inet_recv(PG_FUNCTION_ARGS)
errdetail("Value has bits set to right of mask."))); errdetail("Value has bits set to right of mask.")));
} }
PG_RETURN_INET_P(addr); return addr;
}
Datum
inet_recv(PG_FUNCTION_ARGS)
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
PG_RETURN_INET_P(network_recv(buf, false));
} }
/* share code with INET case */
Datum Datum
cidr_recv(PG_FUNCTION_ARGS) cidr_recv(PG_FUNCTION_ARGS)
{ {
return inet_recv(fcinfo); StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
PG_RETURN_INET_P(network_recv(buf, true));
} }
/* /*
* inet_send - converts inet to binary format * network_send - converts inet to binary format
*/ */
Datum static bytea *
inet_send(PG_FUNCTION_ARGS) network_send(inet *addr, bool is_cidr)
{ {
inet *addr = PG_GETARG_INET_P(0);
StringInfoData buf; StringInfoData buf;
char *addrptr; char *addrptr;
int nb, int nb,
@ -256,7 +273,7 @@ inet_send(PG_FUNCTION_ARGS)
pq_begintypsend(&buf); pq_begintypsend(&buf);
pq_sendbyte(&buf, ip_family(addr)); pq_sendbyte(&buf, ip_family(addr));
pq_sendbyte(&buf, ip_bits(addr)); pq_sendbyte(&buf, ip_bits(addr));
pq_sendbyte(&buf, ip_is_cidr(addr)); pq_sendbyte(&buf, is_cidr);
nb = ip_addrsize(addr); nb = ip_addrsize(addr);
if (nb < 0) if (nb < 0)
nb = 0; nb = 0;
@ -264,41 +281,93 @@ inet_send(PG_FUNCTION_ARGS)
addrptr = (char *) ip_addr(addr); addrptr = (char *) ip_addr(addr);
for (i = 0; i < nb; i++) for (i = 0; i < nb; i++)
pq_sendbyte(&buf, addrptr[i]); pq_sendbyte(&buf, addrptr[i]);
PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); return pq_endtypsend(&buf);
}
Datum
inet_send(PG_FUNCTION_ARGS)
{
inet *addr = PG_GETARG_INET_P(0);
PG_RETURN_BYTEA_P(network_send(addr, false));
} }
/* share code with INET case */
Datum Datum
cidr_send(PG_FUNCTION_ARGS) cidr_send(PG_FUNCTION_ARGS)
{ {
return inet_send(fcinfo); inet *addr = PG_GETARG_INET_P(0);
PG_RETURN_BYTEA_P(network_send(addr, true));
} }
static Datum static inet *
text_network(text *src, bool is_cidr) text_network(text *src, bool is_cidr)
{ {
int len = VARSIZE(src) - VARHDRSZ; int len = VARSIZE(src) - VARHDRSZ;
char *str = palloc(len + 1); char *str = palloc(len + 1);
memcpy(str, VARDATA(src), len); memcpy(str, VARDATA(src), len);
*(str + len) = '\0'; str[len] = '\0';
PG_RETURN_INET_P(network_in(str, is_cidr)); return network_in(str, is_cidr);
} }
Datum
text_inet(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_P(0);
PG_RETURN_INET_P(text_network(src, false));
}
Datum Datum
text_cidr(PG_FUNCTION_ARGS) text_cidr(PG_FUNCTION_ARGS)
{ {
return text_network(PG_GETARG_TEXT_P(0), 1); text *src = PG_GETARG_TEXT_P(0);
PG_RETURN_INET_P(text_network(src, true));
} }
Datum Datum
text_inet(PG_FUNCTION_ARGS) inet_to_cidr(PG_FUNCTION_ARGS)
{ {
return text_network(PG_GETARG_TEXT_P(0), 0); inet *src = PG_GETARG_INET_P(0);
inet *dst;
int bits;
int byte;
int nbits;
int maxbytes;
bits = ip_bits(src);
/* safety check */
if ((bits < 0) || (bits > ip_maxbits(src)))
elog(ERROR, "invalid inet bit length: %d", bits);
/* clone the original data */
dst = (inet *) palloc(VARSIZE(src));
memcpy(dst, src, VARSIZE(src));
/* zero out any bits to the right of the netmask */
byte = bits / 8;
nbits = bits % 8;
/* clear the first byte, this might be a partial byte */
if (nbits != 0)
{
ip_addr(dst)[byte] &= ~(0xFF >> nbits);
byte++;
}
/* clear remaining bytes */
maxbytes = ip_addrsize(dst);
while (byte < maxbytes)
{
ip_addr(dst)[byte] = 0;
byte++;
}
PG_RETURN_INET_P(dst);
} }
Datum Datum
@ -325,6 +394,50 @@ inet_set_masklen(PG_FUNCTION_ARGS)
PG_RETURN_INET_P(dst); PG_RETURN_INET_P(dst);
} }
Datum
cidr_set_masklen(PG_FUNCTION_ARGS)
{
inet *src = PG_GETARG_INET_P(0);
int bits = PG_GETARG_INT32(1);
inet *dst;
int byte;
int nbits;
int maxbytes;
if (bits == -1)
bits = ip_maxbits(src);
if ((bits < 0) || (bits > ip_maxbits(src)))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid mask length: %d", bits)));
/* clone the original data */
dst = (inet *) palloc(VARSIZE(src));
memcpy(dst, src, VARSIZE(src));
ip_bits(dst) = bits;
/* zero out any bits to the right of the new netmask */
byte = bits / 8;
nbits = bits % 8;
/* clear the first byte, this might be a partial byte */
if (nbits != 0)
{
ip_addr(dst)[byte] &= ~(0xFF >> nbits);
byte++;
}
/* clear remaining bytes */
maxbytes = ip_addrsize(dst);
while (byte < maxbytes)
{
ip_addr(dst)[byte] = 0;
byte++;
}
PG_RETURN_INET_P(dst);
}
/* /*
* Basic comparison function for sorting and inet/cidr comparisons. * Basic comparison function for sorting and inet/cidr comparisons.
* *
@ -424,23 +537,15 @@ network_ne(PG_FUNCTION_ARGS)
/* /*
* Support function for hash indexes on inet/cidr. * Support function for hash indexes on inet/cidr.
*
* Since network_cmp considers only ip_family, ip_bits, and ip_addr, only
* these fields may be used in the hash; in particular don't use is_cidr.
*/ */
Datum Datum
hashinet(PG_FUNCTION_ARGS) hashinet(PG_FUNCTION_ARGS)
{ {
inet *addr = PG_GETARG_INET_P(0); inet *addr = PG_GETARG_INET_P(0);
int addrsize = ip_addrsize(addr); int addrsize = ip_addrsize(addr);
unsigned char key[sizeof(inet_struct)];
Assert(addrsize + 2 <= sizeof(key));
key[0] = ip_family(addr);
key[1] = ip_bits(addr);
memcpy(key + 2, ip_addr(addr), addrsize);
return hash_any(key, addrsize + 2); /* XXX this assumes there are no pad bytes in the data structure */
return hash_any(VARDATA(addr), addrsize + 2);
} }
/* /*
@ -567,7 +672,7 @@ network_show(PG_FUNCTION_ARGS)
} }
Datum Datum
network_abbrev(PG_FUNCTION_ARGS) inet_abbrev(PG_FUNCTION_ARGS)
{ {
inet *ip = PG_GETARG_INET_P(0); inet *ip = PG_GETARG_INET_P(0);
text *ret; text *ret;
@ -575,12 +680,8 @@ network_abbrev(PG_FUNCTION_ARGS)
int len; int len;
char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
if (ip_is_cidr(ip)) dst = inet_net_ntop(ip_family(ip), ip_addr(ip),
dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip), ip_bits(ip), tmp, sizeof(tmp));
ip_bits(ip), tmp, sizeof(tmp));
else
dst = inet_net_ntop(ip_family(ip), ip_addr(ip),
ip_bits(ip), tmp, sizeof(tmp));
if (dst == NULL) if (dst == NULL)
ereport(ERROR, ereport(ERROR,
@ -595,6 +696,31 @@ network_abbrev(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(ret); PG_RETURN_TEXT_P(ret);
} }
Datum
cidr_abbrev(PG_FUNCTION_ARGS)
{
inet *ip = PG_GETARG_INET_P(0);
text *ret;
char *dst;
int len;
char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip),
ip_bits(ip), tmp, sizeof(tmp));
if (dst == NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("could not format cidr value: %m")));
/* Return string as a text datum */
len = strlen(tmp);
ret = (text *) palloc(len + VARHDRSZ);
VARATT_SIZEP(ret) = len + VARHDRSZ;
memcpy(VARDATA(ret), tmp, len);
PG_RETURN_TEXT_P(ret);
}
Datum Datum
network_masklen(PG_FUNCTION_ARGS) network_masklen(PG_FUNCTION_ARGS)
{ {
@ -666,7 +792,6 @@ network_broadcast(PG_FUNCTION_ARGS)
ip_family(dst) = ip_family(ip); ip_family(dst) = ip_family(ip);
ip_bits(dst) = ip_bits(ip); ip_bits(dst) = ip_bits(ip);
ip_is_cidr(dst) = false;
VARATT_SIZEP(dst) = VARHDRSZ VARATT_SIZEP(dst) = VARHDRSZ
+ ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ((char *) ip_addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst); + ip_addrsize(dst);
@ -712,7 +837,6 @@ network_network(PG_FUNCTION_ARGS)
ip_family(dst) = ip_family(ip); ip_family(dst) = ip_family(ip);
ip_bits(dst) = ip_bits(ip); ip_bits(dst) = ip_bits(ip);
ip_is_cidr(dst) = true;
VARATT_SIZEP(dst) = VARHDRSZ VARATT_SIZEP(dst) = VARHDRSZ
+ ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ((char *) ip_addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst); + ip_addrsize(dst);
@ -756,7 +880,6 @@ network_netmask(PG_FUNCTION_ARGS)
ip_family(dst) = ip_family(ip); ip_family(dst) = ip_family(ip);
ip_bits(dst) = ip_maxbits(ip); ip_bits(dst) = ip_maxbits(ip);
ip_is_cidr(dst) = false;
VARATT_SIZEP(dst) = VARHDRSZ VARATT_SIZEP(dst) = VARHDRSZ
+ ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ((char *) ip_addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst); + ip_addrsize(dst);
@ -806,7 +929,6 @@ network_hostmask(PG_FUNCTION_ARGS)
ip_family(dst) = ip_family(ip); ip_family(dst) = ip_family(ip);
ip_bits(dst) = ip_maxbits(ip); ip_bits(dst) = ip_maxbits(ip);
ip_is_cidr(dst) = false;
VARATT_SIZEP(dst) = VARHDRSZ VARATT_SIZEP(dst) = VARHDRSZ
+ ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + ((char *) ip_addr(dst) - (char *) VARDATA(dst))
+ ip_addrsize(dst); + ip_addrsize(dst);
@ -818,11 +940,6 @@ network_hostmask(PG_FUNCTION_ARGS)
* Convert a value of a network datatype to an approximate scalar value. * Convert a value of a network datatype to an approximate scalar value.
* This is used for estimating selectivities of inequality operators * This is used for estimating selectivities of inequality operators
* involving network types. * involving network types.
*
* Currently, inet/cidr values are simply converted to the IPv4 address;
* this will need more thought when IPv6 is supported too. MAC addresses
* are converted to their numeric equivalent as well (OK since we have a
* double to play in).
*/ */
double double
convert_network_to_scalar(Datum value, Oid typid) convert_network_to_scalar(Datum value, Oid typid)
@ -838,7 +955,7 @@ convert_network_to_scalar(Datum value, Oid typid)
int i; int i;
/* /*
* Note that we don't use the full address here. * Note that we don't use the full address for IPv6.
*/ */
if (ip_family(ip) == PGSQL_AF_INET) if (ip_family(ip) == PGSQL_AF_INET)
len = 4; len = 4;
@ -1020,7 +1137,7 @@ inet_client_addr(PG_FUNCTION_ARGS)
if (ret) if (ret)
PG_RETURN_NULL(); PG_RETURN_NULL();
PG_RETURN_INET_P(network_in(remote_host, 0)); PG_RETURN_INET_P(network_in(remote_host, false));
} }
@ -1094,7 +1211,7 @@ inet_server_addr(PG_FUNCTION_ARGS)
if (ret) if (ret)
PG_RETURN_NULL(); PG_RETURN_NULL();
PG_RETURN_INET_P(network_in(local_host, 0)); PG_RETURN_INET_P(network_in(local_host, false));
} }

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.312 2006/01/18 06:49:27 neilc Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.313 2006/01/26 02:35:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200601181 #define CATALOG_VERSION_NO 200601251
#endif #endif

@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.67 2005/11/07 17:36:46 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_amop.h,v 1.68 2006/01/26 02:35:49 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -388,11 +388,11 @@ DATA(insert ( 1974 0 5 f 1205 ));
* btree cidr * btree cidr
*/ */
DATA(insert ( 432 0 1 f 822 )); DATA(insert ( 432 0 1 f 1203 ));
DATA(insert ( 432 0 2 f 823 )); DATA(insert ( 432 0 2 f 1204 ));
DATA(insert ( 432 0 3 f 820 )); DATA(insert ( 432 0 3 f 1201 ));
DATA(insert ( 432 0 4 f 825 )); DATA(insert ( 432 0 4 f 1206 ));
DATA(insert ( 432 0 5 f 824 )); DATA(insert ( 432 0 5 f 1205 ));
/* /*
* btree numeric * btree numeric
@ -523,7 +523,7 @@ DATA(insert ( 427 0 1 f 1054 ));
/* char_ops */ /* char_ops */
DATA(insert ( 431 0 1 f 92 )); DATA(insert ( 431 0 1 f 92 ));
/* cidr_ops */ /* cidr_ops */
DATA(insert ( 433 0 1 f 820 )); DATA(insert ( 433 0 1 f 1201 ));
/* date_ops */ /* date_ops */
DATA(insert ( 435 0 1 f 1093 )); DATA(insert ( 435 0 1 f 1093 ));
/* float4_ops */ /* float4_ops */

@ -10,7 +10,7 @@
* *
* Copyright (c) 2002-2005, PostgreSQL Global Development Group * Copyright (c) 2002-2005, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.24 2005/10/21 15:45:06 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.25 2006/01/26 02:35:49 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -249,7 +249,7 @@ DATA(insert ( 718 604 1544 e ));
* INET category * INET category
*/ */
DATA(insert ( 650 869 0 i )); DATA(insert ( 650 869 0 i ));
DATA(insert ( 869 650 0 i )); DATA(insert ( 869 650 1715 a ));
/* /*
* BitString category * BitString category

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.137 2005/10/15 02:49:42 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_operator.h,v 1.138 2006/01/26 02:35:49 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -637,7 +637,7 @@ DATA(insert OID = 1223 ( "<=" PGNSP PGUID b f 829 829 16 1225 1224 0 0
DATA(insert OID = 1224 ( ">" PGNSP PGUID b f 829 829 16 1222 1223 0 0 0 0 macaddr_gt scalargtsel scalargtjoinsel )); DATA(insert OID = 1224 ( ">" PGNSP PGUID b f 829 829 16 1222 1223 0 0 0 0 macaddr_gt scalargtsel scalargtjoinsel ));
DATA(insert OID = 1225 ( ">=" PGNSP PGUID b f 829 829 16 1223 1222 0 0 0 0 macaddr_ge scalargtsel scalargtjoinsel )); DATA(insert OID = 1225 ( ">=" PGNSP PGUID b f 829 829 16 1223 1222 0 0 0 0 macaddr_ge scalargtsel scalargtjoinsel ));
/* INET type */ /* INET type (these also support CIDR via implicit cast) */
DATA(insert OID = 1201 ( "=" PGNSP PGUID b t 869 869 16 1201 1202 1203 1203 1203 1205 network_eq eqsel eqjoinsel )); DATA(insert OID = 1201 ( "=" PGNSP PGUID b t 869 869 16 1201 1202 1203 1203 1203 1205 network_eq eqsel eqjoinsel ));
DATA(insert OID = 1202 ( "<>" PGNSP PGUID b f 869 869 16 1202 1201 0 0 0 0 network_ne neqsel neqjoinsel )); DATA(insert OID = 1202 ( "<>" PGNSP PGUID b f 869 869 16 1202 1201 0 0 0 0 network_ne neqsel neqjoinsel ));
DATA(insert OID = 1203 ( "<" PGNSP PGUID b f 869 869 16 1205 1206 0 0 0 0 network_lt scalarltsel scalarltjoinsel )); DATA(insert OID = 1203 ( "<" PGNSP PGUID b f 869 869 16 1205 1206 0 0 0 0 network_lt scalarltsel scalarltjoinsel ));
@ -653,22 +653,6 @@ DATA(insert OID = 933 ( ">>" PGNSP PGUID b f 869 869 16 931 0 0 0 0
DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f 869 869 16 932 0 0 0 0 0 network_supeq - - )); DATA(insert OID = 934 ( ">>=" PGNSP PGUID b f 869 869 16 932 0 0 0 0 0 network_supeq - - ));
#define OID_INET_SUPEQ_OP 934 #define OID_INET_SUPEQ_OP 934
/* CIDR type */
DATA(insert OID = 820 ( "=" PGNSP PGUID b t 650 650 16 820 821 822 822 822 824 network_eq eqsel eqjoinsel ));
DATA(insert OID = 821 ( "<>" PGNSP PGUID b f 650 650 16 821 820 0 0 0 0 network_ne neqsel neqjoinsel ));
DATA(insert OID = 822 ( "<" PGNSP PGUID b f 650 650 16 824 825 0 0 0 0 network_lt scalarltsel scalarltjoinsel ));
DATA(insert OID = 823 ( "<=" PGNSP PGUID b f 650 650 16 825 824 0 0 0 0 network_le scalarltsel scalarltjoinsel ));
DATA(insert OID = 824 ( ">" PGNSP PGUID b f 650 650 16 822 823 0 0 0 0 network_gt scalargtsel scalargtjoinsel ));
DATA(insert OID = 825 ( ">=" PGNSP PGUID b f 650 650 16 823 822 0 0 0 0 network_ge scalargtsel scalargtjoinsel ));
DATA(insert OID = 826 ( "<<" PGNSP PGUID b f 650 650 16 828 0 0 0 0 0 network_sub - - ));
#define OID_CIDR_SUB_OP 826
DATA(insert OID = 827 ( "<<=" PGNSP PGUID b f 650 650 16 1004 0 0 0 0 0 network_subeq - - ));
#define OID_CIDR_SUBEQ_OP 827
DATA(insert OID = 828 ( ">>" PGNSP PGUID b f 650 650 16 826 0 0 0 0 0 network_sup - - ));
#define OID_CIDR_SUP_OP 828
DATA(insert OID = 1004 ( ">>=" PGNSP PGUID b f 650 650 16 827 0 0 0 0 0 network_supeq - - ));
#define OID_CIDR_SUPEQ_OP 1004
/* case-insensitive LIKE hacks */ /* case-insensitive LIKE hacks */
DATA(insert OID = 1625 ( "~~*" PGNSP PGUID b f 19 25 16 0 1626 0 0 0 0 nameiclike iclikesel iclikejoinsel )); DATA(insert OID = 1625 ( "~~*" PGNSP PGUID b f 19 25 16 0 1626 0 0 0 0 nameiclike iclikesel iclikejoinsel ));
#define OID_NAME_ICLIKE_OP 1625 #define OID_NAME_ICLIKE_OP 1625

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.392 2006/01/18 06:49:28 neilc Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.393 2006/01/26 02:35:49 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
@ -2391,10 +2391,16 @@ DATA(insert OID = 930 ( network_supeq PGNSP PGUID 12 f f t f i 2 16 "869 869"
DESCR("is-supernet-or-equal"); DESCR("is-supernet-or-equal");
/* inet/cidr functions */ /* inet/cidr functions */
DATA(insert OID = 605 ( abbrev PGNSP PGUID 12 f f t f i 1 25 "869" _null_ _null_ _null_ network_abbrev - _null_ )); DATA(insert OID = 598 ( abbrev PGNSP PGUID 12 f f t f i 1 25 "869" _null_ _null_ _null_ inet_abbrev - _null_ ));
DESCR("abbreviated display of inet/cidr value"); DESCR("abbreviated display of inet value");
DATA(insert OID = 599 ( abbrev PGNSP PGUID 12 f f t f i 1 25 "650" _null_ _null_ _null_ cidr_abbrev - _null_ ));
DESCR("abbreviated display of cidr value");
DATA(insert OID = 605 ( set_masklen PGNSP PGUID 12 f f t f i 2 869 "869 23" _null_ _null_ _null_ inet_set_masklen - _null_ ));
DESCR("change netmask of inet");
DATA(insert OID = 635 ( set_masklen PGNSP PGUID 12 f f t f i 2 650 "650 23" _null_ _null_ _null_ cidr_set_masklen - _null_ ));
DESCR("change netmask of cidr");
DATA(insert OID = 711 ( family PGNSP PGUID 12 f f t f i 1 23 "869" _null_ _null_ _null_ network_family - _null_ )); DATA(insert OID = 711 ( family PGNSP PGUID 12 f f t f i 1 23 "869" _null_ _null_ _null_ network_family - _null_ ));
DESCR("return address family (4 for IPv4, 6 for IPv6)"); DESCR("address family (4 for IPv4, 6 for IPv6)");
DATA(insert OID = 683 ( network PGNSP PGUID 12 f f t f i 1 650 "869" _null_ _null_ _null_ network_network - _null_ )); DATA(insert OID = 683 ( network PGNSP PGUID 12 f f t f i 1 650 "869" _null_ _null_ _null_ network_network - _null_ ));
DESCR("network part of address"); DESCR("network part of address");
DATA(insert OID = 696 ( netmask PGNSP PGUID 12 f f t f i 1 869 "869" _null_ _null_ _null_ network_netmask - _null_ )); DATA(insert OID = 696 ( netmask PGNSP PGUID 12 f f t f i 1 869 "869" _null_ _null_ _null_ network_netmask - _null_ ));
@ -2413,8 +2419,8 @@ DATA(insert OID = 1713 ( inet PGNSP PGUID 12 f f t f i 1 869 "25" _null_ _nu
DESCR("text to inet"); DESCR("text to inet");
DATA(insert OID = 1714 ( cidr PGNSP PGUID 12 f f t f i 1 650 "25" _null_ _null_ _null_ text_cidr - _null_ )); DATA(insert OID = 1714 ( cidr PGNSP PGUID 12 f f t f i 1 650 "25" _null_ _null_ _null_ text_cidr - _null_ ));
DESCR("text to cidr"); DESCR("text to cidr");
DATA(insert OID = 1715 ( set_masklen PGNSP PGUID 12 f f t f i 2 869 "869 23" _null_ _null_ _null_ inet_set_masklen - _null_ )); DATA(insert OID = 1715 ( cidr PGNSP PGUID 12 f f t f i 1 650 "869" _null_ _null_ _null_ inet_to_cidr - _null_ ));
DESCR("change the netmask of an inet"); DESCR("coerce inet to cidr");
DATA(insert OID = 2196 ( inet_client_addr PGNSP PGUID 12 f f f f s 0 869 "" _null_ _null_ _null_ inet_client_addr - _null_ )); DATA(insert OID = 2196 ( inet_client_addr PGNSP PGUID 12 f f f f s 0 869 "" _null_ _null_ _null_ inet_client_addr - _null_ ));
DESCR("INET address of the client"); DESCR("INET address of the client");

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.271 2006/01/18 06:49:29 neilc Exp $ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.272 2006/01/26 02:35:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -720,11 +720,14 @@ extern Datum network_family(PG_FUNCTION_ARGS);
extern Datum network_broadcast(PG_FUNCTION_ARGS); extern Datum network_broadcast(PG_FUNCTION_ARGS);
extern Datum network_host(PG_FUNCTION_ARGS); extern Datum network_host(PG_FUNCTION_ARGS);
extern Datum network_show(PG_FUNCTION_ARGS); extern Datum network_show(PG_FUNCTION_ARGS);
extern Datum network_abbrev(PG_FUNCTION_ARGS); extern Datum inet_abbrev(PG_FUNCTION_ARGS);
extern Datum cidr_abbrev(PG_FUNCTION_ARGS);
extern double convert_network_to_scalar(Datum value, Oid typid); extern double convert_network_to_scalar(Datum value, Oid typid);
extern Datum text_cidr(PG_FUNCTION_ARGS); extern Datum text_cidr(PG_FUNCTION_ARGS);
extern Datum text_inet(PG_FUNCTION_ARGS); extern Datum text_inet(PG_FUNCTION_ARGS);
extern Datum inet_to_cidr(PG_FUNCTION_ARGS);
extern Datum inet_set_masklen(PG_FUNCTION_ARGS); extern Datum inet_set_masklen(PG_FUNCTION_ARGS);
extern Datum cidr_set_masklen(PG_FUNCTION_ARGS);
extern Datum network_scan_first(Datum in); extern Datum network_scan_first(Datum in);
extern Datum network_scan_last(Datum in); extern Datum network_scan_last(Datum in);
extern Datum inet_client_addr(PG_FUNCTION_ARGS); extern Datum inet_client_addr(PG_FUNCTION_ARGS);

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/inet.h,v 1.21 2006/01/23 21:45:47 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/inet.h,v 1.22 2006/01/26 02:35:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -22,7 +22,6 @@ typedef struct
{ {
unsigned char family; /* PGSQL_AF_INET or PGSQL_AF_INET6 */ unsigned char family; /* PGSQL_AF_INET or PGSQL_AF_INET6 */
unsigned char bits; /* number of bits in netmask */ unsigned char bits; /* number of bits in netmask */
bool is_cidr; /* is cidr? */
unsigned char ipaddr[16]; /* up to 128 bits of address */ unsigned char ipaddr[16]; /* up to 128 bits of address */
} inet_struct; } inet_struct;

@ -274,6 +274,8 @@ WHERE c.castfunc = p.oid AND
-- also binary compatible. This is legal, but usually not intended. -- also binary compatible. This is legal, but usually not intended.
-- As of 7.4, this finds the casts from text and varchar to bpchar, because -- As of 7.4, this finds the casts from text and varchar to bpchar, because
-- those are binary-compatible while the reverse way goes through rtrim(). -- those are binary-compatible while the reverse way goes through rtrim().
-- As of 8.2, this finds the cast from cidr to inet, because that is a
-- trivial binary coercion while the other way goes through inet_to_cidr().
SELECT * SELECT *
FROM pg_cast c FROM pg_cast c
WHERE c.castfunc = 0 AND WHERE c.castfunc = 0 AND
@ -285,7 +287,8 @@ WHERE c.castfunc = 0 AND
------------+------------+----------+------------- ------------+------------+----------+-------------
25 | 1042 | 0 | i 25 | 1042 | 0 | i
1043 | 1042 | 0 | i 1043 | 1042 | 0 | i
(2 rows) 650 | 869 | 0 | i
(3 rows)
-- **************** pg_operator **************** -- **************** pg_operator ****************
-- Look for illegal values in pg_operator fields. -- Look for illegal values in pg_operator fields.

@ -223,6 +223,9 @@ WHERE c.castfunc = p.oid AND
-- As of 7.4, this finds the casts from text and varchar to bpchar, because -- As of 7.4, this finds the casts from text and varchar to bpchar, because
-- those are binary-compatible while the reverse way goes through rtrim(). -- those are binary-compatible while the reverse way goes through rtrim().
-- As of 8.2, this finds the cast from cidr to inet, because that is a
-- trivial binary coercion while the other way goes through inet_to_cidr().
SELECT * SELECT *
FROM pg_cast c FROM pg_cast c
WHERE c.castfunc = 0 AND WHERE c.castfunc = 0 AND

Loading…
Cancel
Save