Re: queries against CIDR fail against 8.0.3?

Поиск
Список
Период
Сортировка
От Russell Francis
Тема Re: queries against CIDR fail against 8.0.3?
Дата
Msg-id 433DF50D.7060206@ev.net
обсуждение исходный текст
Ответ на Re: queries against CIDR fail against 8.0.3?  (Kris Jurka <books@ejurka.com>)
Ответы Re: queries against CIDR fail against 8.0.3?  (Russell Francis <rfrancis@ev.net>)
Список pgsql-jdbc
>
> Seems reasonable for us to offer a PGxxx class for every core backend
> type.  Send them in and we'll take a look...
>
> Kris Jurka
>

Kris,

Attached is an implementation for the proposed PGcidr & PGinet classes.
 I have tried to follow the formatting conventions used in the geometric
extensions but is is a first attempt, please let me know if there is
anything else I should/could do to improve these.

I will take any comments / suggestions and incorporate them into the
PGmacaddr class also.

Cheers,
Russ


/*-------------------------------------------------------------------------
*
*    Copyright (C) 2005, PostgreSQL Global Development Group
*
*--------------------------------------------------------------------------
*/
package org.postgresql.net;

import java.io.Serializable;
import java.sql.SQLException;
import org.postgresql.util.GT;
import org.postgresql.util.PGobject;
import org.postgresql.util.PGtokenizer;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;

/**
 *    This represents org.postgresql's cidr datatype, which is
 *    used to hold network addresses.
 *
 *    <p>
 *    This class wraps the postgresql specific CIDR datatype. It
 *    supports IPV4 network addresses in the following format.
 *    <p>
 *    a[.b[.c[.d]]][/e]
 *
 *    @author Russell Francis < rfrancis@ev.net >
 */
public class PGcidr extends PGobject implements Serializable, Cloneable
{
    protected int hashValue;

    /**
     *    This constructor takes a string in the
     *    cidr format a[.b[.c[.d]]][/e] and creates
     *    a PGcidr to represent it.
     *
     *    @param s The representation of the cidr as a string.
     *    @exception SQLException if the string is not in the proper format.
     */
    public PGcidr( String s )
    throws SQLException
    {
        this();
        setValue( s );
    }

    /**
     *    A simple constructor.
     */
    public PGcidr()
    {
        setType( "cidr" );
    }

    /**
     *    Set the value of this CIDR.
     *
     *     <p>This accepts strings in the a[.b[.c[.d]]][/netmask] format.
     *
      *    @param v The string representation of this network address.
     *    @exception SQLException If it is not in a valid cidr format.
     */
    public void setValue( String v )
    throws SQLException
    {
        int a = 0;
        int b = 0;
        int c = 0;
        int d = 0;
        int netmask = -1;

        if( v == null )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
        }

        PGtokenizer t = new PGtokenizer( v, '/' );

        int size = t.getSize();
        if( ( size != 1 ) && ( size != 2 ) )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
        }

        try
        {
            if( size == 2 )
            {
                // we have a netmask to read
                netmask = Integer.valueOf( t.getToken( 1 ) ).intValue();
                if( ( netmask < 0 ) || ( netmask > 32 ) )
                {
                    throw( new PSQLException(
                        GT.tr( "Conversion to type {0} failed: {1}.", new Object[]{ type, v } ),
                        PSQLState.DATA_TYPE_MISMATCH ) );
                }
            }

            // read the body a.b.c.d
            t = new PGtokenizer( t.getToken( 0 ), '.' );
            size = t.getSize();
            if( ( size < 1 ) || ( size > 4 ) )
            {
                throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                    new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
            }


            a = Integer.valueOf( t.getToken( 0 ) ).intValue();

            if( size >= 2 )
            {
                b = Integer.valueOf( t.getToken( 1 ) ).intValue();
            }

            if( size >= 3 )
            {
                c = Integer.valueOf( t.getToken( 2 ) ).intValue();
            }

            if( size >= 4 )
            {
                d = Integer.valueOf( t.getToken( 3 ) ).intValue();
            }
        }
        catch( NumberFormatException e )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v }), PSQLState.DATA_TYPE_MISMATCH, e ) );
        }

        if( ( a < 0 ) || ( a > 255 ) ||
            ( b < 0 ) || ( b > 255 ) ||
            ( c < 0 ) || ( c > 255 ) ||
            ( d < 0 ) || ( d > 255 ) )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
        }

        // If the netmask is not set in the parameter,
        // we will take a guess like PG does.
        //
        //    1.0.0.0 - 127.0.0.0        -    class A, netmask 8
        //    128.0.0.0 - 191.0.0.0    -     class B, netmask 16
        //     192.0.0.0 - 223.0.0.0    -    class C, netmask 24
        if( netmask == -1 )
        {
            // start with a safe default, we will try to trim
            // this down depending on the values of a,b,c & d.
            netmask = 32;
            if( a >= 1 || a <= 127 )
            {
                if( b == 0 && c == 0 && d == 0 )
                {
                    netmask = 8;
                }
                else if( c == 0 && d == 0 )
                {
                    netmask = 16;
                }
                else if( d == 0 )
                {
                    netmask = 24;
                }
            }
            else if( a >= 128 && a <= 191 )
            {
                if( c == 0 && d == 0 )
                {
                    netmask = 16;
                }
                else if( d == 0 )
                {
                    netmask = 24;
                }
            }
            else if( a >= 192 && a <= 223 )
            {
                if( d == 0 )
                {
                    netmask = 24;
                }
            }
        }

        // verify that there are no bits to the right of the netmask
        if( netmask < 32 )
        {
            int address = ( a << 24 ) | ( b << 16 ) | ( c << 8 ) | d;
            address <<= netmask;

            if( address != 0 )
            {
                // There are bits to the right of the netmask
                throw( new PSQLException(  GT.tr( "Conversion to type {0} failed: {1}.",
                    new Object[]{ type, v }), PSQLState.DATA_TYPE_MISMATCH ) );
            }
        }

        // Seems like it will generate a decent hash?
        this.hashValue = ((a ^ b) << 24) | ((b ^ c) << 8) | ((c ^ d) << 16) | (d ^ netmask);

        // ok, the parameter cleared all of out tests,
        // a.b.c.d/netmask should contain out new CIDR value.
        this.value = "" + a + "." + b + "." + c + "." + d + "/" + netmask;
    }

    /**
      *    Get the hash code for this network address.
     *
     *    @return The hash value for this object.
     */
    public int hashCode()
    {
        return( this.hashValue );
    }

    /**
     *    Compare two PGcidr objects for equality.
     *
     *    <p>This will return true if the parameter obj is of type PGcidr
     *    and represents the same network as this.
     *
     *    @param obj The object which we wish to compare.
     *    @return true if it represents the same network as this, false otherwise.
     */
    public boolean equals( Object obj )
    {
        if( obj instanceof PGcidr )
        {
            PGcidr cidr = (PGcidr)obj;
            if( this.getValue().equals( cidr.getValue() ) )
            {
                return( true );
            }
        }
        return( false );
    }

    /**
     *    This will make a duplicate of the current PGcidr object.
     *
     *    @return null on failure, or a new PGcidr object which
     *        represents the same network address as the invoking
     *        object.
     */
    public Object clone()
    {
        try
        {
            return( new PGcidr( this.getValue() ) );
        }
        catch( SQLException e )
        {
            return( null );
        }
    }
}
/*-------------------------------------------------------------------------
*
*    Copyright (C) 2005, PostgreSQL Global Development Group
*
*--------------------------------------------------------------------------
*/
package org.postgresql.net;

import java.io.Serializable;
import java.sql.SQLException;

import org.postgresql.util.GT;
import org.postgresql.util.PGobject;
import org.postgresql.util.PGtokenizer;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;

/**
 *    This represents org.postgresql's inet datatype, which is used
 *    to hold IPV4 network addresses and ip addresses.
 *
 *    <p>
 *    This class wraps the postgresql specific INET datatype.  It supports
 *    values in the following format.
 *    <p>
 *    a.b.c.d[/netmask]
 *
 *    @author Russell Francis < rfrancis@ev.net >
 */
public class PGinet extends PGobject implements Serializable, Cloneable
{
    private int hashValue;

    /**
      *    This constructor takes a string in the inet format
     *    a.b.c.d[/netmask] and creates a new PGinet to
     *    represent it.
     *
      *    @param s The string representation of the inet value.
     *    @exception SQLException If the string is invalid.
     */
    public PGinet( String s )
    throws SQLException
    {
        this();
        this.setValue( s );
    }

    /**
     *    A simple constructor.
     */
    public PGinet()
    {
        setType( "inet" );
    }

    /**
     *    This method sets the value of this PGinet object.
     *
      *    @param v A string representation of an inet address a.b.c.d[/netmask]
     *    @exception SQLException If the parameter is not a valid inet address.
     */
    public void setValue( String v )
    throws SQLException
    {
        if( v == null )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
        }

        PGtokenizer t = new PGtokenizer( v, '/' );

        int size = t.getSize();
        if( ( size != 1 ) && ( size != 2 ) )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
        }

        int a = 0;
        int b = 0;
        int c = 0;
        int d = 0;
        int netmask = 32;

        try
        {
            if( size == 2 )
            {
                netmask = Integer.valueOf( t.getToken( 1 ) ).intValue();
                if( ( netmask < 0 ) || ( netmask > 32 ) )
                {
                    throw( new PSQLException(
                        GT.tr( "Conversion to typ {0} failed: {1}.", new Object[]{ type, v } ),
                        PSQLState.DATA_TYPE_MISMATCH ) );
                }
            }

            t = new PGtokenizer( t.getToken( 0 ), '.' );
            if( t.getSize() != 4 )
            {
                throw( new PSQLException(
                    GT.tr( "Conversion to typ {0} failed: {1}.", new Object[]{ type, v } ),
                    PSQLState.DATA_TYPE_MISMATCH ) );
            }

            a = Integer.valueOf( t.getToken( 0 ) ).intValue();
            b = Integer.valueOf( t.getToken( 1 ) ).intValue();
            c = Integer.valueOf( t.getToken( 2 ) ).intValue();
            d = Integer.valueOf( t.getToken( 3 ) ).intValue();
        }
        catch( NumberFormatException e )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH, e ) );
        }

        // ensure that the values are within a valid range.
        if( ( a < 0 ) || ( a > 255 ) ||
            ( b < 0 ) || ( b > 255 ) ||
            ( c < 0 ) || ( c > 255 ) ||
            ( d < 0 ) || ( d > 255 ) )
        {
            throw( new PSQLException( GT.tr( "Conversion to type {0} failed: {1}.",
                new Object[]{ type, v } ), PSQLState.DATA_TYPE_MISMATCH ) );
        }

        this.hashValue = ((a ^ c) << 24) | ((b ^ d) << 16) | ((b ^ c) << 8) | (d ^ netmask);
        this.value = "" + a + "." + b + "." + c + "." + d + ((netmask == 32) ? "" : ("/" + netmask));
    }

    /**
     *    Get the hash code for this network address.
     *
      *    @return The hash value for this object.
     */
    public int hashCode()
    {
        return( this.hashValue );
    }

    /**
     *    Compare two PGinet's for equality.
     *
     *    @param obj The object which we wish to compare.
     *    @return true if it represents the same network or ip address
     *        as this PGinet, false otherwise.
     */
    public boolean equals( Object obj )
    {
        if( obj instanceof PGinet )
        {
            PGinet inet = (PGinet)obj;
            if( this.toString().equals( inet.toString() ) )
            {
                return( true );
            }
        }
        return( false );
    }

    /**
      *    Make a duplicate of this PGinet object.
     *
     *    @return null on failure, or a new PGinet address
     *        which is equal to this object.
     */
    public Object clone()
    {
        try
        {
            return( new PGinet( this.getValue() ) );
        }
        catch( SQLException e )
        {
            return( null );
        }
    }
}

В списке pgsql-jdbc по дате отправления:

Предыдущее
От: Kris Jurka
Дата:
Сообщение: Re: queries against CIDR fail against 8.0.3?
Следующее
От: andres@sayago.info
Дата:
Сообщение: Problems with alias in UPDATE over JDeveloper+ADF: I have the answer