Package com.foundationdb.sql.server

Source Code of com.foundationdb.sql.server.ServerValueDecoder

/**
* 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.qp.operator.QueryBindings;
import com.foundationdb.qp.operator.QueryContext;
import com.foundationdb.server.error.AkibanInternalException;
import com.foundationdb.server.error.UnknownDataTypeException;
import com.foundationdb.server.error.UnsupportedCharsetException;
import com.foundationdb.server.types.TCast;
import com.foundationdb.server.types.TExecutionContext;
import com.foundationdb.server.types.TInstance;
import com.foundationdb.server.types.aksql.aktypes.AkBool;
import com.foundationdb.server.types.aksql.aktypes.AkGUID;
import com.foundationdb.server.types.common.types.TBinary;
import com.foundationdb.server.types.common.types.TypesTranslator;
import com.foundationdb.server.types.mcompat.mtypes.MApproximateNumber;
import com.foundationdb.server.types.mcompat.mtypes.MBinary;
import com.foundationdb.server.types.mcompat.mtypes.MDateAndTime;
import com.foundationdb.server.types.mcompat.mtypes.MNumeric;
import com.foundationdb.server.types.mcompat.mtypes.MString;
import com.foundationdb.server.types.service.TypesRegistryService;
import com.foundationdb.server.types.value.Value;
import com.foundationdb.server.types.value.ValueSource;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import java.math.BigDecimal;
import java.sql.Types;
import java.util.Collections;
import java.io.*;

/** Decode values from external representation into query bindings. */
public class ServerValueDecoder
{
    private final TypesTranslator typesTranslator;
    private final String encoding;

    public ServerValueDecoder(TypesTranslator typesTranslator, String encoding) {
        this.typesTranslator = typesTranslator;
        this.encoding = encoding;
    }

    /** Decode the given value into a the given bindings at the given position.
     */
    public void decodeValue(byte[] encoded, ServerType type, boolean binary,
                            QueryBindings bindings, int index,
                            QueryContext queryContext, TypesRegistryService typesRegistryService) {
      
        TInstance targetType = type != null ? type.getType() : null;
        if (targetType == null && encoded != null) {
            throw new UnknownDataTypeException(null);
        }
        ValueSource source;
        if (encoded == null) {
            Value value = new Value(targetType);
            value.putNull();
            bindings.setValue(index, value);
            return;
        }
        else if (!binary) {
            try {
                source = new Value(MString.varchar(), new String(encoded, encoding));
            }
            catch (UnsupportedEncodingException ex) {
                throw new UnsupportedCharsetException(encoding);
            }
        }
        else {
            try {
                switch (type.getBinaryEncoding()) {
                case BINARY_OCTAL_TEXT:
                    source = new Value(MBinary.VARBINARY.instance(false), encoded);
                    break;
                case INT_8:
                case INT_16:
                case INT_32:
                case INT_64: // Types.BIGINT
                    // Go by the length sent rather than the implied type.
                    source = decodeIntegerType(encoded);
                    break;
                case FLOAT_32:

                    source = new Value(MApproximateNumber.FLOAT.instance(false), getDataStream(encoded).readFloat());
                    break;
                case FLOAT_64:
                    source = new Value(MApproximateNumber.DOUBLE.instance(false), getDataStream(encoded).readDouble());
                    break;
                case BOOLEAN_C:
                    source = new Value(AkBool.INSTANCE.instance(false), encoded[0] != 0);
                    break;
                case TIMESTAMP_INT64_MICROS_2000_NOTZ: // Types.TIMESTAMP
                    source = decodeTimestampInt64Micros2000NoTZ(encoded);
                    break;
                case UUID:
                    Value value = new Value(AkGUID.INSTANCE.instance(false));
                    value.putObject(AkGUID.bytesToUUID(encoded, 0));
                    source = value;
                    break;
                // Note: these types had previous implementations, but I couldn't exercise them in tests to verify
                // either with jdbc or pg8000. If you run into them, try looking at the log for this file, it most
                // likely has a correct starting point
                case STRING_BYTES:
                case TIMESTAMP_FLOAT64_SECS_2000_NOTZ: // Types.TIMESTAMP
                case DAYS_2000: // DATE
                case TIME_FLOAT64_SECS_NOTZ: // TIME
                case TIME_INT64_MICROS_NOTZ: // TIME
                case DECIMAL_PG_NUMERIC_VAR:
                default:
                    throw new UnknownDataTypeException(type.toString());
                }
            }
            catch (UnsupportedEncodingException ex) {
                throw new UnsupportedCharsetException(encoding);
            }
            catch (IOException ex) {
                throw new AkibanInternalException("IO error reading from byte array", ex);
            }
        }
        TCast cast = typesRegistryService.getCastsResolver().cast(source.getType(), targetType);
        TExecutionContext context =
                new TExecutionContext(Collections.singletonList(source.getType()),
                        targetType,
                        queryContext);
        Value target = new Value(targetType);
        cast.evaluate(context, source, target);
        bindings.setValue(index, target);
    }

    private ValueSource decodeTimestampInt64Micros2000NoTZ(byte[] encoded) throws IOException {
        long micros = getDataStream(encoded).readLong();
        long secs = micros / 1000000;
        long milliseconds = seconds2000NoTZ(secs);
        int nanos = (int) (micros - secs * 1000000) * 1000;
        Value source = new Value(MDateAndTime.TIMESTAMP.instance(false));
        typesTranslator.setTimestampMillisValue(source, milliseconds, nanos);
        return source;
    }

    public ValueSource decodeIntegerType(byte[] encoded) throws IOException {
        switch (encoded.length) {
        case 1:
            return new Value(MNumeric.TINYINT.instance(false), getDataStream(encoded).read());
        case 2:
            return new Value(MNumeric.SMALLINT.instance(false), getDataStream(encoded).readShort());
        case 4:
            return new Value(MNumeric.INT.instance(false), getDataStream(encoded).readInt());
        case 8:
            return new Value(MNumeric.BIGINT.instance(false), getDataStream(encoded).readLong());
        default:
            throw new AkibanInternalException("Not an integer size: " + encoded);
        }
    }

    private static DataInputStream getDataStream(byte[] bytes) {
        return new DataInputStream(new ByteArrayInputStream(bytes));
    }

    private static long seconds2000NoTZ(long secs) {
        long millis = (secs + 946684800) * 1000; // 2000-01-01 00:00:00-UTC.
        DateTimeZone dtz = DateTimeZone.getDefault();
        millis -= dtz.getOffset(millis);
        return millis;
    }

}
TOP

Related Classes of com.foundationdb.sql.server.ServerValueDecoder

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.