LargeIntLiteral.java
// 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.doris.analysis;
import org.apache.doris.catalog.PrimitiveType;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.io.Text;
import org.apache.doris.thrift.TExprNode;
import org.apache.doris.thrift.TExprNodeType;
import org.apache.doris.thrift.TLargeIntLiteral;
import com.google.gson.annotations.SerializedName;
import java.io.DataInput;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
// large int for the num that native types can not
public class LargeIntLiteral extends NumericLiteralExpr {
// -2^127
public static final BigInteger LARGE_INT_MIN = new BigInteger("-170141183460469231731687303715884105728");
// 2^127 - 1
public static final BigInteger LARGE_INT_MAX = new BigInteger("170141183460469231731687303715884105727");
// 2^127
public static final BigInteger LARGE_INT_MAX_ABS = new BigInteger("170141183460469231731687303715884105728");
@SerializedName("v")
private BigInteger value;
public LargeIntLiteral() {
super();
analysisDone();
}
public LargeIntLiteral(boolean isMax) throws AnalysisException {
super();
type = Type.LARGEINT;
value = isMax ? LARGE_INT_MAX : LARGE_INT_MIN;
analysisDone();
}
public LargeIntLiteral(BigInteger v) {
super();
type = Type.LARGEINT;
value = v;
}
public LargeIntLiteral(String value) throws AnalysisException {
super();
BigInteger bigInt;
try {
bigInt = new BigInteger(value);
// ATTN: value from 'sql_parser.y' is always be positive. for example: '-256' will to be
// 256, and for int8_t, 256 is invalid, while -256 is valid. So we check the right border
// is LARGE_INT_MAX_ABS
if (bigInt.compareTo(LARGE_INT_MIN) < 0 || bigInt.compareTo(LARGE_INT_MAX_ABS) > 0) {
throw new AnalysisException("Large int literal is out of range: " + value);
}
} catch (NumberFormatException e) {
throw new AnalysisException("Invalid integer literal: " + value, e);
}
this.value = bigInt;
type = Type.LARGEINT;
analysisDone();
}
public LargeIntLiteral(BigDecimal value) throws AnalysisException {
super();
BigInteger bigInt;
try {
bigInt = new BigInteger(value.toPlainString());
// ATTN: value from 'sql_parser.y' is always be positive. for example: '-256' will to be
// 256, and for int8_t, 256 is invalid, while -256 is valid. So we check the right border
// is LARGE_INT_MAX_ABS
if (bigInt.compareTo(LARGE_INT_MIN) < 0 || bigInt.compareTo(LARGE_INT_MAX_ABS) > 0) {
throw new AnalysisException("Large int literal is out of range: " + value);
}
} catch (NumberFormatException e) {
throw new AnalysisException("Invalid integer literal: " + value, e);
}
this.value = bigInt;
type = Type.LARGEINT;
analysisDone();
}
protected LargeIntLiteral(LargeIntLiteral other) {
super(other);
value = other.value;
}
@Override
public Expr clone() {
return new LargeIntLiteral(this);
}
public static LargeIntLiteral createMinValue() {
LargeIntLiteral largeIntLiteral = new LargeIntLiteral();
largeIntLiteral.type = Type.LARGEINT;
largeIntLiteral.value = LARGE_INT_MIN;
return largeIntLiteral;
}
@Override
public void analyzeImpl(Analyzer analyzer) throws AnalysisException {
if (value.compareTo(LARGE_INT_MIN) < 0 || value.compareTo(LARGE_INT_MAX) > 0) {
throw new AnalysisException("Number Overflow. literal: " + value);
}
}
@Override
public boolean isMinValue() {
return this.value.compareTo(LARGE_INT_MIN) == 0;
}
@Override
public BigInteger getRealValue() {
return this.value;
}
// little endian for hash code
@Override
public ByteBuffer getHashValue(PrimitiveType type) {
int buffLen = 0;
if (type == PrimitiveType.DECIMAL256) {
buffLen = 32;
} else {
buffLen = 16;
}
ByteBuffer buffer = ByteBuffer.allocate(buffLen);
buffer.order(ByteOrder.LITTLE_ENDIAN);
byte[] byteArray = value.toByteArray();
int len = byteArray.length;
int end = 0;
if (len > buffLen) {
end = len - buffLen;
}
for (int i = len - 1; i >= end; --i) {
buffer.put(byteArray[i]);
}
if (value.signum() >= 0) {
while (len++ < buffLen) {
buffer.put((byte) 0);
}
} else {
while (len++ < buffLen) {
buffer.put((byte) 0xFF);
}
}
buffer.flip();
return buffer;
}
@Override
public int compareLiteral(LiteralExpr expr) {
if (expr instanceof PlaceHolderExpr) {
return this.compareLiteral(((PlaceHolderExpr) expr).getLiteral());
}
if (expr instanceof NullLiteral) {
return 1;
}
if (expr == MaxLiteral.MAX_VALUE) {
return -1;
}
if (expr.type.equals(Type.LARGEINT)) {
return value.compareTo(((LargeIntLiteral) expr).value);
} else {
BigInteger intValue = new BigInteger(((IntLiteral) expr).getStringValue());
return value.compareTo(intValue);
}
}
@Override
public String getStringValue() {
return value.toString();
}
@Override
public long getLongValue() {
return value.longValue();
}
@Override
public double getDoubleValue() {
return value.doubleValue();
}
@Override
public String toSqlImpl() {
return getStringValue();
}
@Override
protected void toThrift(TExprNode msg) {
msg.node_type = TExprNodeType.LARGE_INT_LITERAL;
msg.large_int_literal = new TLargeIntLiteral(value.toString());
}
@Override
protected Expr uncheckedCastTo(Type targetType) throws AnalysisException {
if (targetType.isFloatingPointType()) {
return new FloatLiteral(new Double(value.doubleValue()), targetType);
} else if (targetType.isDecimalV2() || targetType.isDecimalV3()) {
DecimalLiteral res = new DecimalLiteral(new BigDecimal(value));
res.setType(targetType);
return res;
} else if (targetType.isIntegerType()) {
try {
return new IntLiteral(value.longValueExact(), targetType);
} catch (ArithmeticException e) {
throw new AnalysisException("Number out of range[" + value + "]. type: " + targetType);
}
}
return super.uncheckedCastTo(targetType);
}
@Override
public void setupParamFromBinary(ByteBuffer data, boolean isUnsigned) {
value = new BigInteger(Long.toUnsignedString(data.getLong()));
}
@Override
public void swapSign() {
// swapping sign does not change the type
value = value.negate();
}
public void readFields(DataInput in) throws IOException {
super.readFields(in);
value = new BigInteger(Text.readString(in));
}
public static LargeIntLiteral read(DataInput in) throws IOException {
LargeIntLiteral largeIntLiteral = new LargeIntLiteral();
largeIntLiteral.readFields(in);
return largeIntLiteral;
}
@Override
public int hashCode() {
return 31 * super.hashCode() + Objects.hashCode(value);
}
}