| /* |
| * 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.chunk.store; |
| |
| import java.util.BitSet; |
| |
| import org.apache.carbondata.core.constants.CarbonCommonConstants; |
| import org.apache.carbondata.core.datastore.ColumnType; |
| import org.apache.carbondata.core.datastore.chunk.DimensionColumnPage; |
| import org.apache.carbondata.core.datastore.page.ColumnPage; |
| import org.apache.carbondata.core.metadata.datatype.DataType; |
| import org.apache.carbondata.core.metadata.datatype.DataTypes; |
| import org.apache.carbondata.core.scan.result.vector.CarbonColumnVector; |
| import org.apache.carbondata.core.scan.result.vector.CarbonDictionary; |
| import org.apache.carbondata.core.scan.result.vector.ColumnVectorInfo; |
| import org.apache.carbondata.core.util.ByteUtil; |
| import org.apache.carbondata.core.util.CarbonUtil; |
| import org.apache.carbondata.core.util.DataTypeUtil; |
| |
| public class ColumnPageWrapper implements DimensionColumnPage { |
| |
| private ColumnPage columnPage; |
| |
| private CarbonDictionary localDictionary; |
| |
| private boolean isAdaptivePrimitivePage; |
| |
| private int[] invertedIndex; |
| |
| private int[] invertedReverseIndex; |
| |
| private boolean isExplicitSorted; |
| |
| public ColumnPageWrapper(ColumnPage columnPage, CarbonDictionary localDictionary, |
| int[] invertedIndex, int[] invertedReverseIndex, boolean isAdaptivePrimitivePage, |
| boolean isExplicitSorted) { |
| this.columnPage = columnPage; |
| this.localDictionary = localDictionary; |
| this.invertedIndex = invertedIndex; |
| this.invertedReverseIndex = invertedReverseIndex; |
| this.isAdaptivePrimitivePage = isAdaptivePrimitivePage; |
| this.isExplicitSorted = isExplicitSorted; |
| } |
| |
| @Override |
| public int fillRawData(int rowId, int offset, byte[] data) { |
| throw new UnsupportedOperationException("internal error"); |
| } |
| |
| @Override |
| public int fillSurrogateKey(int rowId, int chunkIndex, int[] outputSurrogateKey) { |
| throw new UnsupportedOperationException("internal error"); |
| } |
| |
| @Override |
| public int fillVector(ColumnVectorInfo[] vectorInfo, int chunkIndex) { |
| ColumnVectorInfo columnVectorInfo = vectorInfo[chunkIndex]; |
| CarbonColumnVector vector = columnVectorInfo.vector; |
| int offset = columnVectorInfo.offset; |
| int vectorOffset = columnVectorInfo.vectorOffset; |
| int len = offset + columnVectorInfo.size; |
| for (int i = offset; i < len; i++) { |
| fillRow(i, vector, vectorOffset++); |
| } |
| return chunkIndex + 1; |
| } |
| |
| @Override |
| public int fillVector(int[] filteredRowId, ColumnVectorInfo[] vectorInfo, int chunkIndex) { |
| ColumnVectorInfo columnVectorInfo = vectorInfo[chunkIndex]; |
| CarbonColumnVector vector = columnVectorInfo.vector; |
| int offset = columnVectorInfo.offset; |
| int vectorOffset = columnVectorInfo.vectorOffset; |
| int len = offset + columnVectorInfo.size; |
| for (int i = offset; i < len; i++) { |
| fillRow(filteredRowId[i], vector, vectorOffset++); |
| } |
| return chunkIndex + 1; |
| } |
| |
| @Override |
| public byte[] getChunkData(int rowId) { |
| byte[] nullBitSet = getNullBitSet(rowId, columnPage.getColumnSpec().getColumnType()); |
| if (nullBitSet != null) { |
| // if this row is null, return default null represent in byte array |
| return nullBitSet; |
| } else { |
| if (isExplicitSorted()) { |
| rowId = getInvertedReverseIndex(rowId); |
| } |
| return getChunkDataInBytes(rowId); |
| } |
| } |
| |
| private byte[] getChunkDataInBytes(int rowId) { |
| ColumnType columnType = columnPage.getColumnSpec().getColumnType(); |
| DataType srcDataType = columnPage.getColumnSpec().getSchemaDataType(); |
| DataType targetDataType = columnPage.getDataType(); |
| if (null != localDictionary) { |
| return localDictionary |
| .getDictionaryValue(CarbonUtil.getSurrogateInternal(columnPage.getBytes(rowId), 0, 3)); |
| } else if ((columnType == ColumnType.COMPLEX_PRIMITIVE && isAdaptiveEncoded()) || ( |
| columnType == ColumnType.PLAIN_VALUE && DataTypeUtil.isPrimitiveColumn(srcDataType))) { |
| if (srcDataType == DataTypes.FLOAT) { |
| float floatData = columnPage.getFloat(rowId); |
| return ByteUtil.toXorBytes(floatData); |
| } else if (srcDataType == DataTypes.DOUBLE) { |
| double doubleData = columnPage.getDouble(rowId); |
| return ByteUtil.toXorBytes(doubleData); |
| } else if (DataTypes.isDecimal(srcDataType)) { |
| throw new RuntimeException("unsupported type: " + srcDataType); |
| } else if ((srcDataType == DataTypes.BYTE) || (srcDataType == DataTypes.BOOLEAN) || ( |
| srcDataType == DataTypes.SHORT) || (srcDataType == DataTypes.SHORT_INT) || (srcDataType |
| == DataTypes.INT) || (srcDataType == DataTypes.LONG) || (srcDataType |
| == DataTypes.TIMESTAMP)) { |
| long longData = columnPage.getLong(rowId); |
| if ((srcDataType == DataTypes.BYTE)) { |
| byte out = (byte) longData; |
| return new byte[] { out }; |
| } else if (srcDataType == DataTypes.BOOLEAN) { |
| byte out = (byte) longData; |
| return ByteUtil.toBytes(ByteUtil.toBoolean(out)); |
| } else if (srcDataType == DataTypes.SHORT) { |
| short out = (short) longData; |
| return ByteUtil.toXorBytes(out); |
| } else if (srcDataType == DataTypes.SHORT_INT) { |
| int out = (int) longData; |
| return ByteUtil.toXorBytes(out); |
| } else if (srcDataType == DataTypes.INT) { |
| int out = (int) longData; |
| return ByteUtil.toXorBytes(out); |
| } else { |
| // timestamp and long |
| return ByteUtil.toXorBytes(longData); |
| } |
| } else if ((targetDataType == DataTypes.STRING) || (targetDataType == DataTypes.VARCHAR) || ( |
| targetDataType == DataTypes.BYTE_ARRAY)) { |
| return columnPage.getBytes(rowId); |
| } else { |
| throw new RuntimeException("unsupported type: " + targetDataType); |
| } |
| } else if ((columnType == ColumnType.COMPLEX_PRIMITIVE && !isAdaptiveEncoded())) { |
| if ((srcDataType == DataTypes.BYTE) || (srcDataType == DataTypes.BOOLEAN)) { |
| byte[] out = new byte[1]; |
| out[0] = (columnPage.getByte(rowId)); |
| return ByteUtil.toBytes(ByteUtil.toBoolean(out)); |
| } else if (srcDataType == DataTypes.BYTE_ARRAY) { |
| return columnPage.getBytes(rowId); |
| } else if (srcDataType == DataTypes.DOUBLE) { |
| return ByteUtil.toXorBytes(columnPage.getDouble(rowId)); |
| } else if (srcDataType == DataTypes.FLOAT) { |
| return ByteUtil.toXorBytes(columnPage.getFloat(rowId)); |
| } else if (srcDataType == targetDataType) { |
| return columnPage.getBytes(rowId); |
| } else { |
| throw new RuntimeException("unsupported type: " + targetDataType); |
| } |
| } else { |
| return columnPage.getBytes(rowId); |
| } |
| } |
| |
| private byte[] getNullBitSet(int rowId, ColumnType columnType) { |
| if (columnPage.getNullBits().get(rowId) && columnType == ColumnType.COMPLEX_PRIMITIVE) { |
| // if this row is null, return default null represent in byte array |
| return CarbonCommonConstants.MEMBER_DEFAULT_VAL_ARRAY; |
| } |
| if (columnPage.getNullBits().get(rowId)) { |
| // if this row is null, return default null represent in byte array |
| return CarbonCommonConstants.EMPTY_BYTE_ARRAY; |
| } |
| return null; |
| } |
| |
| /** |
| * Fill the data to the vector |
| * |
| * @param rowId |
| * @param vector |
| * @param vectorRow |
| */ |
| private void fillRow(int rowId, CarbonColumnVector vector, int vectorRow) { |
| if (columnPage.getNullBits().get(rowId)) { |
| vector.putNull(vectorRow); |
| } else { |
| if (isExplicitSorted) { |
| rowId = invertedReverseIndex[rowId]; |
| } |
| DataType dt = vector.getType(); |
| long longData = columnPage.getLong(rowId); |
| if (dt == DataTypes.BOOLEAN) { |
| vector.putBoolean(vectorRow, ByteUtil.toBoolean((byte) longData)); |
| } else if (dt == DataTypes.BYTE) { |
| vector.putByte(vectorRow, (byte) longData); |
| } else if (dt == DataTypes.SHORT) { |
| vector.putShort(vectorRow, (short) longData); |
| } else if (dt == DataTypes.INT) { |
| vector.putInt(vectorRow, (int) longData); |
| } else if (dt == DataTypes.LONG) { |
| // retrieving the data after change in data type restructure operation |
| if (vector.getBlockDataType() == DataTypes.INT) { |
| vector.putLong(vectorRow, (int) longData); |
| } else if (vector.getBlockDataType() == DataTypes.LONG) { |
| vector.putLong(vectorRow, longData); |
| } |
| } else if (dt == DataTypes.TIMESTAMP) { |
| vector.putLong(vectorRow, longData * 1000L); |
| } else { |
| throw new RuntimeException("unsupported type: " + dt); |
| } |
| } |
| } |
| |
| @Override |
| public int getInvertedIndex(int rowId) { |
| return invertedIndex[rowId]; |
| } |
| |
| @Override |
| public int getInvertedReverseIndex(int rowId) { |
| return invertedReverseIndex[rowId]; |
| } |
| |
| @Override |
| public boolean isNoDictionaryColumn() { |
| return true; |
| } |
| |
| @Override |
| public boolean isExplicitSorted() { |
| return isExplicitSorted; |
| } |
| |
| @Override |
| public int compareTo(int rowId, byte[] compareValue) { |
| // rowId is the inverted index, but the null bitset is based on actual data |
| int nullBitSetRowId = rowId; |
| if (isExplicitSorted()) { |
| nullBitSetRowId = getInvertedIndex(rowId); |
| } |
| byte[] nullBitSet = getNullBitSet(nullBitSetRowId, columnPage.getColumnSpec().getColumnType()); |
| if (nullBitSet != null |
| && ByteUtil.UnsafeComparer.INSTANCE.compareTo(nullBitSet, compareValue) == 0) { |
| // check if the compare value is a null value |
| // if the compare value is null and the data is also null we can directly return 0 |
| return 0; |
| } else { |
| byte[] chunkData; |
| if (nullBitSet != null && nullBitSet.length == 0) { |
| chunkData = nullBitSet; |
| } else { |
| chunkData = this.getChunkDataInBytes(rowId); |
| } |
| return ByteUtil.UnsafeComparer.INSTANCE.compareTo(chunkData, compareValue); |
| } |
| } |
| |
| @Override |
| public void freeMemory() { |
| if (null != columnPage) { |
| columnPage.freeMemory(); |
| columnPage = null; |
| } |
| } |
| |
| @Override |
| public boolean isAdaptiveEncoded() { |
| return isAdaptivePrimitivePage; |
| } |
| |
| @Override |
| public BitSet getNullBits() { |
| return columnPage.getNullBits(); |
| } |
| |
| } |