All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oracle.kv.impl.api.table.TimestampValueImpl Maven / Gradle / Ivy

/*-
 * Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle NoSQL
 * Database made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle NoSQL Database for a copy of the license and
 * additional information.
 */

package oracle.kv.impl.api.table;

import static oracle.kv.impl.api.table.TimestampUtils.fromBytes;
import static oracle.kv.impl.api.table.TimestampUtils.formatString;
import static oracle.kv.impl.api.table.TimestampUtils.roundToPrecision;
import static oracle.kv.impl.api.table.TimestampUtils.toMilliseconds;

import java.sql.Timestamp;
import java.util.Arrays;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.TextNode;
import org.codehaus.jackson.util.CharTypes;

import oracle.kv.impl.util.SizeOf;
import oracle.kv.impl.util.SortableString;
import oracle.kv.table.FieldDef;
import oracle.kv.table.FieldValue;
import oracle.kv.table.FieldValueFactory;
import oracle.kv.table.TimestampDef;
import oracle.kv.table.TimestampValue;

/**
 * This class represents a Timestamp value with precision in range of 0 ~ 9.
 */
public class TimestampValueImpl extends FieldValueImpl
    implements TimestampValue {

    private static final long serialVersionUID = 1L;

    static final byte[] DEFAULT_VALUE =
        TimestampUtils.toBytes(new Timestamp(0), 0);

    private final TimestampDefImpl def;

    /* The number of microseconds from the epoch of 1970-01-01T00:00:00Z */
    private byte[] value;

    TimestampValueImpl(TimestampDef def, Timestamp timestamp) {
        validate(timestamp);
        this.def = (TimestampDefImpl)def;
        value = TimestampUtils.toBytes
                    (roundToPrecision(timestamp, def.getPrecision()),
                     def.getPrecision());
    }

    /**
     * This constructor creates TimestampValueImpl from the String format used
     * for sorted keys.
     */
    TimestampValueImpl(TimestampDef def, String keyValue) {
        this(def, SortableString.bytesFromSortable(keyValue));
    }

    TimestampValueImpl(TimestampDef def, byte[] value) {
        this.def = (TimestampDefImpl)def;
        this.value = value;
    }

    TimestampValueImpl(TimestampDef def, long milliseconds) {
        this(def, new Timestamp(milliseconds));
    }

    /*
     * Public api methods from Object and FieldValue
     */
    @Override
    public TimestampValueImpl clone() {
        return new TimestampValueImpl(def, value);
    }

    @Override
    public long sizeof() {
        return (SizeOf.OBJECT_OVERHEAD +
                2 * SizeOf.OBJECT_REF_OVERHEAD +
                SizeOf.byteArraySize(value.length));
    }

    /**
     * Cast "this" to another timestamp with the given precision.
     */
    public TimestampValueImpl castToPrecision(int targetPrec) {

        int myPrec = def.getPrecision();
        assert(myPrec != targetPrec);

        /*
         * Casting to a lower precision, may require rounding up the
         * frac second in the new timestamp value. So we do the cast
         * the "hard way".
         */
        if (targetPrec < myPrec) {
            return FieldDefImpl.getTimeDef(targetPrec).createTimestamp(get());
        }

        int myFracSec = getFracSecond();
        int targetFracSec;

        if (myPrec == 0 || targetPrec == 0) {
            targetFracSec = 0;
        } else if (myPrec < targetPrec) {
            targetFracSec = myFracSec * (int)Math.pow(10, targetPrec - myPrec);
        } else {
            targetFracSec = myFracSec / (int)Math.pow(10, myPrec - targetPrec);
        }

        return
            (TimestampValueImpl)
            FieldValueFactory.createTimestamp(getYear(),
                                              getMonth(),
                                              getDay(),
                                              getHour(),
                                              getMinute(),
                                              getSecond(),
                                              targetFracSec,
                                              targetPrec);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(value);
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof TimestampValueImpl) {
            return (compareTo((FieldValue)other) == 0);
        }
        return false;
    }

    /**
     * Allow comparisons against TimestampValue to succeed.
     */
    @Override
    public int compareTo(FieldValue other) {
        if (other instanceof TimestampValueImpl) {
            TimestampValueImpl otherVal = ((TimestampValueImpl)other);
            return TimestampUtils.compareBytes(
                value,
                def.getPrecision(),
                otherVal.value,
                otherVal.getDefinition().getPrecision());
        }
        throw new ClassCastException("Object is not a TimestampValue");
    }

    @Override
    public String toString() {
        return toString(null, true);
    }

    @Override
    public FieldDef.Type getType() {
        return FieldDef.Type.TIMESTAMP;
    }

    @Override
    public TimestampDefImpl getDefinition() {
        return def;
    }

    @Override
    public TimestampValue asTimestamp() {
        return this;
    }

    @Override
    public boolean isTimestamp() {
        return true;
    }

    @Override
    public boolean isAtomic() {
        return true;
    }

    /*
     * Public api methods from TimestampValue
     */
    @Override
    public Timestamp get() {
        return fromBytes(value, def.getPrecision());
    }

    @Override
    public int getYear() {
        return TimestampUtils.getYear(value);
    }

    @Override
    public int getMonth() {
        return TimestampUtils.getMonth(value);
    }

    @Override
    public int getDay() {
        return TimestampUtils.getDay(value);
    }

    @Override
    public int getHour() {
        return TimestampUtils.getHour(value);
    }

    @Override
    public int getMinute() {
        return TimestampUtils.getMinute(value);
    }

    @Override
    public int getSecond() {
        return TimestampUtils.getSecond(value);
    }

    @Override
    public int getNano() {
        return TimestampUtils.getNano(value, def.getPrecision());
    }

    @Override
    public int getFracSecond() {
        return TimestampUtils.getFracSecond(value, def.getPrecision());
    }

    /*
     * FieldValueImpl internal api methods
     */
    @Override
    public void setTimestamp(Timestamp ts) {
        if (ts == null) {
            throw new IllegalArgumentException("timestamp should not be null");
        }
        value = TimestampUtils.toBytes(roundToPrecision(ts, def.getPrecision()),
                                       def.getPrecision());
    }

    @Override
    public Timestamp getTimestamp() {
        return get();
    }

    /* Returns the milliseconds since Java epoch */
    @Override
    public long castAsLong() {
        return toMilliseconds(getTimestamp());
    }

    @Override
    public String castAsString() {
        return toString();
    }

    @Override
    public String formatForKey(FieldDef field1, int storageSize) {
        return toKeyString(value);
    }

    @Override
    FieldValueImpl getNextValue() {
        Timestamp ts = get();
        if (ts.compareTo(def.getMaxValue()) == 0) {
            return null;
        }
        final int precision = def.getPrecision();
        Timestamp nextVal;
        if (def.getPrecision() <= 3) {
            nextVal = TimestampUtils.plusMillis
                        (ts, (long)Math.pow(10, 3 - precision));
        } else {
            nextVal = TimestampUtils.plusNanos
                        (ts, (long)Math.pow(10, TimestampDefImpl.MAX_PRECISION -
                                                precision));
        }
        return def.createTimestamp(nextVal);
    }

    @Override
    FieldValueImpl getMinimumValue() {
        return def.createTimestamp(def.getMinValue());
    }

    @Override
    public JsonNode toJsonNode() {
        return new TextNode(toString());
    }

    @Override
    public void toStringBuilder(StringBuilder sb) {
        sb.append('\"');
        CharTypes.appendQuoted(sb, toString());
        sb.append('\"');
    }

    @Override
    public String toString(String pattern, boolean withZoneUTC) {
        return formatString(this, pattern, withZoneUTC);
    }

    @Override
    public byte[] getBytes() {
        return getBytes(false);
    }

    /**
     * Returns the byte array that represents the timestamp value.
     *
     * @param fullSize indicates if returning byte array is a full size or
     * compact. If true, then pad with zeros to obtain the max length.
     *
     * @return the byte array.
     */
    byte[] getBytes(boolean fullSize) {
        return fullSize ? Arrays.copyOf(value, def.getNumBytes()) : value;
    }

    void validate(Timestamp timestamp) {
        if (timestamp.compareTo(TimestampDefImpl.MAX_VALUE) > 0 ||
            timestamp.compareTo(TimestampDefImpl.MIN_VALUE) < 0) {

            throw new IllegalArgumentException("Timestamp should be " +
                "in range from " + formatString(TimestampDefImpl.MIN_VALUE) +
                " to " + formatString(TimestampDefImpl.MAX_VALUE) + ": " +
                formatString(timestamp));
        }
    }

    static String toKeyString(byte[] bytes) {
        return SortableString.toSortable(bytes);
    }

    @Override
    public byte[] getTimestampBytes() {
        return getBytes();
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy