]> granicus.if.org Git - postgresql/commitdiff
Adjust INET/CIDR display conventions and reimplement some INET/CIDR
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Nov 2000 20:13:27 +0000 (20:13 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Nov 2000 20:13:27 +0000 (20:13 +0000)
functions, per recent discussions on pghackers.  For now, I have called
the verbose-display formatting function text(), but will reconsider if
enough people object.
initdb forced.

doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
doc/src/sgml/oper.sgml
src/backend/utils/adt/inet_net_ntop.c
src/backend/utils/adt/network.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/builtins.h
src/test/regress/expected/inet.out
src/test/regress/sql/inet.sql

index f3e7aa83abf23528b7e2d9e07bd6526c1d8d66b9..11ccc2a9a60215e79d50e391ca200b2e962c9720 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.39 2000/11/10 20:13:25 tgl Exp $
 -->
 
  <chapter id="datatype">
@@ -65,7 +65,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe
       <row>
        <entry>cidr</entry>
        <entry></entry>
-       <entry>IP version 4 network or host address</entry>
+       <entry>IP network address</entry>
       </row>
       <row>
        <entry>circle</entry>
@@ -95,7 +95,7 @@ $Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.38 2000/10/04 15:47:45 pe
       <row>
        <entry>inet</entry>
        <entry></entry>
-       <entry>IP version 4 network or host address</entry>
+       <entry>IP network or host address</entry>
       </row>
       <row>
        <entry>int2</entry>
@@ -1736,7 +1736,7 @@ January 8 04:05:06 1999 PST
 
    <para>
     <productname>Postgres</> offers data types to store IP and MAC
-    addresses.  It is preferrable to use these types over plain text
+    addresses.  It is preferable to use these types over plain text
     types, because these types offer input error checking and several
     specialized operators and functions.
 
@@ -1755,16 +1755,16 @@ January 8 04:05:06 1999 PST
 
        <row>
        <entry>cidr</entry>
-       <entry>11 bytes</entry>
+       <entry>12 bytes</entry>
        <entry>IP networks</entry>
        <entry>valid IPv4 networks</entry>
        </row>
 
        <row>
        <entry>inet</entry>
-       <entry>11 bytes</entry>
+       <entry>12 bytes</entry>
        <entry>IP hosts and networks</entry>
-       <entry>valid IPv4 hosts</entry>
+       <entry>valid IPv4 hosts or networks</entry>
        </row>
 
        <row>
@@ -1784,19 +1784,48 @@ January 8 04:05:06 1999 PST
    </para>
 
 
+   <sect2 id="inet-type">
+    <title><type>inet</type></title>
+
+    <para>
+     The <type>inet</type> type holds an IP host address, and
+     optionally the identity of the subnet it is in, all in one field.
+     The subnet identity is represented by the number of bits in the
+     network part of the address (the "netmask").  If the netmask is 32,
+     then the value does not indicate a subnet, only a single host.
+     Note that if you want to accept networks only, you should use the
+     <type>cidr</type> type rather than <type>inet</type>.
+    </para>
+
+    <para>
+     The input format for this type is <replaceable
+     class="parameter">x.x.x.x/y</replaceable> where <replaceable
+     class="parameter">x.x.x.x</replaceable> is an IP address and
+     <replaceable class="parameter">y</replaceable> is the number of
+     bits in the netmask.  If the <replaceable
+     class="parameter">y</replaceable> part is left off, then the
+     netmask is 32, and the value represents just a single host.
+     On display, the <replaceable class="parameter">/y</replaceable>
+     portion is suppressed if the netmask is 32.
+    </para>
+   </sect2>
+
    <sect2 id="cidr-type">
     <title><type>cidr</></title>
 
     <para>
-     The <type>cidr</type> type holds an IP network.  The format for
+     The <type>cidr</type> type holds an IP network specification.
+     Input and output formats follow Classless Internet Domain Routing
+     conventions.
+     The format for
      specifying classless networks is <replaceable
      class="parameter">x.x.x.x/y</> where <replaceable
      class="parameter">x.x.x.x</> is the network and <replaceable
      class="parameter">y</> is the number of bits in the netmask.  If
      <replaceable class="parameter">y</> omitted, it is calculated
-     using assumptions from the older classfull naming system except
-     that it is extended to include at least all of the octets in the
-     input.
+     using assumptions from the older classful numbering system, except
+     that it will be at least large enough to include all of the octets
+     written in the input.
     </para>
 
     <para>
@@ -1816,6 +1845,10 @@ January 8 04:05:06 1999 PST
         <entry>192.168.100.128/25</entry>
         <entry>192.168.100.128/25</entry>
        </row>
+       <row>
+        <entry>192.168/24</entry>
+        <entry>192.168.0/24</entry>
+       </row>
        <row>
         <entry>192.168/25</entry>
         <entry>192.168.0.0/25</entry>
@@ -1856,30 +1889,19 @@ January 8 04:05:06 1999 PST
       </tgroup>
      </table>
     </para>
-   </sect2>
-
-   <sect2 id="inet-type">
-    <title><type>inet</type></title>
 
     <para>
-     The <type>inet</type> type holds an IP host address, and
-     optionally the identity of the subnet it is in, all in one field.
-     Note that if you want to store networks only, you should use the
-     <type>cidr</type> type.  The <type>inet</type> type is similar to
-     the <type>cidr</type> type except that the bits in the host part
-     can be non-zero.  Functions exist to extract the various elements
-     of the field.
-    </para>
-
-    <para>
-     The input format for this type is <replaceable
-     class="parameter">x.x.x.x/y</replaceable> where <replaceable
-     class="parameter">x.x.x.x</replaceable> is an internet host and
-     <replaceable class="parameter">y</replaceable> is the number of
-     bits in the netmask.  If the <replaceable
-     class="parameter">y</replaceable> part is left off, then the
-     netmask is 32 and you are effectively only storing the address of
-     a single host.
+    The essential difference between <type>inet</type> and <type>cidr</type>
+    data types is that <type>inet</type> accepts values with nonzero bits to
+    the right of the netmask, whereas <type>cidr</type> does not.
+
+      <tip>
+        <para>
+       If you do not like the output format for <type>inet</type> or
+       <type>cidr</type> values, try the <function>host</>() and
+       <function>text</>() functions.
+       </para>
+      </tip>
     </para>
    </sect2>
 
index c51e8905e1095219607523e5e8d0210badf7ace7..655c63a79311968767ff2d437e51fb7b86dec5e4 100644 (file)
@@ -1480,62 +1480,98 @@ Not defined by this name. Implements the intersection operator '#'
    <para>
     <table tocentry="1" id="cidr-inet-functions">
      <title><type>cidr</> and <type>inet</> Functions</title>
-     <tgroup cols="4">
+     <tgroup cols="5">
       <thead>
        <row>
        <entry>Function</entry>
        <entry>Returns</entry>
        <entry>Description</entry>
        <entry>Example</entry>
+       <entry>Result</entry>
        </row>
       </thead>
       <tbody>
-       <row>
-       <entry>broadcast(cidr)</entry>
-       <entry>text</entry>
-       <entry>construct broadcast address as text</entry>
-       <entry>broadcast('192.168.1.5/24')</entry>
-       </row>
        <row>
        <entry>broadcast(inet)</entry>
-       <entry>text</entry>
-       <entry>construct broadcast address as text</entry>
+       <entry>inet</entry>
+       <entry>broadcast address for network</entry>
        <entry>broadcast('192.168.1.5/24')</entry>
+       <entry>192.168.1.255/24</entry>
        </row>
        <row>
        <entry>host(inet)</entry>
        <entry>text</entry>
-       <entry>extract host address as text</entry>
+       <entry>extract IP address as text</entry>
        <entry>host('192.168.1.5/24')</entry>
-       </row>
-       <row>
-       <entry>masklen(cidr)</entry>
-       <entry>integer</entry>
-       <entry>calculate netmask length</entry>
-       <entry>masklen('192.168.1.5/24')</entry>
+       <entry>192.168.1.5</entry>
        </row>
        <row>
        <entry>masklen(inet)</entry>
        <entry>integer</entry>
-       <entry>calculate netmask length</entry>
+       <entry>extract netmask length</entry>
        <entry>masklen('192.168.1.5/24')</entry>
+       <entry>24</entry>
        </row>
        <row>
        <entry>netmask(inet)</entry>
-       <entry>text</entry>
-       <entry>construct netmask as text</entry>
+       <entry>inet</entry>
+       <entry>construct netmask for network</entry>
        <entry>netmask('192.168.1.5/24')</entry>
+       <entry>255.255.255.0</entry>
+       </row>
+       <row>
+       <entry>network(inet)</entry>
+       <entry>cidr</entry>
+       <entry>extract network part of address</entry>
+       <entry>network('192.168.1.5/24')</entry>
+       <entry>192.168.1/24</entry>
+       </row>
+       <row>
+       <entry>text(inet)</entry>
+       <entry>text</entry>
+       <entry>extract IP address and masklen as text</entry>
+       <entry>text(inet '192.168.1.5')</entry>
+       <entry>192.168.1.5/32</entry>
+       </row>
+      </tbody>
+     </tgroup>
+    </table>
+   </para>
+
+   <para>
+    All of the functions for <type>inet</type> can be applied to
+    <type>cidr</type> values as well.  The <function>host</>() and
+    <function>text</>() functions are primarily intended to offer
+    alternative display formats.
+   </para>
+
+   <para>
+    <table tocentry="1" id="macaddr-functions">
+     <title><type>macaddr</> Functions</title>
+     <tgroup cols="5">
+      <thead>
+       <row>
+       <entry>Function</entry>
+       <entry>Returns</entry>
+       <entry>Description</entry>
+       <entry>Example</entry>
+       <entry>Result</entry>
        </row>
+      </thead>
+      <tbody>
        <row>
        <entry>trunc(macaddr)</entry>
        <entry>macaddr</entry>
        <entry>set last 3 bytes to zero</entry>
        <entry>trunc(macaddr '12:34:56:78:90:ab')</entry>
+       <entry>12:34:56:00:00:00</entry>
        </row>
       </tbody>
      </tgroup>
     </table>
+   </para>
 
+   <para>
     The function <function>trunc</>(<type>macaddr</>) returns a MAC
     address with the last 3 bytes set to 0.  This can be used to
     associate the remaining prefix with a manufacturer.  The directory
index deb3d33cde837f56842af35509bc25edee9329fd..8934323cd05e7e5c9dc0f58905dc5d48ad507fbf 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/Attic/oper.sgml,v 1.21 2000/10/24 20:13:31 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/Attic/oper.sgml,v 1.22 2000/11/10 20:13:25 tgl Exp $
 -->
 
  <Chapter Id="operators">
@@ -756,80 +756,11 @@ logical union
   <sect1 id="net-operators">
    <title>Network Address Type Operators</title>
 
-   <sect2 id="cidr-operators">
-    <title><type>cidr</> Operators</title>
+   <sect2 id="cidr-inet-operators">
+    <title><type>cidr</> and <type>inet</> Operators</title>
 
-    <table tocentry="1" id="cidr-operators-table">
-     <title><type>cidr</> Operators</title>
-     <TGROUP COLS="3">
-      <THEAD>
-       <ROW>
-       <ENTRY>Operator</ENTRY>
-       <ENTRY>Description</ENTRY>
-       <ENTRY>Usage</ENTRY>
-       </ROW>
-      </THEAD>
-      <TBODY>
-       <ROW>
-       <ENTRY> &lt; </ENTRY>
-       <ENTRY>Less than</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr &lt; '192.168.1.6'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &lt;= </ENTRY>
-       <ENTRY>Less than or equal</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr &lt;= '192.168.1.5'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> = </ENTRY>
-       <ENTRY>Equals</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr = '192.168.1.5'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &gt;= </ENTRY>
-       <ENTRY>Greater or equal</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr &gt;= '192.168.1.5'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &gt; </ENTRY>
-       <ENTRY>Greater</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr &gt; '192.168.1.4'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &lt;&gt; </ENTRY>
-       <ENTRY>Not equal</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr &lt;&gt; '192.168.1.4'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &lt;&lt; </ENTRY>
-       <ENTRY>is contained within</ENTRY>
-       <ENTRY>'192.168.1.5'::cidr &lt;&lt; '192.168.1/24'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &lt;&lt;= </ENTRY>
-       <ENTRY>is contained within or equals</ENTRY>
-       <ENTRY>'192.168.1/24'::cidr &lt;&lt;= '192.168.1/24'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &gt;&gt; </ENTRY>
-       <ENTRY>contains</ENTRY>
-       <ENTRY>'192.168.1/24'::cidr &gt;&gt; '192.168.1.5'::cidr</ENTRY>
-       </ROW>
-       <ROW>
-       <ENTRY> &gt;&gt;= </ENTRY>
-       <ENTRY>contains or equals</ENTRY>
-       <ENTRY>'192.168.1/24'::cidr &gt;&gt;= '192.168.1/24'::cidr</ENTRY>
-       </ROW>
-      </TBODY>
-     </TGROUP>
-    </TABLE>
-   </sect2>
-
-   <sect2 id="inet-operators">
-   <title><type>inet</> Operators</title>
-   
-    <table tocentry="1" id="inet-operators-table">
-     <title><type>inet</> Operators</title>
+    <table tocentry="1" id="cidr-inet-operators-table">
+     <title><type>cidr</> and <type>inet</> Operators</title>
      <TGROUP COLS="3">
       <THEAD>
        <ROW>
@@ -892,6 +823,16 @@ logical union
       </TBODY>
      </TGROUP>
     </TABLE>
+
+    <para>
+     All of the operators for <type>inet</type> can be applied to
+     <type>cidr</type> values as well.  The operators
+     <literal>&lt;&lt;</> <literal>&lt;&lt;=</>
+     <literal>&gt;&gt;</> <literal>&gt;&gt;=</>
+     test for subnet inclusion: they consider only the network parts
+     of the two addresses, ignoring any host part, and determine whether
+     one network part is identical to or a subnet of the other.
+    </para>
    </sect2>
 
    <sect2 id="macaddr-operators">
index c38ecc5a6f2150181052657bc7ad965ce2f3a4e7..ecc83cab8148b9266f403504a7f5828436cb42e5 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.8 1999/07/17 20:17:56 momjian Exp $";
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.9 2000/11/10 20:13:25 tgl Exp $";
 
 #endif
 
@@ -56,7 +56,7 @@ inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
 {
        switch (af)
        {
-                       case AF_INET:
+               case AF_INET:
                        return (inet_cidr_ntop_ipv4(src, bits, dst, size));
                default:
                        errno = EAFNOSUPPORT;
@@ -102,15 +102,12 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
        /* Format whole octets. */
        for (b = bits / 8; b > 0; b--)
        {
-               if (size < sizeof "255.")
+               if (size < sizeof ".255")
                        goto emsgsize;
                t = dst;
-               dst += SPRINTF((dst, "%u", *src++));
-               if (b > 1)
-               {
+               if (dst != odst)
                        *dst++ = '.';
-                       *dst = '\0';
-               }
+               dst += SPRINTF((dst, "%u", *src++));
                size -= (size_t) (dst - t);
        }
 
@@ -132,6 +129,7 @@ inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
        if (size < sizeof "/32")
                goto emsgsize;
        dst += SPRINTF((dst, "/%u", bits));
+
        return (odst);
 
 emsgsize:
@@ -159,7 +157,7 @@ inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
 {
        switch (af)
        {
-                       case AF_INET:
+               case AF_INET:
                        return (inet_net_ntop_ipv4(src, bits, dst, size));
                default:
                        errno = EAFNOSUPPORT;
@@ -185,48 +183,34 @@ inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
 {
        char       *odst = dst;
        char       *t;
-       size_t          len = 4;
-       int                     b,
-                               tb;
+       int                     len = 4;
+       int                     b;
 
        if (bits < 0 || bits > 32)
        {
                errno = EINVAL;
                return (NULL);
        }
-       if (bits == 0)
-       {
-               if (size < sizeof "0")
-                       goto emsgsize;
-               *dst++ = '0';
-               size--;
-               *dst = '\0';
-       }
 
-       /* Format whole octets plus nonzero trailing octets. */
-       tb = (bits == 32) ? 31 : bits;
-       for (b = 0; bits != 0 && (b <= (tb / 8) || (b < len && *src != 0)); b++)
+       /* Always format all four octets, regardless of mask length. */
+       for (b = len; b > 0; b--)
        {
-               if (size < sizeof "255.")
+               if (size < sizeof ".255")
                        goto emsgsize;
                t = dst;
-               dst += SPRINTF((dst, "%u", *src++));
-               if (b + 1 <= (tb / 8) || (b + 1 < len && *src != 0))
-               {
+               if (dst != odst)
                        *dst++ = '.';
-                       *dst = '\0';
-               }
+               dst += SPRINTF((dst, "%u", *src++));
                size -= (size_t) (dst - t);
        }
 
        /* don't print masklen if 32 bits */
-       if (bits == 32)
-               return odst;
-
-       /* Format CIDR /width. */
-       if (size < sizeof "/32")
-               goto emsgsize;
-       dst += SPRINTF((dst, "/%u", bits));
+       if (bits != 32)
+       {
+               if (size < sizeof "/32")
+                       goto emsgsize;
+               dst += SPRINTF((dst, "/%u", bits));
+       }
 
        return (odst);
 
index a3070f29e76a1f6d1e73ad97704087d8f1059199..52f4e8ecd2fdc9ec7bf401261b9f155692feb8d6 100644 (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.25 2000/10/27 01:52:15 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.26 2000/11/10 20:13:25 tgl Exp $
  *
  *     Jon Postel RIP 16 Oct 1998
  */
@@ -67,12 +67,12 @@ network_in(char *src, int type)
 
        /*
         * Error check: CIDR values must not have any bits set beyond the masklen.
-        * XXX this code not IPV6 ready.
+        * XXX this code is not IPV6 ready.
         */
        if (type)
        {
                if (! v4addressOK(ip_v4addr(dst), bits))
-                       elog(ERROR, "invalid CIDR value '%s': width too small", src);
+                       elog(ERROR, "invalid CIDR value '%s': has bits set to right of mask", src);
        }
 
        VARATT_SIZEP(dst) = VARHDRSZ
@@ -338,12 +338,10 @@ network_host(PG_FUNCTION_ARGS)
        char       *ptr,
                                tmp[sizeof("255.255.255.255/32")];
 
-       if (ip_type(ip))
-               elog(ERROR, "CIDR type has no host part");
-
        if (ip_family(ip) == AF_INET)
        {
                /* It's an IP V4 address: */
+               /* force display of 32 bits, regardless of masklen... */
                if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
                        elog(ERROR, "unable to print host (%s)", strerror(errno));
        }
@@ -351,7 +349,7 @@ network_host(PG_FUNCTION_ARGS)
                /* Go for an IPV6 address here, before faulting out: */
                elog(ERROR, "unknown address family (%d)", ip_family(ip));
 
-       /* Suppress /n if present */
+       /* Suppress /n if present (shouldn't happen now) */
        if ((ptr = strchr(tmp, '/')) != NULL)
                *ptr = '\0';
 
@@ -363,6 +361,40 @@ network_host(PG_FUNCTION_ARGS)
        PG_RETURN_TEXT_P(ret);
 }
 
+Datum
+network_show(PG_FUNCTION_ARGS)
+{
+       inet       *ip = PG_GETARG_INET_P(0);
+       text       *ret;
+       int                     len;
+       char            tmp[sizeof("255.255.255.255/32")];
+
+       if (ip_family(ip) == AF_INET)
+       {
+               /* It's an IP V4 address: */
+               /* force display of 32 bits, regardless of masklen... */
+               if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
+                       elog(ERROR, "unable to print host (%s)", strerror(errno));
+       }
+       else
+               /* Go for an IPV6 address here, before faulting out: */
+               elog(ERROR, "unknown address family (%d)", ip_family(ip));
+
+       /* Add /n if not present */
+       if (strchr(tmp, '/') == NULL)
+       {
+               len = strlen(tmp);
+               snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip));
+       }
+
+       /* 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
 network_masklen(PG_FUNCTION_ARGS)
 {
@@ -375,100 +407,100 @@ Datum
 network_broadcast(PG_FUNCTION_ARGS)
 {
        inet       *ip = PG_GETARG_INET_P(0);
-       text       *ret;
-       int                     len;
-       char       *ptr,
-                               tmp[sizeof("255.255.255.255/32")];
+       inet       *dst;
+
+       dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
+       /* make sure any unused bits are zeroed */
+       MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
 
        if (ip_family(ip) == AF_INET)
        {
                /* It's an IP V4 address: */
-               int                     addr;
                unsigned long mask = 0xffffffff;
 
-               if (ip_bits(ip) < 32)
-                       mask >>= ip_bits(ip);
-               addr = htonl(ntohl(ip_v4addr(ip)) | mask);
+               mask >>= ip_bits(ip);
 
-               if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL)
-                       elog(ERROR, "unable to print address (%s)", strerror(errno));
+               ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) | mask);
        }
        else
                /* Go for an IPV6 address here, before faulting out: */
                elog(ERROR, "unknown address family (%d)", ip_family(ip));
 
-       /* Suppress /n if present */
-       if ((ptr = strchr(tmp, '/')) != NULL)
-               *ptr = '\0';
+       ip_family(dst) = ip_family(ip);
+       ip_bits(dst) = ip_bits(ip);
+       ip_type(dst) = 0;
+       VARATT_SIZEP(dst) = VARHDRSZ
+               + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
+               + ip_addrsize(dst);
 
-       /* 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);
+       PG_RETURN_INET_P(dst);
 }
 
 Datum
 network_network(PG_FUNCTION_ARGS)
 {
        inet       *ip = PG_GETARG_INET_P(0);
-       text       *ret;
-       int                     len;
-       char            tmp[sizeof("255.255.255.255/32")];
+       inet       *dst;
+
+       dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
+       /* make sure any unused bits are zeroed */
+       MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
 
        if (ip_family(ip) == AF_INET)
        {
                /* It's an IP V4 address: */
-               int                     addr = htonl(ntohl(ip_v4addr(ip)) & (0xffffffff << (32 - ip_bits(ip))));
+               unsigned long mask = 0xffffffff;
 
-               if (inet_cidr_ntop(AF_INET, &addr, ip_bits(ip), tmp, sizeof(tmp)) == NULL)
-                       elog(ERROR, "unable to print network (%s)", strerror(errno));
+               mask <<= (32 - ip_bits(ip));
+
+               ip_v4addr(dst) = htonl(ntohl(ip_v4addr(ip)) & mask);
        }
        else
                /* Go for an IPV6 address here, before faulting out: */
                elog(ERROR, "unknown address family (%d)", ip_family(ip));
 
-       /* 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);
+       ip_family(dst) = ip_family(ip);
+       ip_bits(dst) = ip_bits(ip);
+       ip_type(dst) = 1;
+       VARATT_SIZEP(dst) = VARHDRSZ
+               + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
+               + ip_addrsize(dst);
+
+       PG_RETURN_INET_P(dst);
 }
 
 Datum
 network_netmask(PG_FUNCTION_ARGS)
 {
        inet       *ip = PG_GETARG_INET_P(0);
-       text       *ret;
-       int                     len;
-       char       *ptr,
-                               tmp[sizeof("255.255.255.255/32")];
+       inet       *dst;
+
+       dst = (inet *) palloc(VARHDRSZ + sizeof(inet_struct));
+       /* make sure any unused bits are zeroed */
+       MemSet(dst, 0, VARHDRSZ + sizeof(inet_struct));
 
        if (ip_family(ip) == AF_INET)
        {
                /* It's an IP V4 address: */
-               int                     addr = htonl(ip_bits(ip) ?
-                                  (-1 << (32 - ip_bits(ip))) & 0xffffffff : 0x00000000);
+               unsigned long mask = 0xffffffff;
+
+               mask <<= (32 - ip_bits(ip));
+
+               ip_v4addr(dst) = htonl(mask);
 
-               if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL)
-                       elog(ERROR, "unable to print netmask (%s)", strerror(errno));
+               ip_bits(dst) = 32;
        }
        else
                /* Go for an IPV6 address here, before faulting out: */
                elog(ERROR, "unknown address family (%d)", ip_family(ip));
 
-       /* Suppress /n if present */
-       if ((ptr = strchr(tmp, '/')) != NULL)
-               *ptr = '\0';
+       ip_family(dst) = ip_family(ip);
+       ip_type(dst) = 0;
+       VARATT_SIZEP(dst) = VARHDRSZ
+               + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
+               + ip_addrsize(dst);
 
-       /* 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);
+       PG_RETURN_INET_P(dst);
 }
 
 /*
index 01efe5efb98cd04aa43104d06962c0b74a32b6a6..bf66917aa7f7aa4453aabea0caae497af50146ef 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.56 2000/11/08 16:59:50 petere Exp $
+ * $Id: catversion.h,v 1.57 2000/11/10 20:13:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200011080
+#define CATALOG_VERSION_NO     200011101
 
 #endif
index 30a7b2d99821528bf70876f63922cfb287a1cb3d..11f20071c7e2bc2956830b6f93f611f55aa61b8c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.172 2000/11/06 15:58:46 thomas Exp $
+ * $Id: pg_proc.h,v 1.173 2000/11/10 20:13:26 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -2270,17 +2270,19 @@ DESCR("is-supernet");
 DATA(insert OID = 930 (  network_supeq         PGUID 12 f t t t 2 f 16 "869 869" 100 0 0 100   network_supeq - ));
 DESCR("is-supernet-or-equal");
 
-/* inet/cidr versions */
-DATA(insert OID = 696 (  netmask                       PGUID 12 f t t t 1 f 25 "869" 100 0 0 100  network_netmask - ));
+/* inet/cidr functions */
+DATA(insert OID = 683 (  network                       PGUID 12 f t t t 1 f 650 "869" 100 0 0 100  network_network - ));
+DESCR("network part of address");
+DATA(insert OID = 696 (  netmask                       PGUID 12 f t t t 1 f 869 "869" 100 0 0 100  network_netmask - ));
 DESCR("netmask of address");
 DATA(insert OID = 697 (  masklen                       PGUID 12 f t t t 1 f 23 "869" 100 0 0 100  network_masklen - ));
 DESCR("netmask length");
-DATA(insert OID = 698 (  broadcast                     PGUID 12 f t t t 1 f 25 "869" 100 0 0 100  network_broadcast - ));
-DESCR("broadcast address");
+DATA(insert OID = 698 (  broadcast                     PGUID 12 f t t t 1 f 869 "869" 100 0 0 100  network_broadcast - ));
+DESCR("broadcast address of network");
 DATA(insert OID = 699 (  host                          PGUID 12 f t t t 1 f 25 "869" 100 0 0 100  network_host - ));
-DESCR("host address");
-DATA(insert OID = 683 (  network                       PGUID 12 f t t t 1 f 25 "869" 100 0 0 100  network_network - ));
-DESCR("network address");
+DESCR("show address octets only");
+DATA(insert OID = 730 (  text                          PGUID 12 f t t t 1 f 25 "869" 100 0 0 100  network_show - ));
+DESCR("show all parts of inet/cidr value");
 
 DATA(insert OID =  1691 (  boolle                      PGUID 12 f t t t 2 f 16 "16 16" 100 0 0 100  boolle - ));
 DESCR("less-than-or-equal");
index 446c33cc420684f505bfbcd66a797d53017f1eeb..f6a4055bb1d030a087eae5a9648475211b2a667d 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.140 2000/10/24 20:16:47 petere Exp $
+ * $Id: builtins.h,v 1.141 2000/11/10 20:13:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -504,6 +504,7 @@ extern Datum network_netmask(PG_FUNCTION_ARGS);
 extern Datum network_masklen(PG_FUNCTION_ARGS);
 extern Datum network_broadcast(PG_FUNCTION_ARGS);
 extern Datum network_host(PG_FUNCTION_ARGS);
+extern Datum network_show(PG_FUNCTION_ARGS);
 
 /* mac.c */
 extern Datum macaddr_in(PG_FUNCTION_ARGS);
index daa9cded1333a57f35881e0a7464f58a81c14c1a..6f86056c0132b4046a093eaa0a9899ee17276f14 100644 (file)
@@ -17,7 +17,7 @@ INSERT INTO INET_TBL (c, i) VALUES ('10', '11.1.2.3/8');
 INSERT INTO INET_TBL (c, i) VALUES ('10', '9.1.2.3/8');
 -- check that CIDR rejects invalid input:
 INSERT INTO INET_TBL (c, i) VALUES ('192.168.1.2/24', '192.168.1.226');
-ERROR:  invalid CIDR value '192.168.1.2/24': width too small
+ERROR:  invalid CIDR value '192.168.1.2/24': has bits set to right of mask
 SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
  ten |     cidr     |       inet       
 -----+--------------+------------------
@@ -34,35 +34,35 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
 (10 rows)
 
 -- now test some support functions
-SELECT '' AS ten, i AS inet, host(i) FROM INET_TBL;
- ten |       inet       |     host      
------+------------------+---------------
-     | 192.168.1.226/24 | 192.168.1.226
-     | 192.168.1.226    | 192.168.1.226
-     | 10.1.2.3/8       | 10.1.2.3
-     | 10.1.2.3/8       | 10.1.2.3
-     | 10.1.2.3         | 10.1.2.3
-     | 10.1.2.3/24      | 10.1.2.3
-     | 10.1.2.3/16      | 10.1.2.3
-     | 10.1.2.3/8       | 10.1.2.3
-     | 11.1.2.3/8       | 11.1.2.3
-     | 9.1.2.3/8        | 9.1.2.3
+SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL;
+ ten |       inet       |     host      |       text       
+-----+------------------+---------------+------------------
+     | 192.168.1.226/24 | 192.168.1.226 | 192.168.1.226/24
+     | 192.168.1.226    | 192.168.1.226 | 192.168.1.226/32
+     | 10.1.2.3/8       | 10.1.2.3      | 10.1.2.3/8
+     | 10.1.2.3/8       | 10.1.2.3      | 10.1.2.3/8
+     | 10.1.2.3         | 10.1.2.3      | 10.1.2.3/32
+     | 10.1.2.3/24      | 10.1.2.3      | 10.1.2.3/24
+     | 10.1.2.3/16      | 10.1.2.3      | 10.1.2.3/16
+     | 10.1.2.3/8       | 10.1.2.3      | 10.1.2.3/8
+     | 11.1.2.3/8       | 11.1.2.3      | 11.1.2.3/8
+     | 9.1.2.3/8        | 9.1.2.3       | 9.1.2.3/8
 (10 rows)
 
 SELECT '' AS ten, c AS cidr, broadcast(c),
   i AS inet, broadcast(i) FROM INET_TBL;
- ten |     cidr     |    broadcast    |       inet       |    broadcast    
------+--------------+-----------------+------------------+-----------------
-     | 192.168.1/24 | 192.168.1.255   | 192.168.1.226/24 | 192.168.1.255
-     | 192.168.1/24 | 192.168.1.255   | 192.168.1.226    | 255.255.255.255
-     | 10/8         | 10.255.255.255  | 10.1.2.3/8       | 10.255.255.255
-     | 10.0.0.0/32  | 255.255.255.255 | 10.1.2.3/8       | 10.255.255.255
-     | 10.1.2.3/32  | 255.255.255.255 | 10.1.2.3         | 255.255.255.255
-     | 10.1.2/24    | 10.1.2.255      | 10.1.2.3/24      | 10.1.2.255
-     | 10.1/16      | 10.1.255.255    | 10.1.2.3/16      | 10.1.255.255
-     | 10/8         | 10.255.255.255  | 10.1.2.3/8       | 10.255.255.255
-     | 10/8         | 10.255.255.255  | 11.1.2.3/8       | 11.255.255.255
-     | 10/8         | 10.255.255.255  | 9.1.2.3/8        | 9.255.255.255
+ ten |     cidr     |    broadcast     |       inet       |    broadcast     
+-----+--------------+------------------+------------------+------------------
+     | 192.168.1/24 | 192.168.1.255/24 | 192.168.1.226/24 | 192.168.1.255/24
+     | 192.168.1/24 | 192.168.1.255/24 | 192.168.1.226    | 255.255.255.255
+     | 10/8         | 10.255.255.255/8 | 10.1.2.3/8       | 10.255.255.255/8
+     | 10.0.0.0/32  | 255.255.255.255  | 10.1.2.3/8       | 10.255.255.255/8
+     | 10.1.2.3/32  | 255.255.255.255  | 10.1.2.3         | 255.255.255.255
+     | 10.1.2/24    | 10.1.2.255/24    | 10.1.2.3/24      | 10.1.2.255/24
+     | 10.1/16      | 10.1.255.255/16  | 10.1.2.3/16      | 10.1.255.255/16
+     | 10/8         | 10.255.255.255/8 | 10.1.2.3/8       | 10.255.255.255/8
+     | 10/8         | 10.255.255.255/8 | 11.1.2.3/8       | 11.255.255.255/8
+     | 10/8         | 10.255.255.255/8 | 9.1.2.3/8        | 9.255.255.255/8
 (10 rows)
 
 SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",
index e225b2824f7920d45c72b31ccd78023cdc12322d..d91c3a0bbf078713590ec1907cbb10a121cd2182 100644 (file)
@@ -23,7 +23,7 @@ SELECT '' AS ten, c AS cidr, i AS inet FROM INET_TBL;
 
 -- now test some support functions
 
-SELECT '' AS ten, i AS inet, host(i) FROM INET_TBL;
+SELECT '' AS ten, i AS inet, host(i), text(i) FROM INET_TBL;
 SELECT '' AS ten, c AS cidr, broadcast(c),
   i AS inet, broadcast(i) FROM INET_TBL;
 SELECT '' AS ten, c AS cidr, network(c) AS "network(cidr)",