Package com.foundationdb.sql.server

Source Code of com.foundationdb.sql.server.ServerJavaValues$CachedCast

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.foundationdb.sql.server;

import com.foundationdb.server.error.NoSuchCastException;
import com.foundationdb.server.types.TCast;
import com.foundationdb.server.types.TClass;
import com.foundationdb.server.types.TExecutionContext;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.FormatOptions;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.server.types.value.Value;
import com.foundationdb.server.types.value.ValueSource;
import com.foundationdb.server.types.value.ValueSources;
import com.foundationdb.util.AkibanAppender;
import com.foundationdb.util.WrappingByteSource;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.RowId;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;
import java.util.Collections;

/** Make something like an array of typed values (for instance, a
* <code>Row</code> or a <code>QueryContext</code>) accessible using
* standard Java types, includings ones from the <code>java.sql</code>
* package.
*
* API like <code>ResultSet</code> or <code>PreparedStatement</code>.
*/
public abstract class ServerJavaValues
{
    public static final int RETURN_VALUE_INDEX = -1;

    protected abstract int size();
    protected abstract ServerQueryContext getContext();
    protected abstract ValueSource getValue(int index);
    protected abstract TInstance getType(int index);
    protected abstract void setValue(int index, ValueSource source);
    protected abstract ResultSet toResultSet(int index, Object resultSet);

    private boolean wasNull;
    private CachedCast[] cachedCasts;

    protected ValueSource value(int index) {
        ValueSource value = getValue(index);
        wasNull = value.isNull();
        return value;
    }

    protected TypesTranslator getTypesTranslator() {
        return getContext().getTypesTranslator();
    }

    protected static class CachedCast {
        TClass targetClass;
        TCast tcast;
        TExecutionContext tcontext;
        Value target;

        protected CachedCast(TInstance sourceInstance, TClass targetClass,
                             ServerQueryContext context) {
            this.targetClass = targetClass;
            TInstance targetInstance = targetClass.instance(sourceInstance == null || sourceInstance.nullability());
            tcast = context.getServer().typesRegistryService().getCastsResolver()
                .cast(sourceInstance, targetInstance);
            if (tcast == null)
                throw new NoSuchCastException(sourceInstance, targetInstance);
            tcontext = new TExecutionContext(Collections.singletonList(sourceInstance),
                                             targetInstance,
                                             context);
            target = new Value(targetInstance);
        }

        protected boolean matches(TClass required) {
            return required.equals(targetClass);
        }

        protected ValueSource apply(ValueSource value) {
            tcast.evaluate(tcontext, value, target);
            return target;
        }
    }

    /** Cast as necessary to <code>required</code>.
     * A cache is maintained for each index with the last class, on
     * the assumption the caller will be applying the same
     * <code>getXxx</code> / <code>setXxx</code> to the same field each time.
     */
    protected ValueSource cachedCast(int index, ValueSource value, int jdbcType) {
        return cachedCast(index, value, getType(index), jdbcType);
    }

    protected ValueSource cachedCast(int index, ValueSource source, TInstance sourceType, int jdbcType) {
        if (jdbcType == getTypesTranslator().jdbcType(sourceType))
            return source;
        return cachedCast(index, source, sourceType,
                          getTypesTranslator().typeClassForJDBCType(jdbcType));
    }

    protected ValueSource cachedCast(int index, ValueSource value, TClass required) {
        return cachedCast(index, value, getType(index), required);
    }

    protected ValueSource cachedCast(int index, ValueSource source, TInstance sourceType, TClass required) {
        if (required.equals(sourceType.typeClass()))
            return source;      // Already of the required class.
        // Leave room for return value (index does not matter -- only used here).
        if (cachedCasts == null)
            cachedCasts = new CachedCast[size() + 1];
        if (index == RETURN_VALUE_INDEX)
            index = cachedCasts.length - 1;
        CachedCast cast = cachedCasts[index];
        if ((cast == null) || !cast.matches(required)) {
            cast = new CachedCast(sourceType, required, getContext());
            cachedCasts[index] = cast;
        }
        return cast.apply(source);
    }

    protected TInstance jdbcInstance(int jdbcType) {
        return getTypesTranslator().typeClassForJDBCType(jdbcType).instance(true);
    }

    protected void setValue(int index, Object value, TInstance sourceType) {
        TInstance targetType = this.getType(index);
        if (sourceType == null) {
            sourceType = targetType;
        }
        ValueSource source = ValueSources.valuefromObject(value, sourceType);
        if (targetType != null)
            source = cachedCast(index, source, sourceType, targetType.typeClass());
        setValue(index, source);
    }

    public boolean wasNull() {
        return wasNull;
    }

    public String getString(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else
            return cachedCast(index, value, Types.VARCHAR).getString();
    }

    public String getNString(int index) {
        throw new UnsupportedOperationException();
    }

    public boolean getBoolean(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return false;
        else
            return cachedCast(index, value, Types.BOOLEAN).getBoolean();
    }

    public byte getByte(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return 0;
        else
            return (byte)getTypesTranslator()
                .getIntegerValue(cachedCast(index, value, Types.TINYINT));
    }

    public short getShort(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return 0;
        else
            return (short)getTypesTranslator()
                .getIntegerValue(cachedCast(index, value, Types.SMALLINT));
    }

    public int getInt(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return 0;
        else
            return (int)getTypesTranslator()
                .getIntegerValue(cachedCast(index, value, Types.INTEGER));
    }

    public long getLong(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return 0;
        else
            return getTypesTranslator()
                .getIntegerValue(cachedCast(index, value, Types.BIGINT));
    }

    public float getFloat(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return 0.0f;
        else
            return cachedCast(index, value, Types.FLOAT).getFloat();
    }

    public double getDouble(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return 0.0;
        else
            return cachedCast(index, value, Types.DOUBLE).getDouble();
    }

    public BigDecimal getBigDecimal(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else
            return getTypesTranslator().getDecimalValue(cachedCast(index, value, Types.DECIMAL));
    }

    public byte[] getBytes(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else
            return cachedCast(index, value, Types.VARBINARY).getBytes();
    }

    public Date getDate(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else
            return new Date(getTypesTranslator().getTimestampMillisValue(value));
    }

    public Time getTime(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else {
            return new Time(getTypesTranslator().getTimestampMillisValue(value));
        }
    }

    public Timestamp getTimestamp(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else {
            Timestamp result = new Timestamp(getTypesTranslator().getTimestampMillisValue(value));
            result.setNanos(getTypesTranslator().getTimestampNanosValue(value));
            return result;
        }
    }

    public Date getDate(int index, Calendar cal) {
        return getDate(index);
    }

    public Time getTime(int index, Calendar cal) {
        return getTime(index);
    }

    public Timestamp getTimestamp(int index, Calendar cal) {
        return getTimestamp(index);
    }

    public ResultSet getResultSet(int index) {
        ValueSource value = value(index);
        if (wasNull)
            return null;
        else
            return toResultSet(index, value.getObject());
    }

    public Object getObject(int index) {
        return getObject(index, getTypesTranslator().jdbcClass(getType(index)));
    }

    public Object getObject(int index, Class<?> type) {
        if (type == String.class)
            return getString(index);
        else if (type == BigDecimal.class)
            return getBigDecimal(index);
        else if ((type == Boolean.class) || (type == Boolean.TYPE)) {
            boolean value = getBoolean(index);
            return wasNull() ? null : Boolean.valueOf(value);
        }
        else if ((type == Byte.class) || (type == Byte.TYPE)) {
            byte value = getByte(index);
            return wasNull() ? null : Byte.valueOf(value);
        }
        else if ((type == Short.class) || (type == Short.TYPE)) {
            short value = getShort(index);
            return wasNull() ? null : Short.valueOf(value);
        }
        else if ((type == Integer.class) || (type == Integer.TYPE)) {
            int value = getInt(index);
            return wasNull() ? null : Integer.valueOf(value);
        }
        else if ((type == Long.class) || (type == Long.TYPE)) {
            long value = getLong(index);
            return wasNull() ? null : Long.valueOf(value);
        }
        else if ((type == Float.class) || (type == Float.TYPE)) {
            float value = getFloat(index);
            return wasNull() ? null : Float.valueOf(value);
        }
        else if ((type == Double.class) || (type == Double.TYPE)) {
            double value = getDouble(index);
            return wasNull() ? null : Double.valueOf(value);
        }
        else if (type == byte[].class)
            return getBytes(index);
        else if (type == Date.class)
            return getDate(index);
        else if (type == Time.class)
            return getTime(index);
        else if (type == Timestamp.class)
            return getTimestamp(index);
        else if (type == ResultSet.class)
            return getResultSet(index);
        else if (type == Array.class)
            return getArray(index);
        else if (type == Blob.class)
            return getBlob(index);
        else if (type == Clob.class)
            return getClob(index);
        else if (type == Ref.class)
            return getRef(index);
        else if (type == URL.class)
            return getURL(index);
        else if (type == RowId.class)
            return getRowId(index);
        else if (type == NClob.class)
            return getNClob(index);
        else if (type == SQLXML.class)
            return getSQLXML(index);
        else
            throw new UnsupportedOperationException("Unsupported type " + type);
    }

    public InputStream getAsciiStream(int index) {
        throw new UnsupportedOperationException();
    }

    public InputStream getUnicodeStream(int index) {
        throw new UnsupportedOperationException();
    }

    public Reader getCharacterStream(int index) {
        throw new UnsupportedOperationException();
    }

    public Reader getNCharacterStream(int index) {
        throw new UnsupportedOperationException();
    }

    public InputStream getBinaryStream(int index) {
        throw new UnsupportedOperationException();
    }

    public Ref getRef(int index) {
        throw new UnsupportedOperationException();
    }

    public Blob getBlob(int index) {
        throw new UnsupportedOperationException();
    }

    public Clob getClob(int index) {
        throw new UnsupportedOperationException();
    }

    public NClob getNClob(int index) {
        throw new UnsupportedOperationException();
    }

    public SQLXML getSQLXML(int index) {
        throw new UnsupportedOperationException();
    }

    public RowId getRowId(int index) {
        throw new UnsupportedOperationException();
    }

    public Array getArray(int index) {
        throw new UnsupportedOperationException();
    }

    public URL getURL(int index) {
        throw new UnsupportedOperationException();
    }

    public void setNull(int index) {
        setValue(index, (Object)null, jdbcInstance(Types.INTEGER));
    }

    public void setBoolean(int index, boolean x) {
        setValue(index, x, jdbcInstance(Types.BOOLEAN));
    }

    public void setByte(int index, byte x) {
        setValue(index, (int)x, jdbcInstance(Types.TINYINT));
    }

    public void setShort(int index, short x) {
        setValue(index, (int)x, jdbcInstance(Types.SMALLINT));
    }

    public void setInt(int index, int x) {
        setValue(index, x, jdbcInstance(Types.INTEGER));
    }

    public void setLong(int index, long x) {
        setValue(index, x, jdbcInstance(Types.BIGINT));
    }

    public void setFloat(int index, float x) {
        setValue(index, x, jdbcInstance(Types.FLOAT));
    }

    public void setDouble(int index, double x) {
        setValue(index, x, jdbcInstance(Types.DOUBLE));
    }

    public void setBigDecimal(int index, BigDecimal x) {
        setValue(index, x, jdbcInstance(Types.DECIMAL));
    }

    public void setString(int index, String x) {
        setValue(index, x, jdbcInstance(Types.VARCHAR));
    }

    public void setBytes(int index, byte x[]) {
        setValue(index, new WrappingByteSource(x), jdbcInstance(Types.VARBINARY));
    }

    public void setDate(int index, Date x) {
        Value value = new Value(jdbcInstance(Types.DATE));
        getTypesTranslator().setTimestampMillisValue(value, x.getTime(), 0);
        setValue(index, value);
    }

    public void setTime(int index, Time x) {
        Value value = new Value(jdbcInstance(Types.TIME));
        getTypesTranslator().setTimestampMillisValue(value, x.getTime(), 0);
        setValue(index, value);
    }

    public void setTimestamp(int index, Timestamp x) {
        Value value = new Value(jdbcInstance(Types.TIMESTAMP));
        getTypesTranslator().setTimestampMillisValue(value, x.getTime(), x.getNanos());
        setValue(index, value);
    }

    public void setDate(int index, Date x, Calendar cal) {
        setDate(index, x);
    }

    public void setTime(int index, Time x, Calendar cal) {
        setTime(index, x);
    }

    public void setTimestamp(int index, Timestamp x, Calendar cal) {
        setTimestamp(index, x);
    }

    public void setObject(int index, Object x) {
        if (x == null)
            setNull(index);
        else if (x instanceof String)
            setString(index, (String)x);
        else if (x instanceof BigDecimal)
            setBigDecimal(index, (BigDecimal)x);
        else if (x instanceof Boolean)
            setBoolean(index, (Boolean)x);
        else if (x instanceof Byte)
            setByte(index, (Byte)x);
        else if (x instanceof Short)
            setShort(index, (Short)x);
        else if (x instanceof Integer)
            setInt(index, (Integer)x);
        else if (x instanceof Long)
            setLong(index, (Long)x);
        else if (x instanceof Float)
            setFloat(index, (Float)x);
        else if (x instanceof Double)
            setDouble(index, (Double)x);
        else if (x instanceof byte[])
            setBytes(index, (byte[])x);
        else if (x instanceof Date)
            setDate(index, (Date)x);
        else if (x instanceof Time)
            setTime(index, (Time)x);
        else if (x instanceof Timestamp)
            setTimestamp(index, (Timestamp)x);
        else if (x instanceof Array)
            setArray(index, (Array)x);
        else if (x instanceof Blob)
            setBlob(index, (Blob)x);
        else if (x instanceof Clob)
            setClob(index, (Clob)x);
        else if (x instanceof Ref)
            setRef(index, (Ref)x);
        else if (x instanceof URL)
            setURL(index, (URL)x);
        else if (x instanceof RowId)
            setRowId(index, (RowId)x);
        else if (x instanceof NClob)
            setNClob(index, (NClob)x);
        else if (x instanceof SQLXML)
            setSQLXML(index, (SQLXML)x);
        else if (x instanceof BigInteger)
            setLong(index, ((BigInteger)x).longValue());
        else
            throw new UnsupportedOperationException("Unsupported type " + x);
    }

    public void setNString(int index, String value) {
        setString(index, value);
    }

    public void setAsciiStream(int index, InputStream x, int length) throws IOException {
        String value;
        byte[] b = new byte[length];
        int l = x.read(b);
        value = new String(b, 0, l, "ASCII");
        setValue(index, value, jdbcInstance(Types.VARCHAR));
    }

    public void setUnicodeStream(int index, InputStream x, int length) throws IOException {
        String value;
        byte[] b = new byte[length];
        int l = x.read(b);
        value = new String(b, 0, l, "UTF-8");
        setValue(index, value, jdbcInstance(Types.VARCHAR));
    }

    public void setBinaryStream(int index, InputStream x, int length) throws IOException {
        WrappingByteSource value;
        byte[] b = new byte[length];
        int l = x.read(b);
        value = new WrappingByteSource().wrap(b, 0, l);
        setValue(index, value, jdbcInstance(Types.VARBINARY));
    }

    public void setCharacterStream(int index, Reader reader, int length) throws IOException {
        String value;
        char[] c = new char[length];
        int l = reader.read(c);
        value = new String(c, 0, l);
        setValue(index, value, jdbcInstance(Types.VARCHAR));
    }

    public void setNCharacterStream(int index, Reader value, long length) throws IOException {
        setCharacterStream(index, value, length);
    }

    public void setAsciiStream(int index, InputStream x, long length) throws IOException {
        setAsciiStream(index, x, (int)length);
    }

    public void setBinaryStream(int index, InputStream x, long length) throws IOException {
        setBinaryStream(index, x, (int)length);
    }

    public void setCharacterStream(int index, Reader reader, long length) throws IOException {
        setCharacterStream(index, reader, (int)length);
    }

    public void setAsciiStream(int index, InputStream x) throws IOException {
        String value;
        ByteArrayOutputStream ostr = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        while (true) {
            int len = x.read(buf);
            if (len < 0) break;
            ostr.write(buf, 0, len);
        }
        value = new String(ostr.toByteArray(), "ASCII");
        setValue(index, value, jdbcInstance(Types.VARCHAR));
    }

    public void setBinaryStream(int index, InputStream x) throws IOException {
        WrappingByteSource value;
        ByteArrayOutputStream ostr = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        while (true) {
            int len = x.read(buf);
            if (len < 0) break;
            ostr.write(buf, 0, len);
        }
        value = new WrappingByteSource(ostr.toByteArray());
        setValue(index, value, jdbcInstance(Types.VARBINARY));
    }

    public void setCharacterStream(int index, Reader reader) throws IOException {
        String value;
        StringWriter ostr = new StringWriter();
        char[] buf = new char[1024];
        while (true) {
            int len = reader.read(buf);
            if (len < 0) break;
            ostr.write(buf, 0, len);
        }
        value = ostr.toString();
        setValue(index, value, jdbcInstance(Types.VARCHAR));
    }

    public void setNCharacterStream(int index, Reader value) throws IOException {
        setCharacterStream(index, value);
    }

    public void setRef(int index, Ref x) {
        throw new UnsupportedOperationException();
    }

    public void setBlob(int index, Blob x) {
        throw new UnsupportedOperationException();
    }

    public void setClob(int index, Clob x) {
        throw new UnsupportedOperationException();
    }

    public void setClob(int index, Reader reader) {
        throw new UnsupportedOperationException();
    }

    public void setBlob(int index, InputStream inputStream) {
        throw new UnsupportedOperationException();
    }

    public void setNClob(int index, Reader reader) {
        throw new UnsupportedOperationException();
    }

    public void setNClob(int index, NClob value) {
        throw new UnsupportedOperationException();
    }

    public void setClob(int index, Reader reader, long length) {
        throw new UnsupportedOperationException();
    }

    public void setBlob(int index, InputStream inputStream, long length) {
        throw new UnsupportedOperationException();
    }

    public void setNClob(int index, Reader reader, long length) {
        throw new UnsupportedOperationException();
    }

    public void setSQLXML(int index, SQLXML xmlObject) {
        throw new UnsupportedOperationException();
    }

    public void setURL(int index, URL x) {
        throw new UnsupportedOperationException();
    }

    public void setRowId(int index, RowId x) {
        throw new UnsupportedOperationException();
    }

    public void setArray(int index, Array x) {
        throw new UnsupportedOperationException();
    }

    public void formatAsJson(int index, AkibanAppender appender, FormatOptions options) {
        ValueSource value = getValue(index);
        value.getType().formatAsJson(value, appender, options);
    }
}
TOP

Related Classes of com.foundationdb.sql.server.ServerJavaValues$CachedCast

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.