blob: 8e41509593beed28f4be675ab17e01c6a40d0fa6 [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.iotdb.db.mpp.plan.analyze;
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.commons.path.MeasurementPath;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.path.PathPatternTree;
import org.apache.iotdb.db.exception.sql.MeasurementNotExistException;
import org.apache.iotdb.db.exception.sql.SemanticException;
import org.apache.iotdb.db.mpp.common.schematree.ISchemaTree;
import org.apache.iotdb.db.mpp.plan.expression.Expression;
import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
import org.apache.iotdb.db.mpp.plan.expression.binary.BinaryExpression;
import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
import org.apache.iotdb.db.mpp.plan.expression.leaf.LeafOperand;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
import org.apache.iotdb.db.mpp.plan.expression.ternary.BetweenExpression;
import org.apache.iotdb.db.mpp.plan.expression.ternary.TernaryExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.InExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.UnaryExpression;
import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn;
import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.filter.TimeFilter;
import org.apache.iotdb.tsfile.read.filter.basic.Filter;
import org.apache.iotdb.tsfile.read.filter.factory.FilterFactory;
import org.apache.iotdb.tsfile.utils.Pair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.cartesianProduct;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.checkConstantSatisfy;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.constructTimeFilter;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.getPairFromBetweenTimeFirst;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.getPairFromBetweenTimeSecond;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.getPairFromBetweenTimeThird;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructBinaryExpression;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructBinaryExpressions;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructFunctionExpression;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructFunctionExpressions;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructTernaryExpression;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructTernaryExpressions;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructTimeSeriesOperand;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructTimeSeriesOperands;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructUnaryExpression;
import static org.apache.iotdb.db.mpp.plan.analyze.ExpressionUtils.reconstructUnaryExpressions;
public class ExpressionAnalyzer {
/**
* Check if all suffix paths in expression are measurements or one-level wildcards, used in ALIGN
* BY DEVICE query or GroupByLevel query. If not, throw a {@link SemanticException}.
*
* @param expression expression to be checked
*/
public static void checkIsAllMeasurement(Expression expression) {
if (expression instanceof TernaryExpression) {
checkIsAllMeasurement(((TernaryExpression) expression).getFirstExpression());
checkIsAllMeasurement(((TernaryExpression) expression).getSecondExpression());
checkIsAllMeasurement(((TernaryExpression) expression).getThirdExpression());
} else if (expression instanceof BinaryExpression) {
checkIsAllMeasurement(((BinaryExpression) expression).getLeftExpression());
checkIsAllMeasurement(((BinaryExpression) expression).getRightExpression());
} else if (expression instanceof UnaryExpression) {
checkIsAllMeasurement(((UnaryExpression) expression).getExpression());
} else if (expression instanceof FunctionExpression) {
for (Expression childExpression : expression.getExpressions()) {
checkIsAllMeasurement(childExpression);
}
} else if (expression instanceof TimeSeriesOperand) {
PartialPath path = ((TimeSeriesOperand) expression).getPath();
if (path.getNodes().length > 1
|| path.getFullPath().equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) {
throw new SemanticException(
"the suffix paths can only be measurement or one-level wildcard");
}
} else if (expression instanceof TimestampOperand || expression instanceof ConstantOperand) {
// do nothing
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Identify the expression is a valid built-in aggregation function.
*
* @param expression expression to be checked
* @return true if this expression is valid
*/
public static ResultColumn.ColumnType identifyOutputColumnType(
Expression expression, boolean isRoot) {
if (expression instanceof TernaryExpression) {
ResultColumn.ColumnType firstType =
identifyOutputColumnType(((TernaryExpression) expression).getFirstExpression(), false);
ResultColumn.ColumnType secondType =
identifyOutputColumnType(((TernaryExpression) expression).getSecondExpression(), false);
ResultColumn.ColumnType thirdType =
identifyOutputColumnType(((TernaryExpression) expression).getThirdExpression(), false);
boolean rawFlag = false, aggregationFlag = false;
if (firstType == ResultColumn.ColumnType.RAW
|| secondType == ResultColumn.ColumnType.RAW
|| thirdType == ResultColumn.ColumnType.RAW) {
rawFlag = true;
}
if (firstType == ResultColumn.ColumnType.AGGREGATION
|| secondType == ResultColumn.ColumnType.AGGREGATION
|| thirdType == ResultColumn.ColumnType.AGGREGATION) {
aggregationFlag = true;
}
if (rawFlag && aggregationFlag) {
throw new SemanticException(
"Raw data and aggregation result hybrid calculation is not supported.");
}
if (firstType == ResultColumn.ColumnType.CONSTANT
&& secondType == ResultColumn.ColumnType.CONSTANT
&& thirdType == ResultColumn.ColumnType.CONSTANT) {
throw new SemanticException("Constant column is not supported.");
}
if (firstType != ResultColumn.ColumnType.CONSTANT) {
return firstType;
}
if (secondType != ResultColumn.ColumnType.CONSTANT) {
return secondType;
}
return thirdType;
} else if (expression instanceof BinaryExpression) {
ResultColumn.ColumnType leftType =
identifyOutputColumnType(((BinaryExpression) expression).getLeftExpression(), false);
ResultColumn.ColumnType rightType =
identifyOutputColumnType(((BinaryExpression) expression).getRightExpression(), false);
if ((leftType == ResultColumn.ColumnType.RAW
&& rightType == ResultColumn.ColumnType.AGGREGATION)
|| (leftType == ResultColumn.ColumnType.AGGREGATION
&& rightType == ResultColumn.ColumnType.RAW)) {
throw new SemanticException(
"Raw data and aggregation result hybrid calculation is not supported.");
}
if (isRoot
&& leftType == ResultColumn.ColumnType.CONSTANT
&& rightType == ResultColumn.ColumnType.CONSTANT) {
throw new SemanticException("Constant column is not supported.");
}
if (leftType != ResultColumn.ColumnType.CONSTANT) {
return leftType;
}
return rightType;
} else if (expression instanceof UnaryExpression) {
return identifyOutputColumnType(((UnaryExpression) expression).getExpression(), false);
} else if (expression instanceof FunctionExpression) {
List<Expression> inputExpressions = expression.getExpressions();
if (expression.isBuiltInAggregationFunctionExpression()) {
for (Expression inputExpression : inputExpressions) {
if (identifyOutputColumnType(inputExpression, false)
== ResultColumn.ColumnType.AGGREGATION) {
throw new SemanticException(
"Aggregation results cannot be as input of the aggregation function.");
}
}
return ResultColumn.ColumnType.AGGREGATION;
} else {
ResultColumn.ColumnType checkedType = null;
int lastCheckedIndex = 0;
for (int i = 0; i < inputExpressions.size(); i++) {
ResultColumn.ColumnType columnType =
identifyOutputColumnType(inputExpressions.get(i), false);
if (columnType != ResultColumn.ColumnType.CONSTANT) {
checkedType = columnType;
lastCheckedIndex = i;
break;
}
}
if (checkedType == null) {
throw new SemanticException(
String.format(
"Input of '%s' is illegal.",
((FunctionExpression) expression).getFunctionName()));
}
for (int i = lastCheckedIndex; i < inputExpressions.size(); i++) {
ResultColumn.ColumnType columnType =
identifyOutputColumnType(inputExpressions.get(i), false);
if (columnType != ResultColumn.ColumnType.CONSTANT && columnType != checkedType) {
throw new SemanticException(
String.format(
"Raw data and aggregation result hybrid input of '%s' is not supported.",
((FunctionExpression) expression).getFunctionName()));
}
}
return checkedType;
}
} else if (expression instanceof TimeSeriesOperand || expression instanceof TimestampOperand) {
return ResultColumn.ColumnType.RAW;
} else if (expression instanceof ConstantOperand) {
return ResultColumn.ColumnType.CONSTANT;
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Concat suffix path in SELECT or WITHOUT NULL clause with the prefix path in the FROM clause.
* and Construct a {@link PathPatternTree}.
*
* @param expression expression in SELECT or WITHOUT NULL clause which may include suffix paths
* @param prefixPaths prefix paths in the FROM clause
* @param patternTree a PathPatternTree contains all paths to query
* @return the concatenated expression list
*/
public static List<Expression> concatExpressionWithSuffixPaths(
Expression expression, List<PartialPath> prefixPaths, PathPatternTree patternTree) {
if (expression instanceof TernaryExpression) {
List<Expression> firstExpressions =
concatExpressionWithSuffixPaths(
((TernaryExpression) expression).getFirstExpression(), prefixPaths, patternTree);
List<Expression> secondExpressions =
concatExpressionWithSuffixPaths(
((TernaryExpression) expression).getSecondExpression(), prefixPaths, patternTree);
List<Expression> thirdExpressions =
concatExpressionWithSuffixPaths(
((TernaryExpression) expression).getThirdExpression(), prefixPaths, patternTree);
return reconstructTernaryExpressions(
expression, firstExpressions, secondExpressions, thirdExpressions);
} else if (expression instanceof BinaryExpression) {
List<Expression> leftExpressions =
concatExpressionWithSuffixPaths(
((BinaryExpression) expression).getLeftExpression(), prefixPaths, patternTree);
List<Expression> rightExpressions =
concatExpressionWithSuffixPaths(
((BinaryExpression) expression).getRightExpression(), prefixPaths, patternTree);
return reconstructBinaryExpressions(
expression.getExpressionType(), leftExpressions, rightExpressions);
} else if (expression instanceof UnaryExpression) {
List<Expression> childExpressions =
concatExpressionWithSuffixPaths(
((UnaryExpression) expression).getExpression(), prefixPaths, patternTree);
return reconstructUnaryExpressions((UnaryExpression) expression, childExpressions);
} else if (expression instanceof FunctionExpression) {
List<List<Expression>> extendedExpressions = new ArrayList<>();
for (Expression suffixExpression : expression.getExpressions()) {
extendedExpressions.add(
concatExpressionWithSuffixPaths(suffixExpression, prefixPaths, patternTree));
}
List<List<Expression>> childExpressionsList = new ArrayList<>();
cartesianProduct(extendedExpressions, childExpressionsList, 0, new ArrayList<>());
return reconstructFunctionExpressions((FunctionExpression) expression, childExpressionsList);
} else if (expression instanceof TimeSeriesOperand) {
PartialPath rawPath = ((TimeSeriesOperand) expression).getPath();
List<PartialPath> actualPaths = new ArrayList<>();
if (rawPath.getFullPath().startsWith(SQLConstant.ROOT + TsFileConstant.PATH_SEPARATOR)) {
actualPaths.add(rawPath);
patternTree.appendPathPattern(rawPath);
} else {
for (PartialPath prefixPath : prefixPaths) {
PartialPath concatPath = prefixPath.concatPath(rawPath);
patternTree.appendPathPattern(concatPath);
actualPaths.add(concatPath);
}
}
return reconstructTimeSeriesOperands(actualPaths);
} else if (expression instanceof TimestampOperand) {
return Collections.singletonList(expression);
} else if (expression instanceof ConstantOperand) {
return Collections.singletonList(expression);
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Concat suffix path in SELECT or WITHOUT NULL clause with the prefix path in the FROM clause.
*
* @param expression expression in SELECT or WITHOUT NULL clause which may include suffix paths
* @param prefixPaths prefix paths in the FROM clause
* @return the concatenated partialPath list
*/
public static List<PartialPath> concatExpressionWithSuffixPaths(
Expression expression, List<PartialPath> prefixPaths) {
Set<PartialPath> resultPaths = new HashSet<>();
if (expression instanceof TernaryExpression) {
List<PartialPath> firstExpressions =
concatExpressionWithSuffixPaths(
((TernaryExpression) expression).getFirstExpression(), prefixPaths);
List<PartialPath> secondExpressions =
concatExpressionWithSuffixPaths(
((TernaryExpression) expression).getSecondExpression(), prefixPaths);
List<PartialPath> thirdExpressions =
concatExpressionWithSuffixPaths(
((TernaryExpression) expression).getThirdExpression(), prefixPaths);
resultPaths.addAll(firstExpressions);
resultPaths.addAll(secondExpressions);
resultPaths.addAll(thirdExpressions);
return new ArrayList<>(resultPaths);
} else if (expression instanceof BinaryExpression) {
List<PartialPath> leftExpressions =
concatExpressionWithSuffixPaths(
((BinaryExpression) expression).getLeftExpression(), prefixPaths);
List<PartialPath> rightExpressions =
concatExpressionWithSuffixPaths(
((BinaryExpression) expression).getRightExpression(), prefixPaths);
resultPaths.addAll(leftExpressions);
resultPaths.addAll(rightExpressions);
return new ArrayList<>(resultPaths);
} else if (expression instanceof UnaryExpression) {
List<PartialPath> childExpressions =
concatExpressionWithSuffixPaths(
((UnaryExpression) expression).getExpression(), prefixPaths);
resultPaths.addAll(childExpressions);
return new ArrayList<>(resultPaths);
} else if (expression instanceof FunctionExpression) {
for (Expression suffixExpression : expression.getExpressions()) {
resultPaths.addAll(concatExpressionWithSuffixPaths(suffixExpression, prefixPaths));
}
return new ArrayList<>(resultPaths);
} else if (expression instanceof TimeSeriesOperand) {
PartialPath rawPath = ((TimeSeriesOperand) expression).getPath();
List<PartialPath> actualPaths = new ArrayList<>();
if (rawPath.getFullPath().startsWith(SQLConstant.ROOT + TsFileConstant.PATH_SEPARATOR)) {
actualPaths.add(rawPath);
} else {
for (PartialPath prefixPath : prefixPaths) {
PartialPath concatPath = prefixPath.concatPath(rawPath);
actualPaths.add(concatPath);
}
}
return actualPaths;
} else if (expression instanceof TimestampOperand || expression instanceof ConstantOperand) {
return new ArrayList<>();
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Concat suffix path in WHERE clause with the prefix path in the FROM clause and Construct a
* {@link PathPatternTree}. This method return void, i.e. will not rewrite the statement.
*
* @param predicate expression in WHERE clause
* @param prefixPaths prefix paths in the FROM clause
* @param patternTree a PathPatternTree contains all paths to query
*/
public static void constructPatternTreeFromExpression(
Expression predicate, List<PartialPath> prefixPaths, PathPatternTree patternTree) {
if (predicate instanceof TernaryExpression) {
constructPatternTreeFromExpression(
((TernaryExpression) predicate).getFirstExpression(), prefixPaths, patternTree);
constructPatternTreeFromExpression(
((TernaryExpression) predicate).getSecondExpression(), prefixPaths, patternTree);
constructPatternTreeFromExpression(
((TernaryExpression) predicate).getThirdExpression(), prefixPaths, patternTree);
} else if (predicate instanceof BinaryExpression) {
constructPatternTreeFromExpression(
((BinaryExpression) predicate).getLeftExpression(), prefixPaths, patternTree);
constructPatternTreeFromExpression(
((BinaryExpression) predicate).getRightExpression(), prefixPaths, patternTree);
} else if (predicate instanceof UnaryExpression) {
constructPatternTreeFromExpression(
((UnaryExpression) predicate).getExpression(), prefixPaths, patternTree);
} else if (predicate instanceof FunctionExpression) {
for (Expression suffixExpression : predicate.getExpressions()) {
constructPatternTreeFromExpression(suffixExpression, prefixPaths, patternTree);
}
} else if (predicate instanceof TimeSeriesOperand) {
PartialPath rawPath = ((TimeSeriesOperand) predicate).getPath();
if (rawPath.getFullPath().startsWith(SQLConstant.ROOT + TsFileConstant.PATH_SEPARATOR)) {
patternTree.appendPathPattern(rawPath);
return;
}
for (PartialPath prefixPath : prefixPaths) {
PartialPath concatPath = prefixPath.concatPath(rawPath);
patternTree.appendPathPattern(concatPath);
}
} else if (predicate instanceof TimestampOperand || predicate instanceof ConstantOperand) {
// do nothing
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + predicate.getExpressionType());
}
}
/**
* Bind schema ({@link PartialPath} -> {@link MeasurementPath}) and removes wildcards in
* Expression.
*
* @param schemaTree interface for querying schema information
* @return the expression list after binding schema
*/
public static List<Expression> removeWildcardInExpression(
Expression expression, ISchemaTree schemaTree) {
if (expression instanceof TernaryExpression) {
List<Expression> firstExpressions =
removeWildcardInExpression(
((TernaryExpression) expression).getFirstExpression(), schemaTree);
List<Expression> secondExpressions =
removeWildcardInExpression(
((TernaryExpression) expression).getSecondExpression(), schemaTree);
List<Expression> thirdExpressions =
removeWildcardInExpression(
((TernaryExpression) expression).getThirdExpression(), schemaTree);
return reconstructTernaryExpressions(
expression, firstExpressions, secondExpressions, thirdExpressions);
} else if (expression instanceof BinaryExpression) {
List<Expression> leftExpressions =
removeWildcardInExpression(
((BinaryExpression) expression).getLeftExpression(), schemaTree);
List<Expression> rightExpressions =
removeWildcardInExpression(
((BinaryExpression) expression).getRightExpression(), schemaTree);
return reconstructBinaryExpressions(
expression.getExpressionType(), leftExpressions, rightExpressions);
} else if (expression instanceof UnaryExpression) {
List<Expression> childExpressions =
removeWildcardInExpression(((UnaryExpression) expression).getExpression(), schemaTree);
return reconstructUnaryExpressions((UnaryExpression) expression, childExpressions);
} else if (expression instanceof FunctionExpression) {
// One by one, remove the wildcards from the input expressions. In most cases, an expression
// will produce multiple expressions after removing the wildcards. We use extendedExpressions
// to collect the produced expressions.
List<List<Expression>> extendedExpressions = new ArrayList<>();
for (Expression originExpression : expression.getExpressions()) {
List<Expression> actualExpressions =
removeWildcardInExpression(originExpression, schemaTree);
if (actualExpressions.isEmpty()) {
// Let's ignore the eval of the function which has at least one non-existence series as
// input. See IOTDB-1212: https://github.com/apache/iotdb/pull/3101
return Collections.emptyList();
}
extendedExpressions.add(actualExpressions);
}
// Calculate the Cartesian product of extendedExpressions to get the actual expressions after
// removing all wildcards. We use actualExpressions to collect them.
List<List<Expression>> childExpressionsList = new ArrayList<>();
cartesianProduct(extendedExpressions, childExpressionsList, 0, new ArrayList<>());
return reconstructFunctionExpressions((FunctionExpression) expression, childExpressionsList);
} else if (expression instanceof TimeSeriesOperand) {
PartialPath path = ((TimeSeriesOperand) expression).getPath();
List<MeasurementPath> actualPaths = schemaTree.searchMeasurementPaths(path).left;
return reconstructTimeSeriesOperands(actualPaths);
} else if (expression instanceof TimestampOperand) {
return Collections.singletonList(expression);
} else if (expression instanceof ConstantOperand) {
return Collections.singletonList(expression);
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Concat suffix path in WHERE and HAVING clause with the prefix path in the FROM clause. And
* then, bind schema ({@link PartialPath} -> {@link MeasurementPath}) and removes wildcards in
* Expression.
*
* @param prefixPaths prefix paths in the FROM clause
* @param schemaTree interface for querying schema information
* @return the expression list with full path and after binding schema
*/
public static List<Expression> removeWildcardInFilter(
Expression predicate,
List<PartialPath> prefixPaths,
ISchemaTree schemaTree,
boolean isWhere) {
if (predicate instanceof TernaryExpression) {
List<Expression> firstExpressions =
removeWildcardInFilter(
((TernaryExpression) predicate).getFirstExpression(),
prefixPaths,
schemaTree,
isWhere);
List<Expression> secondExpressions =
removeWildcardInFilter(
((TernaryExpression) predicate).getSecondExpression(),
prefixPaths,
schemaTree,
isWhere);
List<Expression> thirdExpressions =
removeWildcardInFilter(
((TernaryExpression) predicate).getThirdExpression(),
prefixPaths,
schemaTree,
isWhere);
return reconstructTernaryExpressions(
predicate, firstExpressions, secondExpressions, thirdExpressions);
} else if (predicate instanceof BinaryExpression) {
List<Expression> leftExpressions =
removeWildcardInFilter(
((BinaryExpression) predicate).getLeftExpression(), prefixPaths, schemaTree, isWhere);
List<Expression> rightExpressions =
removeWildcardInFilter(
((BinaryExpression) predicate).getRightExpression(),
prefixPaths,
schemaTree,
isWhere);
if (predicate.getExpressionType() == ExpressionType.LOGIC_AND) {
List<Expression> resultExpressions = new ArrayList<>(leftExpressions);
resultExpressions.addAll(rightExpressions);
return resultExpressions;
}
return reconstructBinaryExpressions(
predicate.getExpressionType(), leftExpressions, rightExpressions);
} else if (predicate instanceof UnaryExpression) {
List<Expression> childExpressions =
removeWildcardInFilter(
((UnaryExpression) predicate).getExpression(), prefixPaths, schemaTree, isWhere);
return reconstructUnaryExpressions((UnaryExpression) predicate, childExpressions);
} else if (predicate instanceof FunctionExpression) {
if (predicate.isBuiltInAggregationFunctionExpression() && isWhere) {
throw new SemanticException("aggregate functions are not supported in WHERE clause");
}
List<List<Expression>> extendedExpressions = new ArrayList<>();
for (Expression suffixExpression : predicate.getExpressions()) {
extendedExpressions.add(
removeWildcardInFilter(suffixExpression, prefixPaths, schemaTree, isWhere));
}
List<List<Expression>> childExpressionsList = new ArrayList<>();
cartesianProduct(extendedExpressions, childExpressionsList, 0, new ArrayList<>());
return reconstructFunctionExpressions((FunctionExpression) predicate, childExpressionsList);
} else if (predicate instanceof TimeSeriesOperand) {
PartialPath filterPath = ((TimeSeriesOperand) predicate).getPath();
List<PartialPath> concatPaths = new ArrayList<>();
if (!filterPath.getFirstNode().equals(SQLConstant.ROOT)) {
prefixPaths.forEach(prefix -> concatPaths.add(prefix.concatPath(filterPath)));
} else {
// do nothing in the case of "where root.d1.s1 > 5"
concatPaths.add(filterPath);
}
List<PartialPath> noStarPaths = new ArrayList<>();
for (PartialPath concatPath : concatPaths) {
List<MeasurementPath> actualPaths = schemaTree.searchMeasurementPaths(concatPath).left;
if (actualPaths.size() == 0) {
throw new SemanticException(
String.format(
"the path '%s' in %s clause does not exist",
concatPath, isWhere ? "WHERE" : "HAVING"));
}
noStarPaths.addAll(actualPaths);
}
return reconstructTimeSeriesOperands(noStarPaths);
} else if (predicate instanceof TimestampOperand) {
// do nothing in the case of "where time > 5"
return Collections.singletonList(predicate);
} else if (predicate instanceof ConstantOperand) {
return Collections.singletonList(predicate);
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + predicate.getExpressionType());
}
}
public static Expression replaceRawPathWithGroupedPath(
Expression predicate, Map<Expression, Expression> rawPathToGroupedPathMapInHaving) {
if (predicate instanceof TernaryExpression) {
Expression firstExpression =
replaceRawPathWithGroupedPath(
((TernaryExpression) predicate).getFirstExpression(),
rawPathToGroupedPathMapInHaving);
Expression secondExpression =
replaceRawPathWithGroupedPath(
((TernaryExpression) predicate).getSecondExpression(),
rawPathToGroupedPathMapInHaving);
Expression thirdExpression =
replaceRawPathWithGroupedPath(
((TernaryExpression) predicate).getThirdExpression(),
rawPathToGroupedPathMapInHaving);
return reconstructTernaryExpression(
predicate, firstExpression, secondExpression, thirdExpression);
} else if (predicate instanceof BinaryExpression) {
Expression leftExpression =
replaceRawPathWithGroupedPath(
((BinaryExpression) predicate).getLeftExpression(), rawPathToGroupedPathMapInHaving);
Expression rightExpression =
replaceRawPathWithGroupedPath(
((BinaryExpression) predicate).getRightExpression(), rawPathToGroupedPathMapInHaving);
return reconstructBinaryExpression(
predicate.getExpressionType(), leftExpression, rightExpression);
} else if (predicate instanceof UnaryExpression) {
Expression expression =
replaceRawPathWithGroupedPath(
((UnaryExpression) predicate).getExpression(), rawPathToGroupedPathMapInHaving);
return reconstructUnaryExpression((UnaryExpression) predicate, expression);
} else if (predicate instanceof FunctionExpression) {
List<Expression> expressions = predicate.getExpressions();
List<Expression> childrenExpressions = new ArrayList<>();
for (Expression expression : expressions) {
childrenExpressions.add(
replaceRawPathWithGroupedPath(expression, rawPathToGroupedPathMapInHaving));
}
return reconstructFunctionExpression((FunctionExpression) predicate, childrenExpressions);
} else if (predicate instanceof TimeSeriesOperand) {
PartialPath groupedPath =
((TimeSeriesOperand) rawPathToGroupedPathMapInHaving.get(predicate)).getPath();
return reconstructTimeSeriesOperand(groupedPath);
} else if (predicate instanceof TimestampOperand || predicate instanceof ConstantOperand) {
return predicate;
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + predicate.getExpressionType());
}
}
/**
* Concat expression with the device path in the FROM clause.And then, bind schema ({@link
* PartialPath} -> {@link MeasurementPath}) and removes wildcards in Expression. This method used
* in ALIGN BY DEVICE query.
*
* @param devicePath device path in the FROM clause
* @return expression list with full path and after binding schema
*/
public static List<Expression> concatDeviceAndRemoveWildcard(
Expression expression, PartialPath devicePath, ISchemaTree schemaTree) {
if (expression instanceof TernaryExpression) {
List<Expression> firstExpressions =
concatDeviceAndRemoveWildcard(
((TernaryExpression) expression).getFirstExpression(), devicePath, schemaTree);
List<Expression> secondExpressions =
concatDeviceAndRemoveWildcard(
((TernaryExpression) expression).getSecondExpression(), devicePath, schemaTree);
List<Expression> thirdExpressions =
concatDeviceAndRemoveWildcard(
((TernaryExpression) expression).getThirdExpression(), devicePath, schemaTree);
return reconstructTernaryExpressions(
expression, firstExpressions, secondExpressions, thirdExpressions);
} else if (expression instanceof BinaryExpression) {
List<Expression> leftExpressions =
concatDeviceAndRemoveWildcard(
((BinaryExpression) expression).getLeftExpression(), devicePath, schemaTree);
List<Expression> rightExpressions =
concatDeviceAndRemoveWildcard(
((BinaryExpression) expression).getRightExpression(), devicePath, schemaTree);
return reconstructBinaryExpressions(
expression.getExpressionType(), leftExpressions, rightExpressions);
} else if (expression instanceof UnaryExpression) {
List<Expression> childExpressions =
concatDeviceAndRemoveWildcard(
((UnaryExpression) expression).getExpression(), devicePath, schemaTree);
return reconstructUnaryExpressions((UnaryExpression) expression, childExpressions);
} else if (expression instanceof FunctionExpression) {
List<List<Expression>> extendedExpressions = new ArrayList<>();
for (Expression suffixExpression : expression.getExpressions()) {
List<Expression> concatedExpression =
concatDeviceAndRemoveWildcard(suffixExpression, devicePath, schemaTree);
if (concatedExpression != null && concatedExpression.size() != 0) {
extendedExpressions.add(concatedExpression);
}
}
List<List<Expression>> childExpressionsList = new ArrayList<>();
cartesianProduct(extendedExpressions, childExpressionsList, 0, new ArrayList<>());
return reconstructFunctionExpressions((FunctionExpression) expression, childExpressionsList);
} else if (expression instanceof TimeSeriesOperand) {
PartialPath measurement = ((TimeSeriesOperand) expression).getPath();
PartialPath concatPath = devicePath.concatPath(measurement);
List<MeasurementPath> actualPaths = schemaTree.searchMeasurementPaths(concatPath).left;
if (actualPaths.isEmpty()) {
return new ArrayList<>();
}
List<PartialPath> noStarPaths = new ArrayList<>(actualPaths);
return reconstructTimeSeriesOperands(noStarPaths);
} else if (expression instanceof TimestampOperand) {
// do nothing in the case of "where time > 5"
return Collections.singletonList(expression);
} else if (expression instanceof ConstantOperand) {
return Collections.singletonList(expression);
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Concat measurement in WHERE and HAVING clause with device path. And then, bind schema ({@link
* PartialPath} -> {@link MeasurementPath}) and removes wildcards.
*
* @return the expression list with full path and after binding schema
*/
public static List<Expression> removeWildcardInFilterByDevice(
Expression predicate, PartialPath devicePath, ISchemaTree schemaTree, boolean isWhere) {
if (predicate instanceof TernaryExpression) {
List<Expression> firstExpressions =
removeWildcardInFilterByDevice(
((TernaryExpression) predicate).getFirstExpression(),
devicePath,
schemaTree,
isWhere);
List<Expression> secondExpressions =
removeWildcardInFilterByDevice(
((TernaryExpression) predicate).getSecondExpression(),
devicePath,
schemaTree,
isWhere);
List<Expression> thirdExpressions =
removeWildcardInFilterByDevice(
((TernaryExpression) predicate).getThirdExpression(),
devicePath,
schemaTree,
isWhere);
return reconstructTernaryExpressions(
predicate, firstExpressions, secondExpressions, thirdExpressions);
} else if (predicate instanceof BinaryExpression) {
List<Expression> leftExpressions =
removeWildcardInFilterByDevice(
((BinaryExpression) predicate).getLeftExpression(), devicePath, schemaTree, isWhere);
List<Expression> rightExpressions =
removeWildcardInFilterByDevice(
((BinaryExpression) predicate).getRightExpression(), devicePath, schemaTree, isWhere);
if (predicate.getExpressionType() == ExpressionType.LOGIC_AND) {
List<Expression> resultExpressions = new ArrayList<>(leftExpressions);
resultExpressions.addAll(rightExpressions);
return resultExpressions;
}
return reconstructBinaryExpressions(
predicate.getExpressionType(), leftExpressions, rightExpressions);
} else if (predicate instanceof UnaryExpression) {
List<Expression> childExpressions =
removeWildcardInFilterByDevice(
((UnaryExpression) predicate).getExpression(), devicePath, schemaTree, isWhere);
return reconstructUnaryExpressions((UnaryExpression) predicate, childExpressions);
} else if (predicate instanceof FunctionExpression) {
if (predicate.isBuiltInAggregationFunctionExpression() && isWhere) {
throw new SemanticException("aggregate functions are not supported in WHERE clause");
}
List<List<Expression>> extendedExpressions = new ArrayList<>();
for (Expression suffixExpression : predicate.getExpressions()) {
extendedExpressions.add(
removeWildcardInFilterByDevice(suffixExpression, devicePath, schemaTree, isWhere));
}
List<List<Expression>> childExpressionsList = new ArrayList<>();
cartesianProduct(extendedExpressions, childExpressionsList, 0, new ArrayList<>());
return reconstructFunctionExpressions((FunctionExpression) predicate, childExpressionsList);
} else if (predicate instanceof TimeSeriesOperand) {
PartialPath measurement = ((TimeSeriesOperand) predicate).getPath();
PartialPath concatPath = devicePath.concatPath(measurement);
List<MeasurementPath> noStarPaths = schemaTree.searchMeasurementPaths(concatPath).left;
if (noStarPaths.size() == 0) {
throw new MeasurementNotExistException(
String.format(
"ALIGN BY DEVICE: Measurement '%s' does not exist in device '%s'",
measurement, devicePath));
}
return reconstructTimeSeriesOperands(noStarPaths);
} else if (predicate instanceof TimestampOperand) {
// do nothing in the case of "where time > 5"
return Collections.singletonList(predicate);
} else if (predicate instanceof ConstantOperand) {
return Collections.singletonList(predicate);
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + predicate.getExpressionType());
}
}
/**
* Extract global time filter from query filter.
*
* @param predicate raw query filter
* @param canRewrite determined by the father of current expression
* @param isFirstOr whether it is the first LogicOrExpression encountered
* @return global time filter
*/
public static Pair<Filter, Boolean> transformToGlobalTimeFilter(
Expression predicate, boolean canRewrite, boolean isFirstOr) {
if (predicate.getExpressionType().equals(ExpressionType.LOGIC_AND)) {
Pair<Filter, Boolean> leftResultPair =
transformToGlobalTimeFilter(
((BinaryExpression) predicate).getLeftExpression(), canRewrite, isFirstOr);
Pair<Filter, Boolean> rightResultPair =
transformToGlobalTimeFilter(
((BinaryExpression) predicate).getRightExpression(), canRewrite, isFirstOr);
// rewrite predicate to avoid duplicate calculation on time filter
// If Left-child or Right-child does not contain value filter
// We can set it to true in Predicate Tree
if (canRewrite) {
if (leftResultPair.left != null && !leftResultPair.right) {
((BinaryExpression) predicate)
.setLeftExpression(new ConstantOperand(TSDataType.BOOLEAN, "true"));
}
if (rightResultPair.left != null && !rightResultPair.right) {
((BinaryExpression) predicate)
.setRightExpression(new ConstantOperand(TSDataType.BOOLEAN, "true"));
}
}
if (leftResultPair.left != null && rightResultPair.left != null) {
return new Pair<>(
FilterFactory.and(leftResultPair.left, rightResultPair.left),
leftResultPair.right || rightResultPair.right);
} else if (leftResultPair.left != null) {
return new Pair<>(leftResultPair.left, true);
} else if (rightResultPair.left != null) {
return new Pair<>(rightResultPair.left, true);
}
return new Pair<>(null, true);
} else if (predicate.getExpressionType().equals(ExpressionType.LOGIC_OR)) {
Pair<Filter, Boolean> leftResultPair =
transformToGlobalTimeFilter(
((BinaryExpression) predicate).getLeftExpression(), false, false);
Pair<Filter, Boolean> rightResultPair =
transformToGlobalTimeFilter(
((BinaryExpression) predicate).getRightExpression(), false, false);
if (leftResultPair.left != null && rightResultPair.left != null) {
if (isFirstOr && !leftResultPair.right && !rightResultPair.right) {
((BinaryExpression) predicate)
.setLeftExpression(new ConstantOperand(TSDataType.BOOLEAN, "true"));
((BinaryExpression) predicate)
.setRightExpression(new ConstantOperand(TSDataType.BOOLEAN, "true"));
}
return new Pair<>(
FilterFactory.or(leftResultPair.left, rightResultPair.left),
leftResultPair.right || rightResultPair.right);
}
return new Pair<>(null, true);
} else if (predicate.getExpressionType().equals(ExpressionType.LOGIC_NOT)) {
Pair<Filter, Boolean> childResultPair =
transformToGlobalTimeFilter(
((UnaryExpression) predicate).getExpression(), canRewrite, isFirstOr);
return new Pair<>(FilterFactory.not(childResultPair.left), childResultPair.right);
} else if (predicate.isCompareBinaryExpression()) {
Filter timeInLeftFilter =
constructTimeFilter(
predicate.getExpressionType(),
((BinaryExpression) predicate).getLeftExpression(),
((BinaryExpression) predicate).getRightExpression());
if (timeInLeftFilter != null) {
return new Pair<>(timeInLeftFilter, false);
}
Filter timeInRightFilter =
constructTimeFilter(
predicate.getExpressionType(),
((BinaryExpression) predicate).getRightExpression(),
((BinaryExpression) predicate).getLeftExpression());
if (timeInRightFilter != null) {
return new Pair<>(timeInRightFilter, false);
}
return new Pair<>(null, true);
} else if (predicate.getExpressionType().equals(ExpressionType.LIKE)
|| predicate.getExpressionType().equals(ExpressionType.REGEXP)) {
return new Pair<>(null, true);
} else if (predicate.getExpressionType().equals(ExpressionType.BETWEEN)) {
Expression firstExpression = ((TernaryExpression) predicate).getFirstExpression();
Expression secondExpression = ((TernaryExpression) predicate).getSecondExpression();
Expression thirdExpression = ((TernaryExpression) predicate).getThirdExpression();
if (firstExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
return getPairFromBetweenTimeFirst(
secondExpression, thirdExpression, ((BetweenExpression) predicate).isNotBetween());
} else if (secondExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
if (checkConstantSatisfy(firstExpression, thirdExpression)) {
return getPairFromBetweenTimeSecond((BetweenExpression) predicate, firstExpression);
} else {
return new Pair<>(null, true); // TODO return Filter.True/False
}
} else if (thirdExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
if (checkConstantSatisfy(secondExpression, firstExpression)) {
return getPairFromBetweenTimeThird((BetweenExpression) predicate, firstExpression);
} else {
return new Pair<>(null, true); // TODO return Filter.True/False
}
}
return new Pair<>(null, true);
} else if (predicate.getExpressionType().equals(ExpressionType.IS_NULL)) {
return new Pair<>(null, true);
} else if (predicate.getExpressionType().equals(ExpressionType.IN)) {
Expression timeExpression = ((InExpression) predicate).getExpression();
if (timeExpression.getExpressionType().equals(ExpressionType.TIMESTAMP)) {
return new Pair<>(
TimeFilter.in(
((InExpression) predicate)
.getValues().stream().map(Long::parseLong).collect(Collectors.toSet()),
((InExpression) predicate).isNotIn()),
false);
}
return new Pair<>(null, true);
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + predicate.getExpressionType());
}
}
/**
* Search for subexpressions that can be queried natively, including time series raw data and
* built-in aggregate functions.
*
* @param expression expression to be searched
* @param isRawDataSource if true, built-in aggregate functions are not be returned
* @return searched subexpression list
*/
public static List<Expression> searchSourceExpressions(
Expression expression, boolean isRawDataSource) {
if (expression instanceof TernaryExpression) {
List<Expression> resultExpressions = new ArrayList<>();
resultExpressions.addAll(
searchSourceExpressions(
((TernaryExpression) expression).getFirstExpression(), isRawDataSource));
resultExpressions.addAll(
searchSourceExpressions(
((TernaryExpression) expression).getSecondExpression(), isRawDataSource));
resultExpressions.addAll(
searchSourceExpressions(
((TernaryExpression) expression).getThirdExpression(), isRawDataSource));
return resultExpressions;
} else if (expression instanceof BinaryExpression) {
List<Expression> resultExpressions = new ArrayList<>();
resultExpressions.addAll(
searchSourceExpressions(
((BinaryExpression) expression).getLeftExpression(), isRawDataSource));
resultExpressions.addAll(
searchSourceExpressions(
((BinaryExpression) expression).getRightExpression(), isRawDataSource));
return resultExpressions;
} else if (expression instanceof UnaryExpression) {
return searchSourceExpressions(
((UnaryExpression) expression).getExpression(), isRawDataSource);
} else if (expression instanceof FunctionExpression) {
if (!isRawDataSource && expression.isBuiltInAggregationFunctionExpression()) {
return Collections.singletonList(expression);
}
List<Expression> resultExpressions = new ArrayList<>();
for (Expression childExpression : expression.getExpressions()) {
resultExpressions.addAll(searchSourceExpressions(childExpression, isRawDataSource));
}
return resultExpressions;
} else if (expression instanceof TimeSeriesOperand) {
return Collections.singletonList(expression);
} else if (expression instanceof TimestampOperand || expression instanceof ConstantOperand) {
return Collections.emptyList();
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Search for built-in aggregate functions subexpressions.
*
* @param expression expression to be searched
* @return searched aggregate functions list
*/
public static List<Expression> searchAggregationExpressions(Expression expression) {
if (expression instanceof TernaryExpression) {
List<Expression> resultExpressions = new ArrayList<>();
resultExpressions.addAll(
searchAggregationExpressions(((TernaryExpression) expression).getFirstExpression()));
resultExpressions.addAll(
searchAggregationExpressions(((TernaryExpression) expression).getSecondExpression()));
resultExpressions.addAll(
searchAggregationExpressions(((TernaryExpression) expression).getThirdExpression()));
return resultExpressions;
} else if (expression instanceof BinaryExpression) {
List<Expression> resultExpressions = new ArrayList<>();
resultExpressions.addAll(
searchAggregationExpressions(((BinaryExpression) expression).getLeftExpression()));
resultExpressions.addAll(
searchAggregationExpressions(((BinaryExpression) expression).getRightExpression()));
return resultExpressions;
} else if (expression instanceof UnaryExpression) {
return searchAggregationExpressions(((UnaryExpression) expression).getExpression());
} else if (expression instanceof FunctionExpression) {
if (expression.isBuiltInAggregationFunctionExpression()) {
return Collections.singletonList(expression);
}
List<Expression> resultExpressions = new ArrayList<>();
for (Expression inputExpression : expression.getExpressions()) {
resultExpressions.addAll(searchAggregationExpressions(inputExpression));
}
return resultExpressions;
} else if (expression instanceof LeafOperand) {
return Collections.emptyList();
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/**
* Remove alias from expression. eg: root.sg.d1.status + 1 -> root.sg.d1.s2 + 1, and reconstruct
* the name of FunctionExpression to lowercase.
*
* @return expression after removing alias
*/
public static Expression removeAliasFromExpression(Expression expression) {
if (expression instanceof TernaryExpression) {
Expression firstExpression =
removeAliasFromExpression(((TernaryExpression) expression).getFirstExpression());
Expression secondExpression =
removeAliasFromExpression(((TernaryExpression) expression).getSecondExpression());
Expression thirdExpression =
removeAliasFromExpression(((TernaryExpression) expression).getThirdExpression());
return reconstructTernaryExpressions(
expression,
Collections.singletonList(firstExpression),
Collections.singletonList(secondExpression),
Collections.singletonList(thirdExpression))
.get(0);
} else if (expression instanceof BinaryExpression) {
Expression leftExpression =
removeAliasFromExpression(((BinaryExpression) expression).getLeftExpression());
Expression rightExpression =
removeAliasFromExpression(((BinaryExpression) expression).getRightExpression());
return reconstructBinaryExpressions(
expression.getExpressionType(),
Collections.singletonList(leftExpression),
Collections.singletonList(rightExpression))
.get(0);
} else if (expression instanceof UnaryExpression) {
Expression childExpression =
removeAliasFromExpression(((UnaryExpression) expression).getExpression());
return reconstructUnaryExpressions(
(UnaryExpression) expression, Collections.singletonList(childExpression))
.get(0);
} else if (expression instanceof FunctionExpression) {
FunctionExpression functionExpression = (FunctionExpression) expression;
List<Expression> childExpressions = new ArrayList<>();
for (Expression suffixExpression : expression.getExpressions()) {
childExpressions.add(removeAliasFromExpression(suffixExpression));
}
// Reconstruct the function name to lower case to finish the calculation afterwards while the
// origin name will be only as output name
return new FunctionExpression(
functionExpression.getFunctionName().toLowerCase(),
functionExpression.getFunctionAttributes(),
childExpressions);
} else if (expression instanceof TimeSeriesOperand) {
PartialPath rawPath = ((TimeSeriesOperand) expression).getPath();
if (rawPath.isMeasurementAliasExists()) {
MeasurementPath measurementPath = (MeasurementPath) rawPath;
MeasurementPath newPath =
new MeasurementPath(measurementPath, measurementPath.getMeasurementSchema());
newPath.setUnderAlignedEntity(measurementPath.isUnderAlignedEntity());
return new TimeSeriesOperand(newPath);
}
return expression;
} else if (expression instanceof ConstantOperand || expression instanceof TimestampOperand) {
// do nothing
return expression;
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/** Check for arithmetic expression, logical expression, UDF. Returns true if it exists. */
public static boolean checkIsNeedTransform(Expression expression) {
if (expression instanceof TernaryExpression) {
return true;
} else if (expression instanceof BinaryExpression) {
return true;
} else if (expression instanceof UnaryExpression) {
return true;
} else if (expression instanceof FunctionExpression) {
return !expression.isBuiltInAggregationFunctionExpression();
} else if (expression instanceof TimeSeriesOperand) {
return false;
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Method can only be used in source expression
/////////////////////////////////////////////////////////////////////////////////////////////////
public static String getDeviceNameInSourceExpression(Expression expression) {
if (expression instanceof TernaryExpression) {
String DeviceName =
getDeviceNameInSourceExpression(((TernaryExpression) expression).getFirstExpression());
if (DeviceName == null) {
DeviceName =
getDeviceNameInSourceExpression(((TernaryExpression) expression).getSecondExpression());
}
if (DeviceName == null) {
DeviceName =
getDeviceNameInSourceExpression(((TernaryExpression) expression).getThirdExpression());
}
return DeviceName;
} else if (expression instanceof BinaryExpression) {
String leftDeviceName =
getDeviceNameInSourceExpression(((BinaryExpression) expression).getLeftExpression());
if (leftDeviceName != null) {
return leftDeviceName;
}
return getDeviceNameInSourceExpression(((BinaryExpression) expression).getRightExpression());
} else if (expression instanceof UnaryExpression) {
return getDeviceNameInSourceExpression(((UnaryExpression) expression).getExpression());
} else if (expression instanceof TimeSeriesOperand) {
return ((TimeSeriesOperand) expression).getPath().getDevice();
} else if (expression instanceof FunctionExpression) {
return getDeviceNameInSourceExpression(expression.getExpressions().get(0));
} else if (expression instanceof ConstantOperand || expression instanceof TimestampOperand) {
return null;
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
public static Expression getMeasurementExpression(Expression expression) {
if (expression instanceof TernaryExpression) {
Expression firstExpression =
getMeasurementExpression(((TernaryExpression) expression).getFirstExpression());
Expression secondExpression =
getMeasurementExpression(((TernaryExpression) expression).getSecondExpression());
Expression thirdExpression =
getMeasurementExpression(((TernaryExpression) expression).getThirdExpression());
return reconstructTernaryExpressions(
expression,
Collections.singletonList(firstExpression),
Collections.singletonList(secondExpression),
Collections.singletonList(thirdExpression))
.get(0);
} else if (expression instanceof BinaryExpression) {
Expression leftExpression =
getMeasurementExpression(((BinaryExpression) expression).getLeftExpression());
Expression rightExpression =
getMeasurementExpression(((BinaryExpression) expression).getRightExpression());
return reconstructBinaryExpressions(
expression.getExpressionType(),
Collections.singletonList(leftExpression),
Collections.singletonList(rightExpression))
.get(0);
} else if (expression instanceof UnaryExpression) {
Expression childExpression =
getMeasurementExpression(((UnaryExpression) expression).getExpression());
return reconstructUnaryExpressions(
(UnaryExpression) expression, Collections.singletonList(childExpression))
.get(0);
} else if (expression instanceof FunctionExpression) {
List<Expression> childExpressions = new ArrayList<>();
for (Expression suffixExpression : expression.getExpressions()) {
childExpressions.add(getMeasurementExpression(suffixExpression));
}
return new FunctionExpression(
((FunctionExpression) expression).getFunctionName(),
((FunctionExpression) expression).getFunctionAttributes(),
childExpressions);
} else if (expression instanceof TimeSeriesOperand) {
MeasurementPath rawPath = (MeasurementPath) ((TimeSeriesOperand) expression).getPath();
PartialPath measurement = new PartialPath(rawPath.getMeasurement(), false);
MeasurementPath measurementWithSchema =
new MeasurementPath(measurement, rawPath.getMeasurementSchema());
return new TimeSeriesOperand(measurementWithSchema);
} else if (expression instanceof TimestampOperand || expression instanceof ConstantOperand) {
return expression;
} else {
throw new IllegalArgumentException(
"unsupported expression type: " + expression.getExpressionType());
}
}
public static Expression evaluatePredicate(Expression predicate) {
if (predicate.getExpressionType().equals(ExpressionType.LOGIC_AND)) {
Expression left = evaluatePredicate(((BinaryExpression) predicate).getLeftExpression());
Expression right = evaluatePredicate(((BinaryExpression) predicate).getRightExpression());
boolean isLeftTrue =
left.isConstantOperand() && Boolean.parseBoolean(left.getExpressionString());
boolean isRightTrue =
right.isConstantOperand() && Boolean.parseBoolean(right.getExpressionString());
if (isLeftTrue && isRightTrue) {
return new ConstantOperand(TSDataType.BOOLEAN, "true");
} else if (isLeftTrue) {
return right;
} else if (isRightTrue) {
return left;
}
return predicate;
} else if (predicate.getExpressionType().equals(ExpressionType.LOGIC_OR)) {
Expression left = evaluatePredicate(((BinaryExpression) predicate).getLeftExpression());
Expression right = evaluatePredicate(((BinaryExpression) predicate).getRightExpression());
boolean isLeftTrue =
left.isConstantOperand() && Boolean.parseBoolean(left.getExpressionString());
boolean isRightTrue =
right.isConstantOperand() && Boolean.parseBoolean(right.getExpressionString());
if (isRightTrue || isLeftTrue) {
return new ConstantOperand(TSDataType.BOOLEAN, "true");
}
}
return predicate;
}
}