001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client.coprocessor;
019
020import java.io.IOException;
021import java.math.BigDecimal;
022import java.math.RoundingMode;
023import org.apache.hadoop.hbase.Cell;
024import org.apache.hadoop.hbase.CellUtil;
025import org.apache.hadoop.hbase.HBaseInterfaceAudience;
026import org.apache.hadoop.hbase.PrivateCellUtil;
027import org.apache.hadoop.hbase.coprocessor.ColumnInterpreter;
028import org.apache.hadoop.hbase.util.Bytes;
029import org.apache.yetus.audience.InterfaceAudience;
030import org.apache.yetus.audience.InterfaceStability;
031
032import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
033
034import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.BigDecimalMsg;
035import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.EmptyMsg;
036
037/**
038 * ColumnInterpreter for doing Aggregation's with BigDecimal columns. This class is required at the
039 * RegionServer also.
040 */
041@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
042@InterfaceStability.Evolving
043public class BigDecimalColumnInterpreter
044  extends ColumnInterpreter<BigDecimal, BigDecimal, EmptyMsg, BigDecimalMsg, BigDecimalMsg> {
045
046  @Override
047  public BigDecimal getValue(byte[] colFamily, byte[] colQualifier, Cell kv) throws IOException {
048    if (kv == null || CellUtil.cloneValue(kv) == null) {
049      return null;
050    }
051    return PrivateCellUtil.getValueAsBigDecimal(kv).setScale(2, RoundingMode.HALF_EVEN);
052  }
053
054  @Override
055  public BigDecimal add(BigDecimal bd1, BigDecimal bd2) {
056    if (bd1 == null ^ bd2 == null) {
057      return (bd1 == null) ? bd2 : bd1; // either of one is null.
058    }
059    if (bd1 == null) {
060      return null;
061    }
062    return bd1.add(bd2);
063  }
064
065  @Override
066  public int compare(final BigDecimal bd1, final BigDecimal bd2) {
067    if (bd1 == null ^ bd2 == null) {
068      return bd1 == null ? -1 : 1; // either of one is null.
069    }
070    if (bd1 == null) {
071      return 0; // both are null
072    }
073    return bd1.compareTo(bd2); // natural ordering.
074  }
075
076  @Override
077  public BigDecimal getMaxValue() {
078    return BigDecimal.valueOf(Double.MAX_VALUE);
079  }
080
081  @Override
082  public BigDecimal increment(BigDecimal bd) {
083    return bd == null ? null : (bd.add(BigDecimal.ONE));
084  }
085
086  @Override
087  public BigDecimal multiply(BigDecimal bd1, BigDecimal bd2) {
088    return (bd1 == null || bd2 == null)
089      ? null
090      : bd1.multiply(bd2).setScale(2, RoundingMode.HALF_EVEN);
091  }
092
093  @Override
094  public BigDecimal getMinValue() {
095    return BigDecimal.valueOf(Double.MIN_VALUE);
096  }
097
098  @Override
099  public double divideForAvg(BigDecimal bd1, Long l2) {
100    return (l2 == null || bd1 == null) ? Double.NaN : (bd1.doubleValue() / l2.doubleValue());
101  }
102
103  @Override
104  public BigDecimal castToReturnType(BigDecimal bd) {
105    return bd;
106  }
107
108  @Override
109  public BigDecimal castToCellType(BigDecimal bd) {
110    return bd;
111  }
112
113  @Override
114  public EmptyMsg getRequestData() {
115    return EmptyMsg.getDefaultInstance();
116  }
117
118  @Override
119  public void initialize(EmptyMsg msg) {
120    // nothing
121  }
122
123  private BigDecimalMsg getProtoForType(BigDecimal t) {
124    BigDecimalMsg.Builder builder = BigDecimalMsg.newBuilder();
125    return builder.setBigdecimalMsg(UnsafeByteOperations.unsafeWrap(Bytes.toBytes(t))).build();
126  }
127
128  @Override
129  public BigDecimalMsg getProtoForCellType(BigDecimal t) {
130    return getProtoForType(t);
131  }
132
133  @Override
134  public BigDecimalMsg getProtoForPromotedType(BigDecimal s) {
135    return getProtoForType(s);
136  }
137
138  @Override
139  public BigDecimal getPromotedValueFromProto(BigDecimalMsg r) {
140    return Bytes.toBigDecimal(r.getBigdecimalMsg().toByteArray());
141  }
142
143  @Override
144  public BigDecimal getCellValueFromProto(BigDecimalMsg q) {
145    return Bytes.toBigDecimal(q.getBigdecimalMsg().toByteArray());
146  }
147}