blob: d0597790adee455a580766cc99a7ae4e1ff9469c [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.persist.impl;
import java.math.BigDecimal;
import java.math.BigInteger;
import com.sleepycat.compat.DbCompat;
/**
* Widens a value returned by another input when any readXxx method is called.
* Used to cause an Accessor to read a widened value.
*
* For non-key fields we support all Java primitive widening:
* - byte to short, int, long, float, double, BigInteger and BigDecimal
* - short to int, long, float, double, BigInteger and BigDecimal
* - char to int, long, float, double, BigInteger and BigDecimal
* - int to long, float, double, BigInteger and BigDecimal
* - long to float, double, BigInteger and BigDecimal
* - float to double
*
* For non-key fields we also support:
* - Java reference widening
* - primitive to primitive wrapper
* - Java primitive widening to corresponding primitive wrappers
* - Java widening of primitive wrapper to primitive wrapper
*
* For secondary keys fields we ONLY support:
* - primitive to primitive wrapper
*
* But for primary keys and composite key fields we ONLY support:
* - primitive to primitive wrapper
* - primitive wrapper to primitive
* These conversions don't require any converter, since the stored format is
* not changed. A WidenerInput is not used for these changes.
*
* @author Mark Hayes
*/
class WidenerInput extends AbstractInput {
private EntityInput input;
private int fromFormatId;
private int toFormatId;
/**
* Returns whether widening is supported by this class. If false is
* returned by this method, then widening is disallowed and a field
* converter or deleter is necessary.
*/
static boolean isWideningSupported(Format fromFormat,
Format toFormat,
boolean isSecKeyField) {
int fromFormatId = fromFormat.getId();
int toFormatId = toFormat.getId();
switch (fromFormatId) {
case Format.ID_BOOL:
switch (toFormatId) {
case Format.ID_BOOL_W:
return true;
default:
return false;
}
case Format.ID_BYTE:
switch (toFormatId) {
case Format.ID_BYTE_W:
return true;
case Format.ID_SHORT:
case Format.ID_SHORT_W:
case Format.ID_INT:
case Format.ID_INT_W:
case Format.ID_LONG:
case Format.ID_LONG_W:
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_BYTE_W:
switch (toFormatId) {
case Format.ID_SHORT_W:
case Format.ID_INT_W:
case Format.ID_LONG_W:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_SHORT:
switch (toFormatId) {
case Format.ID_SHORT_W:
return true;
case Format.ID_INT:
case Format.ID_INT_W:
case Format.ID_LONG:
case Format.ID_LONG_W:
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_SHORT_W:
switch (toFormatId) {
case Format.ID_INT_W:
case Format.ID_LONG_W:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_INT:
switch (toFormatId) {
case Format.ID_INT_W:
return true;
case Format.ID_LONG:
case Format.ID_LONG_W:
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_INT_W:
switch (toFormatId) {
case Format.ID_LONG_W:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_LONG:
switch (toFormatId) {
case Format.ID_LONG_W:
return true;
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_LONG_W:
switch (toFormatId) {
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_FLOAT:
switch (toFormatId) {
case Format.ID_FLOAT_W:
return true;
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return !isSecKeyField;
default:
return false;
}
case Format.ID_FLOAT_W:
switch (toFormatId) {
case Format.ID_DOUBLE_W:
return !isSecKeyField;
default:
return false;
}
case Format.ID_DOUBLE:
switch (toFormatId) {
case Format.ID_DOUBLE_W:
return true;
default:
return false;
}
case Format.ID_CHAR:
switch (toFormatId) {
case Format.ID_CHAR_W:
return true;
case Format.ID_INT:
case Format.ID_INT_W:
case Format.ID_LONG:
case Format.ID_LONG_W:
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_CHAR_W:
switch (toFormatId) {
case Format.ID_INT_W:
case Format.ID_LONG_W:
case Format.ID_FLOAT_W:
case Format.ID_DOUBLE_W:
case Format.ID_BIGINT:
return !isSecKeyField;
default:
return false;
}
case Format.ID_STRING:
switch (toFormatId) {
case Format.ID_OBJECT:
return !isSecKeyField;
default:
return false;
}
default:
return false;
}
}
WidenerInput(EntityInput input, int fromFormatId, int toFormatId) {
super(input.getCatalog(), input.isRawAccess());
this.input = input;
this.fromFormatId = fromFormatId;
this.toFormatId = toFormatId;
}
public void registerPriKeyObject(Object o) {
input.registerPriKeyObject(o);
}
public void registerPriStringKeyObject(Object o) {
input.registerPriStringKeyObject(o);
}
public int readArrayLength() {
throw DbCompat.unexpectedState();
}
public int readEnumConstant(String[] names) {
throw DbCompat.unexpectedState();
}
public void skipField(Format declaredFormat) {
throw DbCompat.unexpectedState();
}
public String readString() {
throw DbCompat.unexpectedState();
}
public Object readKeyObject(Format fromFormat)
throws RefreshException {
return readObject();
}
public Object readObject()
throws RefreshException {
switch (fromFormatId) {
case Format.ID_BOOL:
checkToFormat(Format.ID_BOOL_W);
return input.readBoolean();
case Format.ID_BYTE:
return byteToObject(input.readByte());
case Format.ID_BYTE_W:
Byte b = (Byte) input.readObject();
return (b != null) ? byteToObject(b) : null;
case Format.ID_SHORT:
return shortToObject(input.readShort());
case Format.ID_SHORT_W:
Short s = (Short) input.readObject();
return (s != null) ? shortToObject(s) : null;
case Format.ID_INT:
return intToObject(input.readInt());
case Format.ID_INT_W:
Integer i = (Integer) input.readObject();
return (i != null) ? intToObject(i) : null;
case Format.ID_LONG:
return longToObject(input.readLong());
case Format.ID_LONG_W:
Long l = (Long) input.readObject();
return (l != null) ? longToObject(l) : null;
case Format.ID_FLOAT:
return floatToObject(input.readSortedFloat());
case Format.ID_FLOAT_W:
Float f = (Float) input.readObject();
return (f != null) ? floatToObject(f) : null;
case Format.ID_DOUBLE:
checkToFormat(Format.ID_DOUBLE_W);
return input.readSortedDouble();
case Format.ID_CHAR:
return charToObject(input.readChar());
case Format.ID_CHAR_W:
Character c = (Character) input.readObject();
return (c != null) ? charToObject(c) : null;
case Format.ID_STRING:
checkToFormat(Format.ID_OBJECT);
return input.readStringObject();
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
private Object byteToObject(byte v) {
switch (toFormatId) {
case Format.ID_BYTE:
case Format.ID_BYTE_W:
return Byte.valueOf(v);
case Format.ID_SHORT:
case Format.ID_SHORT_W:
return Short.valueOf(v);
case Format.ID_INT:
case Format.ID_INT_W:
return Integer.valueOf(v);
case Format.ID_LONG:
case Format.ID_LONG_W:
return Long.valueOf(v);
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
return Float.valueOf(v);
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return Double.valueOf(v);
case Format.ID_BIGINT:
return BigInteger.valueOf(v);
default:
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
private Object shortToObject(short v) {
switch (toFormatId) {
case Format.ID_SHORT:
case Format.ID_SHORT_W:
return Short.valueOf(v);
case Format.ID_INT:
case Format.ID_INT_W:
return Integer.valueOf(v);
case Format.ID_LONG:
case Format.ID_LONG_W:
return Long.valueOf(v);
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
return Float.valueOf(v);
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return Double.valueOf(v);
case Format.ID_BIGINT:
return BigInteger.valueOf(v);
default:
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
private Object intToObject(int v) {
switch (toFormatId) {
case Format.ID_INT:
case Format.ID_INT_W:
return Integer.valueOf(v);
case Format.ID_LONG:
case Format.ID_LONG_W:
return Long.valueOf(v);
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
return Float.valueOf(v);
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return Double.valueOf(v);
case Format.ID_BIGINT:
return BigInteger.valueOf(v);
default:
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
private Object longToObject(long v) {
switch (toFormatId) {
case Format.ID_LONG:
case Format.ID_LONG_W:
return Long.valueOf(v);
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
return Float.valueOf(v);
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return Double.valueOf(v);
case Format.ID_BIGINT:
return BigInteger.valueOf(v);
default:
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
private Object floatToObject(float v) {
switch (toFormatId) {
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
return Float.valueOf(v);
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return Double.valueOf(v);
default:
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
private Object charToObject(char v) {
switch (toFormatId) {
case Format.ID_CHAR:
case Format.ID_CHAR_W:
return Character.valueOf(v);
case Format.ID_INT:
case Format.ID_INT_W:
return Integer.valueOf(v);
case Format.ID_LONG:
case Format.ID_LONG_W:
return Long.valueOf(v);
case Format.ID_FLOAT:
case Format.ID_FLOAT_W:
return Float.valueOf(v);
case Format.ID_DOUBLE:
case Format.ID_DOUBLE_W:
return Double.valueOf(v);
case Format.ID_BIGINT:
return BigInteger.valueOf(v);
default:
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
public char readChar() {
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
public boolean readBoolean() {
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
public byte readByte() {
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
public short readShort()
throws RefreshException {
checkToFormat(Format.ID_SHORT);
switch (fromFormatId) {
case Format.ID_BYTE:
return input.readByte();
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
public int readInt()
throws RefreshException {
checkToFormat(Format.ID_INT);
switch (fromFormatId) {
case Format.ID_BYTE:
return input.readByte();
case Format.ID_SHORT:
return input.readShort();
case Format.ID_CHAR:
return input.readChar();
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
public long readLong()
throws RefreshException {
checkToFormat(Format.ID_LONG);
switch (fromFormatId) {
case Format.ID_BYTE:
return input.readByte();
case Format.ID_SHORT:
return input.readShort();
case Format.ID_INT:
return input.readInt();
case Format.ID_CHAR:
return input.readChar();
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
public float readSortedFloat()
throws RefreshException {
checkToFormat(Format.ID_FLOAT);
switch (fromFormatId) {
case Format.ID_BYTE:
return input.readByte();
case Format.ID_SHORT:
return input.readShort();
case Format.ID_INT:
return input.readInt();
case Format.ID_LONG:
return input.readLong();
case Format.ID_CHAR:
return input.readChar();
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
public double readSortedDouble()
throws RefreshException {
checkToFormat(Format.ID_DOUBLE);
switch (fromFormatId) {
case Format.ID_BYTE:
return input.readByte();
case Format.ID_SHORT:
return input.readShort();
case Format.ID_INT:
return input.readInt();
case Format.ID_LONG:
return input.readLong();
case Format.ID_FLOAT:
return input.readSortedFloat();
case Format.ID_CHAR:
return input.readChar();
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
public BigInteger readBigInteger()
throws RefreshException {
checkToFormat(Format.ID_BIGINT);
switch (fromFormatId) {
case Format.ID_BYTE:
return BigInteger.valueOf(input.readByte());
case Format.ID_SHORT:
return BigInteger.valueOf(input.readShort());
case Format.ID_INT:
return BigInteger.valueOf(input.readInt());
case Format.ID_LONG:
return BigInteger.valueOf(input.readLong());
case Format.ID_CHAR:
return BigInteger.valueOf(input.readChar());
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
public BigDecimal readSortedBigDecimal()
throws RefreshException {
checkToFormat(Format.ID_BIGDEC);
switch (fromFormatId) {
case Format.ID_BYTE:
return BigDecimal.valueOf(input.readByte());
case Format.ID_SHORT:
return BigDecimal.valueOf(input.readShort());
case Format.ID_INT:
return BigDecimal.valueOf(input.readInt());
case Format.ID_LONG:
return BigDecimal.valueOf(input.readLong());
case Format.ID_CHAR:
return BigDecimal.valueOf(input.readChar());
default:
throw DbCompat.unexpectedState(String.valueOf(fromFormatId));
}
}
private void checkToFormat(int id) {
if (toFormatId != id) {
throw DbCompat.unexpectedState(String.valueOf(toFormatId));
}
}
public Object readStringObject(){
throw DbCompat.unexpectedState();
}
}