blob: a1e37652d5561bd113e4c2fde234cf87dd2606f4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.carbondata.core.datastore.page.encoding;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import org.apache.carbondata.core.datastore.TableSpec;
import org.apache.carbondata.core.datastore.page.statistics.SimpleStatsResult;
import org.apache.carbondata.core.metadata.ValueEncoderMeta;
import org.apache.carbondata.core.metadata.datatype.DataType;
import org.apache.carbondata.core.metadata.datatype.DataTypes;
import org.apache.carbondata.core.metadata.datatype.DecimalType;
import org.apache.carbondata.core.metadata.schema.table.Writable;
import org.apache.carbondata.core.util.DataTypeUtil;
/**
* It holds metadata for one column page
*/
public class ColumnPageEncoderMeta extends ValueEncoderMeta implements Writable {
private static final long serialVersionUID = 1905162071950251407L;
// column spec of this column
private transient TableSpec.ColumnSpec columnSpec;
// storage data type of this column, it could be different from data type in the column spec
private DataType storeDataType;
// compressor name for compressing and decompressing this column.
// Make it protected for RLEEncoderMeta
protected String compressorName;
// Whether the flow should go to fill complete vector while decoding the page.
private transient boolean fillCompleteVector;
public ColumnPageEncoderMeta() {
}
public ColumnPageEncoderMeta(TableSpec.ColumnSpec columnSpec, DataType storeDataType,
String compressorName) {
if (columnSpec == null) {
throw new IllegalArgumentException("column spec must not be null");
}
if (storeDataType == null) {
throw new IllegalArgumentException("store data type must not be null");
}
if (compressorName == null) {
throw new IllegalArgumentException("compressor must not be null");
}
this.columnSpec = columnSpec;
this.storeDataType = storeDataType;
this.compressorName = compressorName;
setType(DataType.convertType(storeDataType));
}
public ColumnPageEncoderMeta(TableSpec.ColumnSpec columnSpec, DataType storeDataType,
SimpleStatsResult stats, String compressorName) {
this(columnSpec, storeDataType, compressorName);
if (stats != null) {
setDecimal(stats.getDecimalCount());
setMaxValue(stats.getMax());
setMinValue(stats.getMin());
}
}
public DataType getStoreDataType() {
return storeDataType;
}
@Override
public void write(DataOutput out) throws IOException {
columnSpec.write(out);
out.writeByte(storeDataType.getId());
out.writeInt(getDecimal());
out.writeByte(getDataTypeSelected());
writeMinMax(out);
out.writeUTF(compressorName);
}
@Override
public void readFields(DataInput in) throws IOException {
columnSpec = new TableSpec.ColumnSpec();
columnSpec.readFields(in);
storeDataType = DataTypes.valueOf(in.readByte());
if (DataTypes.isDecimal(storeDataType)) {
DecimalType decimalType = (DecimalType) storeDataType;
decimalType.setPrecision(columnSpec.getPrecision());
decimalType.setScale(columnSpec.getScale());
}
setDecimal(in.readInt());
setDataTypeSelected(in.readByte());
readMinMax(in);
compressorName = in.readUTF();
}
private void writeMinMax(DataOutput out) throws IOException {
DataType dataType = columnSpec.getSchemaDataType();
if (dataType == DataTypes.BOOLEAN || dataType == DataTypes.BYTE) {
out.writeByte((byte) getMaxValue());
out.writeByte((byte) getMinValue());
out.writeLong(0L); // unique value is obsoleted, maintain for compatibility
} else if (dataType == DataTypes.SHORT) {
out.writeShort((short) getMaxValue());
out.writeShort((short) getMinValue());
out.writeLong(0L); // unique value is obsoleted, maintain for compatibility
} else if (dataType == DataTypes.INT) {
out.writeInt((int) getMaxValue());
out.writeInt((int) getMinValue());
out.writeLong(0L); // unique value is obsoleted, maintain for compatibility
} else if (dataType == DataTypes.LONG || dataType == DataTypes.TIMESTAMP) {
out.writeLong((Long) getMaxValue());
out.writeLong((Long) getMinValue());
out.writeLong(0L); // unique value is obsoleted, maintain for compatibility
} else if (dataType == DataTypes.DOUBLE) {
out.writeDouble((Double) getMaxValue());
out.writeDouble((Double) getMinValue());
out.writeDouble(0d); // unique value is obsoleted, maintain for compatibility
} else if (dataType == DataTypes.FLOAT) {
out.writeFloat((Float) getMaxValue());
out.writeFloat((Float) getMinValue());
out.writeFloat(0f); // unique value is obsoleted, maintain for compatibility
} else if (DataTypes.isDecimal(dataType)) {
byte[] maxAsBytes = getMaxAsBytes(columnSpec.getSchemaDataType());
byte[] minAsBytes = getMinAsBytes(columnSpec.getSchemaDataType());
byte[] unique = DataTypeUtil.bigDecimalToByte(BigDecimal.ZERO);
out.writeShort((short) maxAsBytes.length);
out.write(maxAsBytes);
out.writeShort((short) minAsBytes.length);
out.write(minAsBytes);
// unique value is obsoleted, maintain for compatibility
out.writeShort((short) unique.length);
out.write(unique);
if (DataTypes.isDecimal(dataType)) {
DecimalType decimalType = (DecimalType) dataType;
out.writeInt(decimalType.getScale());
out.writeInt(decimalType.getPrecision());
} else {
out.writeInt(-1);
out.writeInt(-1);
}
} else if (dataType == DataTypes.BYTE_ARRAY || dataType == DataTypes.BINARY) {
// for complex type, it will come here, ignoring stats for complex type
// TODO: support stats for complex type
} else {
throw new IllegalArgumentException("invalid data type: " + storeDataType);
}
}
private void readMinMax(DataInput in) throws IOException {
DataType dataType = columnSpec.getSchemaDataType();
if (dataType == DataTypes.BOOLEAN || dataType == DataTypes.BYTE) {
this.setMaxValue(in.readByte());
this.setMinValue(in.readByte());
in.readLong(); // for non exist value which is obsoleted, it is backward compatibility;
} else if (dataType == DataTypes.SHORT) {
this.setMaxValue(in.readShort());
this.setMinValue(in.readShort());
in.readLong(); // for non exist value which is obsoleted, it is backward compatibility;
} else if (dataType == DataTypes.INT) {
this.setMaxValue(in.readInt());
this.setMinValue(in.readInt());
in.readLong(); // for non exist value which is obsoleted, it is backward compatibility;
} else if (dataType == DataTypes.LONG || dataType == DataTypes.TIMESTAMP) {
this.setMaxValue(in.readLong());
this.setMinValue(in.readLong());
in.readLong(); // for non exist value which is obsoleted, it is backward compatibility;
} else if (dataType == DataTypes.DOUBLE) {
this.setMaxValue(in.readDouble());
this.setMinValue(in.readDouble());
in.readDouble(); // for non exist value which is obsoleted, it is backward compatibility;
} else if (dataType == DataTypes.FLOAT) {
this.setMaxValue(in.readFloat());
this.setMinValue(in.readFloat());
in.readFloat(); // for non exist value which is obsoleted, it is backward compatibility;
} else if (DataTypes.isDecimal(dataType)) {
byte[] max = new byte[in.readShort()];
in.readFully(max);
this.setMaxValue(DataTypeUtil.byteToBigDecimal(max));
byte[] min = new byte[in.readShort()];
in.readFully(min);
this.setMinValue(DataTypeUtil.byteToBigDecimal(min));
// unique value is obsoleted, maintain for compatibility
short uniqueLength = in.readShort();
in.readFully(new byte[uniqueLength]);
// scale field is obsoleted. It is stored in the schema data type in columnSpec
in.readInt();
// precision field is obsoleted. It is stored in the schema data type in columnSpec
in.readInt();
} else if (dataType == DataTypes.BYTE_ARRAY || dataType == DataTypes.BINARY) {
// for complex type, it will come here, ignoring stats for complex type
// TODO: support stats for complex type
} else {
throw new IllegalArgumentException("invalid data type: " + storeDataType);
}
}
private byte[] getMaxAsBytes(DataType dataType) {
return getValueAsBytes(getMaxValue(), dataType);
}
private byte[] getMinAsBytes(DataType dataType) {
return getValueAsBytes(getMinValue(), dataType);
}
/**
* convert value to byte array
*/
private byte[] getValueAsBytes(Object value, DataType dataType) {
ByteBuffer b;
if (dataType == DataTypes.BYTE_ARRAY) {
b = ByteBuffer.allocate(8);
b.putLong((byte) value);
b.flip();
return b.array();
} else if (dataType == DataTypes.SHORT) {
b = ByteBuffer.allocate(8);
b.putLong((short) value);
b.flip();
return b.array();
} else if (dataType == DataTypes.INT) {
b = ByteBuffer.allocate(8);
b.putLong((int) value);
b.flip();
return b.array();
} else if (dataType == DataTypes.LONG) {
b = ByteBuffer.allocate(8);
b.putLong((long) value);
b.flip();
return b.array();
} else if (dataType == DataTypes.DOUBLE) {
b = ByteBuffer.allocate(8);
b.putDouble((double) value);
b.flip();
return b.array();
} else if (DataTypes.isDecimal(dataType)) {
return DataTypeUtil.bigDecimalToByte((BigDecimal) value);
} else if (dataType == DataTypes.STRING || dataType == DataTypes.TIMESTAMP
|| dataType == DataTypes.DATE) {
return (byte[]) value;
} else {
throw new IllegalArgumentException("Invalid data type: " + storeDataType);
}
}
public int getScale() {
if (DataTypes.isDecimal(columnSpec.getSchemaDataType())) {
return columnSpec.getScale();
}
throw new UnsupportedOperationException();
}
public int getPrecision() {
if (DataTypes.isDecimal(columnSpec.getSchemaDataType())) {
return columnSpec.getPrecision();
}
throw new UnsupportedOperationException();
}
public TableSpec.ColumnSpec getColumnSpec() {
return columnSpec;
}
public String getCompressorName() {
return compressorName;
}
public DataType getSchemaDataType() {
return columnSpec.getSchemaDataType();
}
public boolean isFillCompleteVector() {
return fillCompleteVector;
}
public void setFillCompleteVector(boolean fillCompleteVector) {
this.fillCompleteVector = fillCompleteVector;
}
}