Package org.postgresql.jdbc2

Source Code of org.postgresql.jdbc2.AbstractJdbc2Array$PgArrayList

/*-------------------------------------------------------------------------
*
* Copyright (c) 2004-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
*   $PostgreSQL: pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Array.java,v 1.23 2008/01/08 06:56:28 jurka Exp $
*
*-------------------------------------------------------------------------
*/
package org.postgresql.jdbc2;

import org.postgresql.core.*;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import org.postgresql.util.GT;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Map;
import java.util.Vector;

/**
* Array is used collect one column of query result data.
*
* <p>
* Read a field of type Array into either a natively-typed Java array object or
* a ResultSet. Accessor methods provide the ability to capture array slices.
*
* <p>
* Other than the constructor all methods are direct implementations of those
* specified for java.sql.Array. Please refer to the javadoc for java.sql.Array
* for detailed descriptions of the functionality and parameters of the methods
* of this class.
*
* @see ResultSet#getArray
*/
public abstract class AbstractJdbc2Array
{

    /**
     * Array list implementation specific for storing PG array elements.
     */
    private static class PgArrayList extends ArrayList
    {

        private static final long serialVersionUID = 2052783752654562677L;

        /**
         * How many dimensions.
         */
        int dimensionsCount = 1;

    }

    /**
     * A database connection.
     */
    private BaseConnection connection = null;

    /**
     * The OID of this field.
     */
    private int oid;

    /**
     * Field value as String.
     */
    private String fieldString = null;

    /**
     * Whether Object[] should be used instead primitive arrays. Object[] can
     * contain null elements. It should be set to <Code>true</Code> if
     * {@link BaseConnection#haveMinimumCompatibleVersion(String)} returns
     * <Code>true</Code> for argument "8.3".
     */
    private final boolean useObjects;

    /**
     * Are we connected to an 8.2 or higher server?  Only 8.2 or higher
     * supports null array elements.
     */
    private final boolean haveMinServer82;

    /**
     * Value of field as {@link PgArrayList}. Will be initialized only once
     * within {@link #buildArrayList()}.
     */
    private PgArrayList arrayList;

    /**
     * Create a new Array.
     *
     * @param connection a database connection
     * @param index 1-based index of the query field to load into this Array
     * @param field the Field descriptor for the field to load into this Array
     * @param result the ResultSet from which to get the data for this Array
     */
    public AbstractJdbc2Array(BaseConnection connection, int oid, String fieldString) throws SQLException {
        this.connection = connection;
        this.oid = oid;
        this.fieldString = fieldString;
        this.useObjects = connection.haveMinimumCompatibleVersion("8.3");
        this.haveMinServer82 = connection.haveMinimumServerVersion("8.2");
    }

    public Object getArray() throws SQLException
    {
        return getArrayImpl(1, 0, null);
    }

    public Object getArray(long index, int count) throws SQLException
    {
        return getArrayImpl(index, count, null);
    }

    public Object getArrayImpl(Map map) throws SQLException
    {
        return getArrayImpl(1, 0, map);
    }

    public Object getArrayImpl(long index, int count, Map map) throws SQLException
    {

        // for now maps aren't supported.
        if (map != null && !map.isEmpty())
        {
            throw org.postgresql.Driver.notImplemented(this.getClass(), "getArrayImpl(long,int,Map)");
        }

        // array index is out of range
        if (index < 1)
        {
            throw new PSQLException(GT.tr("The array index is out of range: {0}", new Long(index)), PSQLState.DATA_ERROR);
        }

        buildArrayList();

        if (count == 0)
            count = arrayList.size();

        // array index out of range
        if ((--index) + count > arrayList.size())
        {
            throw new PSQLException(GT.tr("The array index is out of range: {0}, number of elements: {1}.", new Object[] { new Long(index + count), new Long(arrayList.size()) }), PSQLState.DATA_ERROR);
        }

        return buildArray(arrayList, (int) index, count);
    }

    /**
     * Build {@link ArrayList} from field's string input. As a result
     * of this method {@link #arrayList} is build. Method can be called
     * many times in order to make sure that array list is ready to use, however
     * {@link #arrayList} will be set only once during first call.
     */
    private synchronized void buildArrayList()
    {
        if (arrayList != null)
            return;

        arrayList = new PgArrayList();

        if (fieldString != null)
        {

            char[] chars = fieldString.toCharArray();
            StringBuffer buffer = null;
            boolean insideString = false;
            boolean wasInsideString = false; // needed for checking if NULL
            // value occured
            Vector dims = new Vector(); // array dimension arrays
            PgArrayList curArray = arrayList; // currently processed array

            // Starting with 8.0 non-standard (beginning index
            // isn't 1) bounds the dimensions are returned in the
            // data formatted like so "[0:3]={0,1,2,3,4}".
            // Older versions simply do not return the bounds.
            //
            // Right now we ignore these bounds, but we could
            // consider allowing these index values to be used
            // even though the JDBC spec says 1 is the first
            // index. I'm not sure what a client would like
            // to see, so we just retain the old behavior.
            int startOffset = 0;
            {
                if (chars[0] == '[')
                {
                    while (chars[startOffset] != '=')
                    {
                        startOffset++;
                    }
                    startOffset++; // skip =
                }
            }

            for (int i = startOffset; i < chars.length; i++)
            {

                // escape character that we need to skip
                if (chars[i] == '\\')
                    i++;

                // subarray start
                else if (!insideString && chars[i] == '{')
                {
                    if (dims.size() == 0)
                    {
                        dims.add(arrayList);
                    }
                    else
                    {
                        PgArrayList a = new PgArrayList();
                        PgArrayList p = ((PgArrayList) dims.lastElement());
                        p.add(a);
                        dims.add(a);
                    }
                    curArray = (PgArrayList) dims.lastElement();

                    // number of dimensions
                    {
                        for (int t = i + 1; t < chars.length; t++) {
                            if (Character.isWhitespace(chars[t])) continue;
                            else if (chars[t] == '{') curArray.dimensionsCount++;
                            else break;
                        }
                    }

                    buffer = new StringBuffer();
                    continue;
                }

                // quoted element
                else if (chars[i] == '"')
                {
                    insideString = !insideString;
                    wasInsideString = true;
                    continue;
                }

                // white space
                else if (!insideString && Character.isWhitespace(chars[i]))
                {
                    continue;
                }

                // array end or element end
                else if ((!insideString && (chars[i] == ',' || chars[i] == '}')) || i == chars.length - 1)
                {

                    // when character that is a part of array element
                    if (chars[i] != '"' && chars[i] != '}' && chars[i] != ',' && buffer != null)
                    {
                        buffer.append(chars[i]);
                    }

                    String b = buffer == null ? null : buffer.toString();

                    // add element to current array
                    if (b != null && (b.length() > 0 || wasInsideString))
                    {
                        curArray.add(!wasInsideString && haveMinServer82 && b.equals("NULL") ? null : b);
                    }

                    wasInsideString = false;
                    buffer = new StringBuffer();

                    // when end of an array
                    if (chars[i] == '}')
                    {
                        dims.remove(dims.size() - 1);

                        // when multi-dimension
                        if (dims.size() > 0)
                        {
                            curArray = (PgArrayList) dims.lastElement();
                        }

                        buffer = null;
                    }

                    continue;
                }

                if (buffer != null)
                    buffer.append(chars[i]);
            }
        }
    }

    /**
     * Convert {@link ArrayList} to array.
     *
     * @param input list to be converted into array
     */
    private Object buildArray (PgArrayList input, int index, int count) throws SQLException
    {

        if (count < 0)
            count = input.size();

        // array to be returned
        Object ret = null;

        // how many dimensions
        int dims = input.dimensionsCount;

        // dimensions length array (to be used with java.lang.reflect.Array.newInstance(Class<?>, int[]))
        int[] dimsLength = dims > 1 ? new int[dims] : null;
        if (dims > 1) {
            for (int i = 0; i < dims; i++) {
                dimsLength[i] = (i == 0 ? count : 0);
            }
        }

        // array elements counter
        int length = 0;

        // array elements type
        final int type = connection.getSQLType(connection.getPGArrayElement(oid));

        if (type == Types.BIT)
        {
            boolean[] pa = null; // primitive array
            Object[] oa = null; // objects array

            if (dims > 1 || useObjects)
            {
ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(useObjects ? Boolean.class : boolean.class, dimsLength) : new Boolean[count]);
            }
            else
            {
                ret = pa = new boolean[count];
            }

            // add elements
            for (; count > 0; count--)
            {
                Object o = input.get(index++);

                if (dims > 1 || useObjects)
                {
                    oa[length++] = o == null ? null : (dims > 1 ? buildArray((PgArrayList) o, 0, -1) : new Boolean(AbstractJdbc2ResultSet.toBoolean((String) o)));
                }
                else
                {
                    pa[length++] = o == null ? false : AbstractJdbc2ResultSet.toBoolean((String) o);
                }
            }
        }

        else if (type == Types.SMALLINT || type == Types.INTEGER)
        {
            int[] pa = null;
            Object[] oa = null;

            if (dims > 1 || useObjects)
            {
ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(useObjects ? Integer.class : int.class, dimsLength) : new Integer[count]);
            }
            else
            {
                ret = pa = new int[count];
            }

            for (; count > 0; count--)
            {
                Object o = input.get(index++);

                if (dims > 1 || useObjects)
                {
                    oa[length++] = o == null ? null : (dims > 1 ? buildArray((PgArrayList) o, 0, -1) : new Integer(AbstractJdbc2ResultSet.toInt((String) o)));
                }
                else
                {
                    pa[length++] = o == null ? 0 : AbstractJdbc2ResultSet.toInt((String) o);
                }
            }
        }

        else if (type == Types.BIGINT)
        {
            long[] pa = null;
            Object[] oa = null;

            if (dims > 1 || useObjects)
            {
ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(useObjects ? Long.class : long.class, dimsLength) : new Long[count]);
            }

            else
            {
                ret = pa = new long[count];
            }

            for (; count > 0; count--)
            {
                Object o = input.get(index++);

                if (dims > 1 || useObjects)
                {
                    oa[length++] = o == null ? null : (dims > 1 ? buildArray((PgArrayList) o, 0, -1) : new Long(AbstractJdbc2ResultSet.toLong((String) o)));
                }
                else
                {
                    pa[length++] = o == null ? 0l : AbstractJdbc2ResultSet.toLong((String) o);
                }
            }
        }

        else if (type == Types.NUMERIC)
        {
            Object[] oa = null;
            ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(BigDecimal.class, dimsLength) : new BigDecimal[count]);

            for (; count > 0; count--)
            {
                Object v = input.get(index++);
                oa[length++] = dims > 1 && v != null ? buildArray((PgArrayList) v, 0, -1) : (v == null ? null : AbstractJdbc2ResultSet.toBigDecimal((String) v, -1));
            }
        }

        else if (type == Types.REAL)
        {
            float[] pa = null;
            Object[] oa = null;

            if (dims > 1 || useObjects)
            {
ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(useObjects ? Float.class : float.class, dimsLength) : new Float[count]);
            }
            else
            {
                ret = pa = new float[count];
            }

            for (; count > 0; count--)
            {
                Object o = input.get(index++);

                if (dims > 1 || useObjects)
                {
                    oa[length++] = o == null ? null : (dims > 1 ? buildArray((PgArrayList) o, 0, -1) : new Float(AbstractJdbc2ResultSet.toFloat((String) o)));
                }
                else
                {
                    pa[length++] = o == null ? 0f : AbstractJdbc2ResultSet.toFloat((String) o);
                }
            }
        }

        else if (type == Types.DOUBLE)
        {
            double[] pa = null;
            Object[] oa = null;

            if (dims > 1 || useObjects)
            {
ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(useObjects ? Double.class : double.class, dimsLength) : new Double[count]);
            }
            else
            {
                ret = pa = new double[count];
            }

            for (; count > 0; count--)
            {
                Object o = input.get(index++);

                if (dims > 1 || useObjects)
                {
                    oa[length++] = o == null ? null : (dims > 1 ? buildArray((PgArrayList) o, 0, -1) : new Double(AbstractJdbc2ResultSet.toDouble((String) o)));
                }
                else
                {
                    pa[length++] = o == null ? 0d : AbstractJdbc2ResultSet.toDouble((String) o);
                }
            }
        }

        else if (type == Types.CHAR || type == Types.VARCHAR)
        {
            Object[] oa = null;
            ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(String.class, dimsLength) : new String[count]);

            for (; count > 0; count--)
            {
                Object v = input.get(index++);
                oa[length++] = dims > 1 && v != null ? buildArray((PgArrayList) v, 0, -1) : v;
            }
        }

        else if (type == Types.DATE)
        {
            Object[] oa = null;
            ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(java.sql.Date.class, dimsLength) : new java.sql.Date[count]);

            for (; count > 0; count--)
            {
                Object v = input.get(index++);
                oa[length++] = dims > 1 && v != null ? buildArray((PgArrayList) v, 0, -1) : (v == null ? null : connection.getTimestampUtils().toDate(null, (String) v));
            }
        }

        else if (type == Types.TIME)
        {
            Object[] oa = null;
            ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(java.sql.Time.class, dimsLength) : new java.sql.Time[count]);

            for (; count > 0; count--)
            {
                Object v = input.get(index++);
                oa[length++] = dims > 1 && v != null ? buildArray((PgArrayList) v, 0, -1) : (v == null ? null : connection.getTimestampUtils().toTime(null, (String) v));
            }
        }

        else if (type == Types.TIMESTAMP)
        {
            Object[] oa = null;
            ret = oa = (dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(java.sql.Timestamp.class, dimsLength) : new java.sql.Timestamp[count]);

            for (; count > 0; count--)
            {
                Object v = input.get(index++);
                oa[length++] = dims > 1 && v != null ? buildArray((PgArrayList) v, 0, -1) : (v == null ? null : connection.getTimestampUtils().toTimestamp(null, (String) v));
            }
        }

        // other datatypes not currently supported
        else
        {
            if (connection.getLogger().logDebug())
                connection.getLogger().debug("getArrayImpl(long,int,Map) with " + getBaseTypeName());

            throw org.postgresql.Driver.notImplemented(this.getClass(), "getArrayImpl(long,int,Map)");
        }

        return ret;
    }

    public int getBaseType() throws SQLException
    {
        return connection.getSQLType(getBaseTypeName());
    }

    public String getBaseTypeName() throws SQLException
    {
        buildArrayList();
        return connection.getPGType(connection.getPGArrayElement(oid));
    }

    public java.sql.ResultSet getResultSet() throws SQLException
    {
        return getResultSetImpl(1, 0, null);
    }

    public java.sql.ResultSet getResultSet(long index, int count) throws SQLException
    {
        return getResultSetImpl(index, count, null);
    }

    public java.sql.ResultSet getResultSetImpl(Map map) throws SQLException
    {
        return getResultSetImpl(1, 0, map);
    }

    public ResultSet getResultSetImpl(long index, int count, Map map) throws SQLException
    {

        // for now maps aren't supported.
        if (map != null && !map.isEmpty())
        {
            throw org.postgresql.Driver.notImplemented(this.getClass(), "getResultSetImpl(long,int,Map)");
        }

        // array index is out of range
        if (index < 1)
        {
            throw new PSQLException(GT.tr("The array index is out of range: {0}", new Long(index)), PSQLState.DATA_ERROR);
        }

        buildArrayList();

        if (count == 0)
        {
            count = arrayList.size();
        }

        // array index out of range
        if ((--index) + count > arrayList.size())
        {
            throw new PSQLException(GT.tr("The array index is out of range: {0}, number of elements: {1}.", new Object[] { new Long(index + count), new Long(arrayList.size()) }), PSQLState.DATA_ERROR);
        }

        Vector rows = new Vector();

        Field[] fields = new Field[2];

        // one dimensional array
        if (arrayList.dimensionsCount <= 1)
        {
            // array element type
            final int baseOid = connection.getPGArrayElement(oid);
            fields[0] = new Field("INDEX", Oid.INT4);
            fields[1] = new Field("VALUE", baseOid);

            for (int i = 0; i < count; i++)
            {
                int offset = (int)index + i;
                byte[][] t = new byte[2][0];
                String v = (String) arrayList.get(offset);
                t[0] = connection.encodeString(Integer.toString(offset + 1));
                t[1] = v == null ? null : connection.encodeString(v);
                rows.add(t);
            }
        }

        // when multi-dimensional
        else
        {
            fields[0] = new Field("INDEX", Oid.INT4);
            fields[1] = new Field("VALUE", oid);
            for (int i = 0; i < count; i++)
            {
                int offset = (int)index + i;
                byte[][] t = new byte[2][0];
                Object v = arrayList.get(offset);

                t[0] = connection.encodeString(Integer.toString(offset + 1));
                t[1] = v == null ? null : connection.encodeString(toString((PgArrayList) v));
                rows.add(t);
            }
        }

        BaseStatement stat = (BaseStatement) connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        return (ResultSet) stat.createDriverResultSet(fields, rows);
    }

    public String toString()
    {
        return fieldString;
    }

    /**
     * Convert array list to PG String representation (e.g. {0,1,2}).
     */
    private String toString(PgArrayList list) throws SQLException
    {
        StringBuffer b = new StringBuffer().append('{');

        for (int i = 0; i < list.size(); i++)
        {
            Object v = list.get(i);

            if (i > 0)
                b.append(',');

            if (v == null)
                b.append("NULL");

            else if (v instanceof PgArrayList)
                b.append(toString((PgArrayList) v));

            else
                escapeArrayElement(b, (String)v);
        }

        b.append('}');

        return b.toString();
    }

    public static void escapeArrayElement(StringBuffer b, String s)
    {
        b.append('"');
        for (int j = 0; j < s.length(); j++) {
            char c = s.charAt(j);
            if (c == '"' || c == '\\') {
                b.append('\\');
            }

            b.append(c);
        }
        b.append('"');
    }

}
TOP

Related Classes of org.postgresql.jdbc2.AbstractJdbc2Array$PgArrayList

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.