blob: f091ec519c93c5f683c0ae580ef477491b4b722b [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.scan.expression;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.apache.carbondata.core.constants.CarbonCommonConstants;
import org.apache.carbondata.core.keygenerator.directdictionary.timestamp.DateDirectDictionaryGenerator;
import org.apache.carbondata.core.metadata.datatype.DataType;
import org.apache.carbondata.core.metadata.datatype.DataTypes;
import org.apache.carbondata.core.scan.expression.exception.FilterIllegalMemberException;
import org.apache.carbondata.core.util.CarbonUtil;
public class ExpressionResult implements Comparable<ExpressionResult> {
protected DataType dataType;
protected Object value;
private List<ExpressionResult> expressionResults;
private boolean isLiteral = false;
public ExpressionResult(DataType dataType, Object value) {
this.dataType = dataType;
this.value = value;
}
public ExpressionResult(DataType dataType, Object value, boolean isLiteral) {
this(dataType, value);
this.isLiteral = isLiteral;
}
public ExpressionResult(List<ExpressionResult> expressionResults) {
this.expressionResults = expressionResults;
}
public void set(DataType dataType, Object value) {
this.dataType = dataType;
this.value = value;
this.expressionResults = null;
}
public DataType getDataType() {
return dataType;
}
public Integer getInt() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
try {
return Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
throw new FilterIllegalMemberException(e);
}
} else if (dataType == DataTypes.SHORT) {
return ((Short) value).intValue();
} else if (dataType == DataTypes.INT ||
dataType == DataTypes.DOUBLE) {
if (value instanceof Double) {
return ((Double) value).intValue();
}
if (value instanceof Long) {
return ((Long) value).intValue();
}
return (Integer) value;
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return (int) (((java.sql.Date) value).getTime());
} else {
return (Integer) value;
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Timestamp) {
return (int) (((Timestamp) value).getTime());
} else {
if (isLiteral) {
Long l = (Long) value / 1000;
return l.intValue();
}
return (Integer) value;
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to integer type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Integer type value");
}
}
public Short getShort() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
try {
return Short.parseShort(value.toString());
} catch (NumberFormatException e) {
throw new FilterIllegalMemberException(e);
}
} else if (dataType == DataTypes.SHORT ||
dataType == DataTypes.INT ||
dataType == DataTypes.DOUBLE) {
if (value instanceof Double) {
return ((Double) value).shortValue();
} else if (value instanceof Integer) {
return ((Integer) value).shortValue();
}
return (Short) value;
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return (short) (((java.sql.Date) value).getTime());
} else {
return (Short) value;
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Timestamp) {
return (short) (((Timestamp) value).getTime());
} else {
if (isLiteral) {
Long l = ((long) value / 1000);
return l.shortValue();
}
return (Short) value;
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to integer type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Integer type value");
}
}
public String getString() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.DATE || dataType == DataTypes.TIMESTAMP) {
String format = CarbonUtil.getFormatFromProperty(this.getDataType());
SimpleDateFormat parser = new SimpleDateFormat(format);
if (this.getDataType() == DataTypes.DATE) {
parser.setTimeZone(TimeZone.getTimeZone("GMT"));
}
if (value instanceof Timestamp) {
return parser.format((Timestamp) value);
} else if (value instanceof java.sql.Date) {
return parser.format((java.sql.Date) value);
} else if (value instanceof Long) {
if (isLiteral) {
return parser.format(new Timestamp((long) value / 1000));
}
return parser.format(new Timestamp((long) value));
} else if (value instanceof Integer) {
long date = ((int) value) * DateDirectDictionaryGenerator.MILLIS_PER_DAY;
return parser.format(new java.sql.Date(date));
}
return value.toString();
} else {
return value.toString();
}
} catch (Exception e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to String type value");
}
}
public Double getDouble() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
try {
return Double.parseDouble(value.toString());
} catch (NumberFormatException e) {
throw new FilterIllegalMemberException(e);
}
} else if (dataType == DataTypes.SHORT) {
return ((Short) value).doubleValue();
} else if (dataType == DataTypes.INT) {
return ((Integer) value).doubleValue();
} else if (dataType == DataTypes.LONG) {
return ((Long) value).doubleValue();
} else if (dataType == DataTypes.DOUBLE) {
return (Double) value;
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return (double) ((java.sql.Date) value).getTime();
} else {
return (Double) (value);
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Timestamp) {
return (double) ((Timestamp) value).getTime();
} else {
if (isLiteral) {
Long l = (Long) value / 1000;
return l.doubleValue();
}
return (Double) (value);
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to double type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Double type value");
}
}
public Long getLong() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
try {
return Long.parseLong(value.toString());
} catch (NumberFormatException e) {
throw new FilterIllegalMemberException(e);
}
} else if (dataType == DataTypes.SHORT) {
return ((Short) value).longValue();
} else if (dataType == DataTypes.INT) {
return (Long) value;
} else if (dataType == DataTypes.LONG) {
return (Long) value;
} else if (dataType == DataTypes.DOUBLE) {
return (Long) value;
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return ((java.sql.Date) value).getTime();
} else {
return (Long) value;
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
} else {
return (Long) value;
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Long type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(e.getMessage() + " " +
"Cannot convert" + this.getDataType().getName() + " to Long type value");
}
}
//Add to judge for BigDecimal
public BigDecimal getDecimal() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
try {
return new BigDecimal(value.toString());
} catch (NumberFormatException e) {
throw new FilterIllegalMemberException(e);
}
} else if (dataType == DataTypes.SHORT) {
return new BigDecimal((short) value);
} else if (dataType == DataTypes.INT) {
return new BigDecimal((int) value);
} else if (dataType == DataTypes.LONG) {
return new BigDecimal((long) value);
} else if (dataType == DataTypes.DOUBLE || DataTypes.isDecimal(dataType)) {
return new BigDecimal(value.toString());
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return new BigDecimal(((java.sql.Date) value).getTime());
} else {
return new BigDecimal((long) value);
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Timestamp) {
return new BigDecimal(((Timestamp) value).getTime());
} else {
if (isLiteral) {
return new BigDecimal((long) value / 1000);
}
return new BigDecimal((long) value);
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Decimal type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Decimal type value");
}
}
public Long getTime() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
// Currently the query engine layer only supports yyyy-MM-dd HH:mm:ss date format
// no matter in which format the data is been stored, so while retrieving the direct
// surrogate value for filter member first it should be converted in date form as per
// above format and needs to retrieve time stamp.
SimpleDateFormat parser =
new SimpleDateFormat(CarbonCommonConstants.CARBON_TIMESTAMP_DEFAULT_FORMAT);
Date dateToStr;
try {
dateToStr = parser.parse(value.toString());
return dateToStr.getTime();
} catch (ParseException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Time type value");
}
} else if (dataType == DataTypes.SHORT) {
return ((Short) value).longValue();
} else if (dataType == DataTypes.INT || dataType == DataTypes.LONG) {
return (Long) value;
} else if (dataType == DataTypes.DOUBLE) {
return (Long) value;
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return ((Date) value).getTime();
} else {
return (Long) value;
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
} else {
if (isLiteral) {
return (Long) value / 1000;
}
return (Long) value;
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Time type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Time type value");
}
}
public Long getTimeAsMillisecond() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
// Currently the query engine layer only supports yyyy-MM-dd HH:mm:ss date format
// no matter in which format the data is been stored, so while retrieving the direct
// surrogate value for filter member first it should be converted in date form as per
// above format and needs to retrieve time stamp.
SimpleDateFormat parser =
new SimpleDateFormat(CarbonCommonConstants.CARBON_TIMESTAMP_DEFAULT_FORMAT);
Date dateToStr;
try {
dateToStr = parser.parse(value.toString());
return dateToStr.getTime();
} catch (ParseException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Time type value");
}
} else if (dataType == DataTypes.SHORT) {
return ((Short) value).longValue();
} else if (dataType == DataTypes.INT || dataType == DataTypes.LONG) {
return (Long) value;
} else if (dataType == DataTypes.DOUBLE) {
return (Long) value;
} else if (dataType == DataTypes.DATE) {
if (value instanceof java.sql.Date) {
return ((Date) value).getTime();
} else {
return (Long) value;
}
} else if (dataType == DataTypes.TIMESTAMP) {
if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
} else {
return (Long) value;
}
} else {
throw new FilterIllegalMemberException(
"Cannot convert " + this.getDataType().getName() + " to Time type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert " + this.getDataType().getName() + " to Time type value");
}
}
public Boolean getBoolean() throws FilterIllegalMemberException {
if (value == null) {
return null;
}
try {
DataType dataType = this.getDataType();
if (dataType == DataTypes.STRING) {
try {
return Boolean.parseBoolean(value.toString());
} catch (NumberFormatException e) {
throw new FilterIllegalMemberException(e);
}
} else if (dataType == DataTypes.BOOLEAN) {
return Boolean.parseBoolean(value.toString());
} else {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to boolean type value");
}
} catch (ClassCastException e) {
throw new FilterIllegalMemberException(
"Cannot convert" + this.getDataType().getName() + " to Boolean type value");
}
}
public List<ExpressionResult> getList() {
if (null == expressionResults) {
List<ExpressionResult> a = new ArrayList<ExpressionResult>(20);
a.add(new ExpressionResult(dataType, value, isLiteral));
return a;
} else {
return expressionResults;
}
}
public List<String> getListAsString() throws FilterIllegalMemberException {
List<String> evaluateResultListFinal = new ArrayList<String>(20);
List<ExpressionResult> evaluateResultList = getList();
for (ExpressionResult result : evaluateResultList) {
String resultString = result.getString();
if (resultString == null) {
evaluateResultListFinal.add(CarbonCommonConstants.MEMBER_DEFAULT_VAL);
continue;
}
evaluateResultListFinal.add(resultString);
}
return evaluateResultListFinal;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
if (null != expressionResults) {
result = prime * result + expressionResults.hashCode();
} else if (null != value) {
result = prime * result + value.toString().hashCode();
} else {
result = prime * result + "".hashCode();
}
return result;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ExpressionResult)) {
return false;
}
if (this == obj) {
return true;
}
if (getClass() != obj.getClass()) {
return false;
}
ExpressionResult objToCompare = (ExpressionResult) obj;
boolean result = false;
if (this.value == objToCompare.value) {
return true;
}
if (this.isNull() || objToCompare.isNull()) {
return false;
}
// make the comparison against the data type whose precedence is higher like
// LONG precedence is higher than INT, so from int value we should get the long value
// and then compare both the values. If done vice versa exception will be thrown
// and comparison will fail
DataType dataType = null;
if (objToCompare.getDataType().getPrecedenceOrder() < this.getDataType().getPrecedenceOrder()) {
dataType = this.getDataType();
} else {
dataType = objToCompare.getDataType();
}
try {
if (dataType == DataTypes.STRING) {
result = this.getString().equals(objToCompare.getString());
} else if (dataType == DataTypes.SHORT) {
result = this.getShort().equals(objToCompare.getShort());
} else if (dataType == DataTypes.INT) {
result = this.getInt().equals(objToCompare.getInt());
} else if (dataType == DataTypes.LONG ||
dataType == DataTypes.DATE ||
dataType == DataTypes.TIMESTAMP) {
result = this.getLong().equals(objToCompare.getLong());
} else if (dataType == DataTypes.DOUBLE) {
result = this.getDouble().equals(objToCompare.getDouble());
} else if (DataTypes.isDecimal(dataType)) {
result = this.getDecimal().equals(objToCompare.getDecimal());
}
} catch (FilterIllegalMemberException ex) {
return false;
}
return result;
}
public boolean isNull() {
return value == null;
}
@Override
public int compareTo(ExpressionResult o) {
try {
DataType type = o.dataType;
if (type == DataTypes.SHORT ||
type == DataTypes.INT ||
type == DataTypes.LONG ||
type == DataTypes.DOUBLE) {
Double d1 = this.getDouble();
Double d2 = o.getDouble();
return d1.compareTo(d2);
} else if (DataTypes.isDecimal(type)) {
java.math.BigDecimal val1 = this.getDecimal();
java.math.BigDecimal val2 = o.getDecimal();
return val1.compareTo(val2);
} else if (type == DataTypes.DATE || type == DataTypes.TIMESTAMP) {
String format = CarbonUtil.getFormatFromProperty(o.dataType);
SimpleDateFormat parser = new SimpleDateFormat(format);
Date date1 = parser.parse(this.getString());
Date date2 = parser.parse(o.getString());
return date1.compareTo(date2);
} else {
return this.getString().compareTo(o.getString());
}
} catch (ParseException | FilterIllegalMemberException e) {
return -1;
}
}
}