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.protobuf.generated.HBaseProtos.BigDecimalMsg;
029import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.EmptyMsg;
030import org.apache.hadoop.hbase.util.ByteStringer;
031import org.apache.hadoop.hbase.util.Bytes;
032import org.apache.yetus.audience.InterfaceAudience;
033import org.apache.yetus.audience.InterfaceStability;
034
035/**
036 * ColumnInterpreter for doing Aggregation's with BigDecimal columns. This class is required at the
037 * RegionServer also.
038 */
039@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.COPROC)
040@InterfaceStability.Evolving
041public class BigDecimalColumnInterpreter
042  extends ColumnInterpreter<BigDecimal, BigDecimal, EmptyMsg, BigDecimalMsg, BigDecimalMsg> {
043
044  @Override
045  public BigDecimal getValue(byte[] colFamily, byte[] colQualifier, Cell kv) throws IOException {
046    if (kv == null || CellUtil.cloneValue(kv) == null) {
047      return null;
048    }
049    return PrivateCellUtil.getValueAsBigDecimal(kv).setScale(2, RoundingMode.HALF_EVEN);
050  }
051
052  @Override
053  public BigDecimal add(BigDecimal bd1, BigDecimal bd2) {
054    if (bd1 == null ^ bd2 == null) {
055      return (bd1 == null) ? bd2 : bd1; // either of one is null.
056    }
057    if (bd1 == null) {
058      return null;
059    }
060    return bd1.add(bd2);
061  }
062
063  @Override
064  public int compare(final BigDecimal bd1, final BigDecimal bd2) {
065    if (bd1 == null ^ bd2 == null) {
066      return bd1 == null ? -1 : 1; // either of one is null.
067    }
068    if (bd1 == null) {
069      return 0; // both are null
070    }
071    return bd1.compareTo(bd2); // natural ordering.
072  }
073
074  @Override
075  public BigDecimal getMaxValue() {
076    return BigDecimal.valueOf(Double.MAX_VALUE);
077  }
078
079  @Override
080  public BigDecimal increment(BigDecimal bd) {
081    return bd == null ? null : bd.add(BigDecimal.ONE);
082  }
083
084  @Override
085  public BigDecimal multiply(BigDecimal bd1, BigDecimal bd2) {
086    return (bd1 == null || bd2 == null)
087      ? null
088      : bd1.multiply(bd2).setScale(2, RoundingMode.HALF_EVEN);
089  }
090
091  @Override
092  public BigDecimal getMinValue() {
093    return BigDecimal.valueOf(Double.MIN_VALUE);
094  }
095
096  @Override
097  public double divideForAvg(BigDecimal bd1, Long l2) {
098    return (l2 == null || bd1 == null) ? Double.NaN : (bd1.doubleValue() / l2.doubleValue());
099  }
100
101  @Override
102  public BigDecimal castToReturnType(BigDecimal bd) {
103    return bd;
104  }
105
106  @Override
107  public BigDecimal castToCellType(BigDecimal bd) {
108    return bd;
109  }
110
111  @Override
112  public EmptyMsg getRequestData() {
113    return EmptyMsg.getDefaultInstance();
114  }
115
116  @Override
117  public void initialize(EmptyMsg msg) {
118    // nothing
119  }
120
121  private BigDecimalMsg getProtoForType(BigDecimal t) {
122    BigDecimalMsg.Builder builder = BigDecimalMsg.newBuilder();
123    return builder.setBigdecimalMsg(ByteStringer.wrap(Bytes.toBytes(t))).build();
124  }
125
126  @Override
127  public BigDecimalMsg getProtoForCellType(BigDecimal t) {
128    return getProtoForType(t);
129  }
130
131  @Override
132  public BigDecimalMsg getProtoForPromotedType(BigDecimal s) {
133    return getProtoForType(s);
134  }
135
136  @Override
137  public BigDecimal getPromotedValueFromProto(BigDecimalMsg r) {
138    return Bytes.toBigDecimal(r.getBigdecimalMsg().toByteArray());
139  }
140
141  @Override
142  public BigDecimal getCellValueFromProto(BigDecimalMsg q) {
143    return Bytes.toBigDecimal(q.getBigdecimalMsg().toByteArray());
144  }
145}