You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ro...@apache.org on 2022/03/03 00:03:35 UTC
[iotdb] branch master updated: [IOTDB-1807] Compatibility of Apache IoTDB with InfluxDB - Parse InfluxQL (#4535)
This is an automated email from the ASF dual-hosted git repository.
rong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 07fb542 [IOTDB-1807] Compatibility of Apache IoTDB with InfluxDB - Parse InfluxQL (#4535)
07fb542 is described below
commit 07fb54250bd61430b1381ff50005f417372b1b72
Author: Xieqijun <44...@users.noreply.github.com>
AuthorDate: Thu Mar 3 08:02:09 2022 +0800
[IOTDB-1807] Compatibility of Apache IoTDB with InfluxDB - Parse InfluxQL (#4535)
Co-authored-by: Timcross-WEI <ti...@qq.com>
---
.../apache/iotdb/db/qp/sql/InfluxDBSqlParser.g4 | 129 +++++++++
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 2 +-
.../db/qp/sql/{IoTDBSqlLexer.g4 => SqlLexer.g4} | 2 +-
.../apache/iotdb/cli/IoTDBSyntaxHighlighter.java | 4 +-
.../org/apache/iotdb/cli/utils/JlineUtils.java | 6 +-
docs/zh/UserGuide/API/InfluxDB-Protocol.md | 2 +-
.../influxdb/constant/InfluxSQLConstant.java | 57 ++++
.../iotdb/db/protocol/influxdb/dto/IoTDBPoint.java | 10 +-
.../influxdb/operator/InfluxQueryOperator.java | 38 +++
.../influxdb/operator/InfluxSelectComponent.java | 94 +++++++
.../influxdb/sql/InfluxDBLogicalGenerator.java | 66 +++++
.../protocol/influxdb/sql/InfluxDBSqlVisitor.java | 297 +++++++++++++++++++++
.../iotdb/db/qp/constant/FilterConstant.java | 20 +-
.../apache/iotdb/db/qp/constant/SQLConstant.java | 3 +-
.../iotdb/db/qp/logical/crud/SelectComponent.java | 4 +-
.../iotdb/db/qp/strategy/LogicalGenerator.java | 6 +-
.../influxdb/sql/InfluxDBLogicalGeneratorTest.java | 68 +++++
thrift-influxdb/README.md | 2 +-
18 files changed, 778 insertions(+), 32 deletions(-)
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/InfluxDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/InfluxDBSqlParser.g4
new file mode 100644
index 0000000..2df0017
--- /dev/null
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/InfluxDBSqlParser.g4
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+parser grammar InfluxDBSqlParser;
+
+options { tokenVocab=SqlLexer; }
+
+singleStatement
+ : statement SEMI? EOF
+ ;
+
+
+statement
+ : selectClause fromClause whereClause? #selectStatement
+ ;
+
+selectClause
+ : SELECT resultColumn (COMMA resultColumn)*
+ ;
+
+resultColumn
+ : expression (AS identifier)?
+ ;
+
+expression
+ : LR_BRACKET unaryInBracket=expression RR_BRACKET
+ | (PLUS | MINUS) unaryAfterSign=expression
+ | leftExpression=expression (STAR | DIV | MOD) rightExpression=expression
+ | leftExpression=expression (PLUS | MINUS) rightExpression=expression
+ | functionName=nodeName LR_BRACKET expression (COMMA expression)* functionAttribute* RR_BRACKET
+ | nodeName
+ | constant
+ ;
+
+whereClause
+ : WHERE orExpression
+ ;
+
+orExpression
+ : andExpression (OPERATOR_OR andExpression)*
+ ;
+
+andExpression
+ : predicate (OPERATOR_AND predicate)*
+ ;
+
+predicate
+ : (TIME | TIMESTAMP | nodeName ) comparisonOperator constant
+ | OPERATOR_NOT? LR_BRACKET orExpression RR_BRACKET
+ ;
+
+fromClause
+ : FROM nodeName (COMMA nodeName)*
+ ;
+
+nodeName
+ : STAR
+ | ID
+ | QUTOED_ID
+ | QUTOED_ID_IN_NODE_NAME
+ ;
+
+// Identifier
+
+identifier
+ : ID
+ | QUTOED_ID
+ | QUTOED_ID_IN_NODE_NAME
+ | INTEGER_LITERAL
+ ;
+
+
+// Constant & Literal
+
+constant
+ : dateExpression
+ | (MINUS|PLUS)? realLiteral
+ | (MINUS|PLUS)? INTEGER_LITERAL
+ | STRING_LITERAL
+ | BOOLEAN_LITERAL
+ | NULL_LITERAL
+ | NAN_LITERAL
+ ;
+
+functionAttribute
+ : COMMA functionAttributeKey=STRING_LITERAL OPERATOR_EQ functionAttributeValue=STRING_LITERAL
+ ;
+
+comparisonOperator
+ : type = OPERATOR_GT
+ | type = OPERATOR_GTE
+ | type = OPERATOR_LT
+ | type = OPERATOR_LTE
+ | type = OPERATOR_EQ
+ | type = OPERATOR_NEQ
+ ;
+
+// Expression & Predicate
+
+dateExpression
+ : datetimeLiteral ((PLUS | MINUS) DURATION_LITERAL)*
+ ;
+
+realLiteral
+ : INTEGER_LITERAL DOT (INTEGER_LITERAL|EXPONENT_NUM_PART)?
+ | DOT (INTEGER_LITERAL|EXPONENT_NUM_PART)
+ | EXPONENT_NUM_PART
+ ;
+
+datetimeLiteral
+ : DATETIME_LITERAL
+ | NOW LR_BRACKET RR_BRACKET
+ ;
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index a218d15..73b4b0a 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -19,7 +19,7 @@
parser grammar IoTDBSqlParser;
-options { tokenVocab=IoTDBSqlLexer; }
+options { tokenVocab=SqlLexer; }
/**
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
similarity index 99%
rename from antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4
rename to antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index 459d01f..89a4603 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -17,7 +17,7 @@
* under the License.
*/
-lexer grammar IoTDBSqlLexer;
+lexer grammar SqlLexer;
/**
* 1. Whitespace
diff --git a/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java b/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java
index 82e9866..211fec7 100644
--- a/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java
+++ b/cli/src/main/java/org/apache/iotdb/cli/IoTDBSyntaxHighlighter.java
@@ -20,7 +20,7 @@
package org.apache.iotdb.cli;
import org.apache.iotdb.cli.utils.JlineUtils;
-import org.apache.iotdb.db.qp.sql.IoTDBSqlLexer;
+import org.apache.iotdb.db.qp.sql.SqlLexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
@@ -43,7 +43,7 @@ public class IoTDBSyntaxHighlighter implements Highlighter {
@Override
public AttributedString highlight(LineReader reader, String buffer) {
CharStream stream = CharStreams.fromString(buffer);
- IoTDBSqlLexer tokenSource = new IoTDBSqlLexer(stream);
+ SqlLexer tokenSource = new SqlLexer(stream);
tokenSource.removeErrorListeners();
AttributedStringBuilder builder = new AttributedStringBuilder();
while (true) {
diff --git a/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java b/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
index b185398..b9ad88d 100644
--- a/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
+++ b/cli/src/main/java/org/apache/iotdb/cli/utils/JlineUtils.java
@@ -19,7 +19,7 @@
package org.apache.iotdb.cli.utils;
-import org.apache.iotdb.db.qp.sql.IoTDBSqlLexer;
+import org.apache.iotdb.db.qp.sql.SqlLexer;
import org.jline.reader.LineReader;
import org.jline.reader.LineReader.Option;
@@ -44,8 +44,8 @@ public class JlineUtils {
public static final Pattern SQL_KEYWORD_PATTERN = Pattern.compile("([A-Z_]+)");
public static final Set<String> SQL_KEYWORDS =
- IntStream.range(0, IoTDBSqlLexer.VOCABULARY.getMaxTokenType())
- .mapToObj(IoTDBSqlLexer.VOCABULARY::getDisplayName)
+ IntStream.range(0, SqlLexer.VOCABULARY.getMaxTokenType())
+ .mapToObj(SqlLexer.VOCABULARY::getDisplayName)
.filter(Objects::nonNull)
.filter(w -> SQL_KEYWORD_PATTERN.matcher(w).matches())
.collect(Collectors.toSet());
diff --git a/docs/zh/UserGuide/API/InfluxDB-Protocol.md b/docs/zh/UserGuide/API/InfluxDB-Protocol.md
index db9f83f..63f8816 100644
--- a/docs/zh/UserGuide/API/InfluxDB-Protocol.md
+++ b/docs/zh/UserGuide/API/InfluxDB-Protocol.md
@@ -230,7 +230,7 @@ time address name phone sex socre
```
-4. 查询student中name=A或score>97,由于tag存储在路径中,因此没有办法用一次查询同时完成tag和field的*或*语义查询,因此需要多次查询进行或运算求并集,对应到IoTDB的查询为:
+4. 查询student中name=A或score>97,由于tag存储在路径中,因此没有办法用一次查询同时完成tag和field的**或**语义查询,因此需要多次查询进行或运算求并集,对应到IoTDB的查询为:
```sql
select * from root.monitor.student.A
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/constant/InfluxSQLConstant.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/constant/InfluxSQLConstant.java
new file mode 100644
index 0000000..cbc77b7
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/constant/InfluxSQLConstant.java
@@ -0,0 +1,57 @@
+/*
+ * 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.protocol.influxdb.constant;
+
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/** this class contains several constants used in SQL. */
+public class InfluxSQLConstant extends SQLConstant {
+
+ public static final String MAX = "max";
+ public static final String MIN = "min";
+ public static final String FIRST = "first";
+ public static final String MEAN = "mean";
+ public static final String MEDIAN = "median";
+ public static final String MODE = "mode";
+ public static final String SPREAD = "spread";
+ public static final String STDDEV = "stddev";
+ private static final Set<String> NATIVE_FUNCTION_NAMES =
+ new HashSet<>(
+ Arrays.asList(MIN, MAX, FIRST, LAST, MEAN, COUNT, MEDIAN, MODE, SPREAD, STDDEV, SUM));
+ private static final Set<String> NATIVE_SELECTOR_FUNCTION_NAMES =
+ new HashSet<>(Arrays.asList(MIN, MAX, FIRST, LAST));
+
+ public InfluxSQLConstant() throws InstantiationException {
+ // forbidding instantiation
+ super();
+ }
+
+ public static Set<String> getNativeFunctionNames() {
+ return NATIVE_FUNCTION_NAMES;
+ }
+
+ public static Set<String> getNativeSelectorFunctionNames() {
+ return NATIVE_SELECTOR_FUNCTION_NAMES;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/dto/IoTDBPoint.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/dto/IoTDBPoint.java
index 45fbdd9..3d90114 100644
--- a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/dto/IoTDBPoint.java
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/dto/IoTDBPoint.java
@@ -82,21 +82,17 @@ public class IoTDBPoint {
if (reflectField.getType().getName().equalsIgnoreCase("java.util.Map")
&& reflectField.getName().equalsIgnoreCase("fields")) {
fields = (Map<String, Object>) reflectField.get(point);
- }
- if (reflectField.getType().getName().equalsIgnoreCase("java.util.Map")
+ } else if (reflectField.getType().getName().equalsIgnoreCase("java.util.Map")
&& reflectField.getName().equalsIgnoreCase("tags")) {
tags = (Map<String, String>) reflectField.get(point);
- }
- if (reflectField.getType().getName().equalsIgnoreCase("java.lang.String")
+ } else if (reflectField.getType().getName().equalsIgnoreCase("java.lang.String")
&& reflectField.getName().equalsIgnoreCase("measurement")) {
measurement = (String) reflectField.get(point);
- }
- if (reflectField.getType().getName().equalsIgnoreCase("java.lang.Number")
+ } else if (reflectField.getType().getName().equalsIgnoreCase("java.lang.Number")
&& reflectField.getName().equalsIgnoreCase("time")) {
time = (Long) reflectField.get(point);
time = TimeUnit.MILLISECONDS.convert(time, precision);
}
-
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e.getMessage());
}
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/operator/InfluxQueryOperator.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/operator/InfluxQueryOperator.java
new file mode 100644
index 0000000..bdc15eb
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/operator/InfluxQueryOperator.java
@@ -0,0 +1,38 @@
+/*
+ * 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.protocol.influxdb.operator;
+
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+
+public class InfluxQueryOperator extends QueryOperator {
+
+ protected InfluxSelectComponent influxSelectComponent;
+
+ public InfluxQueryOperator() {
+ super();
+ }
+
+ public InfluxSelectComponent getSelectComponent() {
+ return influxSelectComponent;
+ }
+
+ public void setSelectComponent(InfluxSelectComponent influxSelectComponent) {
+ this.influxSelectComponent = influxSelectComponent;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/operator/InfluxSelectComponent.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/operator/InfluxSelectComponent.java
new file mode 100644
index 0000000..4e98caa
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/operator/InfluxSelectComponent.java
@@ -0,0 +1,94 @@
+/*
+ * 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.protocol.influxdb.operator;
+
+import org.apache.iotdb.db.protocol.influxdb.constant.InfluxSQLConstant;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.unary.FunctionExpression;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
+
+import java.time.ZoneId;
+
+/** this class maintains information from select clause. */
+public final class InfluxSelectComponent
+ extends org.apache.iotdb.db.qp.logical.crud.SelectComponent {
+
+ private boolean hasAggregationFunction = false;
+ private boolean hasSelectorFunction = false;
+ private boolean hasMoreSelectorFunction = false;
+ private boolean hasMoreFunction = false;
+ private boolean hasFunction = false;
+ private boolean hasCommonQuery = false;
+
+ public InfluxSelectComponent() {
+ super((ZoneId) null);
+ }
+
+ public void addResultColumn(ResultColumn resultColumn) {
+ Expression expression = resultColumn.getExpression();
+ if (expression instanceof FunctionExpression) {
+ String functionName = ((FunctionExpression) expression).getFunctionName();
+ if (InfluxSQLConstant.getNativeFunctionNames().contains(functionName.toLowerCase())) {
+ if (hasFunction) {
+ hasMoreFunction = true;
+ } else {
+ hasFunction = true;
+ }
+ }
+ if (InfluxSQLConstant.getNativeSelectorFunctionNames().contains(functionName.toLowerCase())) {
+ if (hasSelectorFunction) {
+ hasMoreSelectorFunction = true;
+ } else {
+ hasSelectorFunction = true;
+ }
+ } else {
+ hasAggregationFunction = true;
+ }
+ }
+ if (expression instanceof TimeSeriesOperand) {
+ hasCommonQuery = true;
+ }
+ resultColumns.add(resultColumn);
+ }
+
+ public boolean isHasAggregationFunction() {
+ return hasAggregationFunction;
+ }
+
+ public boolean isHasMoreFunction() {
+ return hasMoreFunction;
+ }
+
+ public boolean isHasCommonQuery() {
+ return hasCommonQuery;
+ }
+
+ public boolean isHasSelectorFunction() {
+ return hasSelectorFunction;
+ }
+
+ public boolean isHasMoreSelectorFunction() {
+ return hasMoreSelectorFunction;
+ }
+
+ public boolean isHasFunction() {
+ return hasFunction;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBLogicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBLogicalGenerator.java
new file mode 100644
index 0000000..361d105
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBLogicalGenerator.java
@@ -0,0 +1,66 @@
+/*
+ * 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.protocol.influxdb.sql;
+
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.sql.InfluxDBSqlParser;
+import org.apache.iotdb.db.qp.sql.SqlLexer;
+import org.apache.iotdb.db.qp.strategy.SQLParseError;
+
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.atn.PredictionMode;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+import org.antlr.v4.runtime.tree.ParseTree;
+
+public class InfluxDBLogicalGenerator {
+
+ private InfluxDBLogicalGenerator() {}
+
+ public static Operator generate(String sql) throws ParseCancellationException {
+ InfluxDBSqlVisitor influxDBSqlVisitor = new InfluxDBSqlVisitor();
+ CharStream charStream1 = CharStreams.fromString(sql);
+ SqlLexer lexer1 = new SqlLexer(charStream1);
+ lexer1.removeErrorListeners();
+ lexer1.addErrorListener(SQLParseError.INSTANCE);
+ CommonTokenStream tokens1 = new CommonTokenStream(lexer1);
+ InfluxDBSqlParser parser1 = new InfluxDBSqlParser(tokens1);
+ parser1.getInterpreter().setPredictionMode(PredictionMode.SLL);
+ parser1.removeErrorListeners();
+ parser1.addErrorListener(SQLParseError.INSTANCE);
+ ParseTree tree;
+ try {
+ tree = parser1.singleStatement(); // STAGE 1
+ } catch (Exception ex) {
+ CharStream charStream2 = CharStreams.fromString(sql);
+ SqlLexer lexer2 = new SqlLexer(charStream2);
+ lexer2.removeErrorListeners();
+ lexer2.addErrorListener(SQLParseError.INSTANCE);
+ CommonTokenStream tokens2 = new CommonTokenStream(lexer2);
+ InfluxDBSqlParser parser2 = new InfluxDBSqlParser(tokens2);
+ parser2.getInterpreter().setPredictionMode(PredictionMode.LL);
+ parser2.removeErrorListeners();
+ parser2.addErrorListener(SQLParseError.INSTANCE);
+ tree = parser2.singleStatement(); // STAGE 2
+ // if we parse ok, it's LL not SLL
+ }
+ return influxDBSqlVisitor.visit(tree);
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBSqlVisitor.java
new file mode 100644
index 0000000..72c4eea
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBSqlVisitor.java
@@ -0,0 +1,297 @@
+/*
+ * 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.protocol.influxdb.sql;
+
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.protocol.influxdb.operator.*;
+import org.apache.iotdb.db.qp.constant.FilterConstant;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
+import org.apache.iotdb.db.qp.logical.crud.FromComponent;
+import org.apache.iotdb.db.qp.logical.crud.WhereComponent;
+import org.apache.iotdb.db.qp.sql.InfluxDBSqlParser;
+import org.apache.iotdb.db.qp.sql.InfluxDBSqlParserBaseVisitor;
+import org.apache.iotdb.db.qp.utils.DatetimeUtils;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.binary.AdditionExpression;
+import org.apache.iotdb.db.query.expression.binary.DivisionExpression;
+import org.apache.iotdb.db.query.expression.binary.ModuloExpression;
+import org.apache.iotdb.db.query.expression.binary.MultiplicationExpression;
+import org.apache.iotdb.db.query.expression.binary.SubtractionExpression;
+import org.apache.iotdb.db.query.expression.unary.FunctionExpression;
+import org.apache.iotdb.db.query.expression.unary.NegationExpression;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
+
+public class InfluxDBSqlVisitor extends InfluxDBSqlParserBaseVisitor<Operator> {
+
+ private InfluxQueryOperator queryOp;
+
+ @Override
+ public Operator visitSingleStatement(InfluxDBSqlParser.SingleStatementContext ctx) {
+ return visit(ctx.statement());
+ }
+
+ @Override
+ public Operator visitSelectStatement(InfluxDBSqlParser.SelectStatementContext ctx) {
+ queryOp = new InfluxQueryOperator();
+ parseSelectClause(ctx.selectClause());
+ parseFromClause(ctx.fromClause());
+ if (ctx.whereClause() != null) {
+ WhereComponent whereComponent = parseWhereClause(ctx.whereClause());
+ queryOp.setWhereComponent(whereComponent);
+ }
+ return queryOp;
+ }
+
+ public void parseSelectClause(InfluxDBSqlParser.SelectClauseContext ctx) {
+ InfluxSelectComponent influxSelectComponent = new InfluxSelectComponent();
+ for (InfluxDBSqlParser.ResultColumnContext resultColumnContext : ctx.resultColumn()) {
+ influxSelectComponent.addResultColumn(parseResultColumn(resultColumnContext));
+ }
+ queryOp.setSelectComponent(influxSelectComponent);
+ }
+
+ private void parseFromClause(InfluxDBSqlParser.FromClauseContext fromClause) {
+ FromComponent fromComponent = new FromComponent();
+
+ for (InfluxDBSqlParser.NodeNameContext nodeName : fromClause.nodeName()) {
+ fromComponent.addPrefixTablePath(new PartialPath(nodeName.getText(), false));
+ }
+ queryOp.setFromComponent(fromComponent);
+ }
+
+ private WhereComponent parseWhereClause(InfluxDBSqlParser.WhereClauseContext ctx) {
+ FilterOperator whereOp = new FilterOperator();
+ whereOp.addChildOperator(parseOrExpression(ctx.orExpression()));
+ return new WhereComponent(whereOp.getChildren().get(0));
+ }
+
+ private FilterOperator parseOrExpression(InfluxDBSqlParser.OrExpressionContext ctx) {
+ if (ctx.andExpression().size() == 1) {
+ return parseAndExpression(ctx.andExpression(0));
+ }
+ FilterOperator binaryOp = new FilterOperator(FilterConstant.FilterType.KW_OR);
+ if (ctx.andExpression().size() > 2) {
+ binaryOp.addChildOperator(parseAndExpression(ctx.andExpression(0)));
+ binaryOp.addChildOperator(parseAndExpression(ctx.andExpression(1)));
+ for (int i = 2; i < ctx.andExpression().size(); i++) {
+ FilterOperator operator = new FilterOperator(FilterConstant.FilterType.KW_OR);
+ operator.addChildOperator(binaryOp);
+ operator.addChildOperator(parseAndExpression(ctx.andExpression(i)));
+ binaryOp = operator;
+ }
+ } else {
+ for (InfluxDBSqlParser.AndExpressionContext andExpressionContext : ctx.andExpression()) {
+ binaryOp.addChildOperator(parseAndExpression(andExpressionContext));
+ }
+ }
+ return binaryOp;
+ }
+
+ private FilterOperator parseAndExpression(InfluxDBSqlParser.AndExpressionContext ctx) {
+ if (ctx.predicate().size() == 1) {
+ return parsePredicate(ctx.predicate(0));
+ }
+ FilterOperator binaryOp = new FilterOperator(FilterConstant.FilterType.KW_AND);
+ int size = ctx.predicate().size();
+ if (size > 2) {
+ binaryOp.addChildOperator(parsePredicate(ctx.predicate(0)));
+ binaryOp.addChildOperator(parsePredicate(ctx.predicate(1)));
+ for (int i = 2; i < size; i++) {
+ FilterOperator op = new FilterOperator(FilterConstant.FilterType.KW_AND);
+ op.addChildOperator(binaryOp);
+ op.addChildOperator(parsePredicate(ctx.predicate(i)));
+ binaryOp = op;
+ }
+ } else {
+ for (InfluxDBSqlParser.PredicateContext predicateContext : ctx.predicate()) {
+ binaryOp.addChildOperator(parsePredicate(predicateContext));
+ }
+ }
+ return binaryOp;
+ }
+
+ private FilterOperator parsePredicate(InfluxDBSqlParser.PredicateContext ctx) {
+ if (ctx.OPERATOR_NOT() != null) {
+ FilterOperator notOp = new FilterOperator(FilterConstant.FilterType.KW_NOT);
+ notOp.addChildOperator(parseOrExpression(ctx.orExpression()));
+ return notOp;
+ } else if (ctx.LR_BRACKET() != null && ctx.OPERATOR_NOT() == null) {
+ return parseOrExpression(ctx.orExpression());
+ } else {
+ String keyName = null;
+ if (ctx.TIME() != null || ctx.TIMESTAMP() != null) {
+ keyName = SQLConstant.RESERVED_TIME;
+ }
+ if (ctx.nodeName() != null) {
+ keyName = ctx.nodeName().getText();
+ }
+ if (keyName == null) {
+ throw new IllegalArgumentException("keyName is null, please check the sql");
+ }
+ return parseBasicFunctionOperator(ctx, keyName);
+ }
+ }
+
+ private ResultColumn parseResultColumn(
+ InfluxDBSqlParser.ResultColumnContext resultColumnContext) {
+ return new ResultColumn(
+ parseExpression(resultColumnContext.expression()),
+ resultColumnContext.AS() == null ? null : resultColumnContext.identifier().getText());
+ }
+
+ private Expression parseExpression(InfluxDBSqlParser.ExpressionContext context) {
+ // LR_BRACKET unaryInBracket=expression RR_BRACKET
+ if (context.unaryInBracket != null) {
+ return parseExpression(context.unaryInBracket);
+ }
+
+ // (PLUS | MINUS) unaryAfterSign=expression
+ if (context.unaryAfterSign != null) {
+ return context.MINUS() != null
+ ? new NegationExpression(parseExpression(context.expression(0)))
+ : parseExpression(context.expression(0));
+ }
+
+ // leftExpression=expression (STAR | DIV | MOD) rightExpression=expression
+ // leftExpression=expression (PLUS | MINUS) rightExpression=expression
+ if (context.leftExpression != null && context.rightExpression != null) {
+ Expression leftExpression = parseExpression(context.leftExpression);
+ Expression rightExpression = parseExpression(context.rightExpression);
+ if (context.STAR() != null) {
+ return new MultiplicationExpression(leftExpression, rightExpression);
+ }
+ if (context.DIV() != null) {
+ return new DivisionExpression(leftExpression, rightExpression);
+ }
+ if (context.MOD() != null) {
+ return new ModuloExpression(leftExpression, rightExpression);
+ }
+ if (context.PLUS() != null) {
+ return new AdditionExpression(leftExpression, rightExpression);
+ }
+ if (context.MINUS() != null) {
+ return new SubtractionExpression(leftExpression, rightExpression);
+ }
+ }
+
+ // functionName=nodeName LR_BRACKET expression (COMMA expression)* functionAttribute* RR_BRACKET
+ if (context.functionName != null) {
+ return parseFunctionExpression(context);
+ }
+
+ // nodeName || constant
+ if (context.nodeName() != null || context.constant() != null) {
+ return new TimeSeriesOperand(new PartialPath(context.nodeName().getText(), false));
+ }
+
+ throw new UnsupportedOperationException();
+ }
+
+ private Expression parseFunctionExpression(InfluxDBSqlParser.ExpressionContext functionClause) {
+
+ FunctionExpression functionExpression =
+ new FunctionExpression(functionClause.functionName.getText());
+
+ // expressions
+ for (InfluxDBSqlParser.ExpressionContext expression : functionClause.expression()) {
+ functionExpression.addExpression(parseExpression(expression));
+ }
+
+ // attributes
+ for (InfluxDBSqlParser.FunctionAttributeContext functionAttribute :
+ functionClause.functionAttribute()) {
+ functionExpression.addAttribute(
+ removeStringQuote(functionAttribute.functionAttributeKey.getText()),
+ removeStringQuote(functionAttribute.functionAttributeValue.getText()));
+ }
+
+ return functionExpression;
+ }
+
+ private static String removeStringQuote(String src) {
+ if (src.charAt(0) == '\'' && src.charAt(src.length() - 1) == '\'') {
+ return src.substring(1, src.length() - 1);
+ } else if (src.charAt(0) == '\"' && src.charAt(src.length() - 1) == '\"') {
+ return src.substring(1, src.length() - 1);
+ } else {
+ throw new IllegalArgumentException("error format for string with quote:" + src);
+ }
+ }
+
+ /**
+ * parse time expression, which is addition and subtraction expression of duration time, now() or
+ * DataTimeFormat time.
+ *
+ * <p>eg. now() + 1d - 2h
+ */
+ private static Long parseDateExpression(InfluxDBSqlParser.DateExpressionContext ctx) {
+ long time;
+ time = parseTimeFormat(ctx.getChild(0).getText());
+ for (int i = 1; i < ctx.getChildCount(); i = i + 2) {
+ if (ctx.getChild(i).getText().equals("+")) {
+ time += DatetimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText());
+ } else {
+ time -= DatetimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText());
+ }
+ }
+ return time;
+ }
+
+ /** function for parsing time format. */
+ public static long parseTimeFormat(String timestampStr) {
+ if (timestampStr == null || timestampStr.trim().equals("")) {
+ throw new IllegalArgumentException("input timestamp cannot be empty");
+ }
+ if (timestampStr.equalsIgnoreCase(SQLConstant.NOW_FUNC)) {
+ return DatetimeUtils.currentTime();
+ }
+ throw new IllegalArgumentException(
+ String.format(
+ "Input time format %s error. "
+ + "Input like yyyy-MM-dd HH:mm:ss, yyyy-MM-ddTHH:mm:ss or "
+ + "refer to user document for more info.",
+ timestampStr));
+ }
+
+ private static FilterOperator parseBasicFunctionOperator(
+ InfluxDBSqlParser.PredicateContext ctx, String pathName) {
+ BasicFunctionOperator basic;
+ if (ctx.constant().dateExpression() != null) {
+ if (!pathName.equals(SQLConstant.RESERVED_TIME)) {
+ throw new IllegalArgumentException("Date can only be used to time");
+ }
+ basic =
+ new BasicFunctionOperator(
+ FilterConstant.lexerToFilterType.get(ctx.comparisonOperator().type.getType()),
+ new PartialPath(pathName, false),
+ Long.toString(parseDateExpression(ctx.constant().dateExpression())));
+ } else {
+ basic =
+ new BasicFunctionOperator(
+ FilterConstant.lexerToFilterType.get(ctx.comparisonOperator().type.getType()),
+ new PartialPath(pathName, false),
+ ctx.constant().getText());
+ }
+ return basic;
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/constant/FilterConstant.java b/server/src/main/java/org/apache/iotdb/db/qp/constant/FilterConstant.java
index dbc5e57..cd8cc49 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/constant/FilterConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/constant/FilterConstant.java
@@ -19,7 +19,7 @@
package org.apache.iotdb.db.qp.constant;
-import org.apache.iotdb.db.qp.sql.IoTDBSqlLexer;
+import org.apache.iotdb.db.qp.sql.SqlLexer;
import java.util.EnumMap;
import java.util.HashMap;
@@ -50,15 +50,15 @@ public class FilterConstant {
}
static {
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_EQ, FilterType.EQUAL);
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_NEQ, FilterType.NOTEQUAL);
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_LTE, FilterType.LESSTHANOREQUALTO);
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_LT, FilterType.LESSTHAN);
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_GTE, FilterType.GREATERTHANOREQUALTO);
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_GT, FilterType.GREATERTHAN);
- lexerToFilterType.put(IoTDBSqlLexer.OPERATOR_IN, FilterType.IN);
- lexerToFilterType.put(IoTDBSqlLexer.REGEXP, FilterType.REGEXP);
- lexerToFilterType.put(IoTDBSqlLexer.LIKE, FilterType.LIKE);
+ lexerToFilterType.put(SqlLexer.OPERATOR_EQ, FilterType.EQUAL);
+ lexerToFilterType.put(SqlLexer.OPERATOR_NEQ, FilterType.NOTEQUAL);
+ lexerToFilterType.put(SqlLexer.OPERATOR_LTE, FilterType.LESSTHANOREQUALTO);
+ lexerToFilterType.put(SqlLexer.OPERATOR_LT, FilterType.LESSTHAN);
+ lexerToFilterType.put(SqlLexer.OPERATOR_GTE, FilterType.GREATERTHANOREQUALTO);
+ lexerToFilterType.put(SqlLexer.OPERATOR_GT, FilterType.GREATERTHAN);
+ lexerToFilterType.put(SqlLexer.OPERATOR_IN, FilterType.IN);
+ lexerToFilterType.put(SqlLexer.REGEXP, FilterType.REGEXP);
+ lexerToFilterType.put(SqlLexer.LIKE, FilterType.LIKE);
}
static {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
index a0b3168..cbae289 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
@@ -30,8 +30,9 @@ import java.util.Set;
@SuppressWarnings("unused") // some fields are for future features
public class SQLConstant {
- private SQLConstant() {
+ public SQLConstant() throws InstantiationException {
// forbidding instantiation
+ throw new InstantiationException();
}
private static final String[] SINGLE_ROOT_ARRAY = {"root", "**"};
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
index 9dac1c3..4b955eb 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectComponent.java
@@ -30,7 +30,7 @@ import java.util.ArrayList;
import java.util.List;
/** this class maintains information from select clause. */
-public final class SelectComponent {
+public class SelectComponent {
private final ZoneId zoneId;
@@ -38,7 +38,7 @@ public final class SelectComponent {
private boolean hasTimeSeriesGeneratingFunction = false;
private boolean hasUserDefinedAggregationFunction = false;
- private List<ResultColumn> resultColumns = new ArrayList<>();
+ protected List<ResultColumn> resultColumns = new ArrayList<>();
private List<PartialPath> pathsCache;
private List<String> aggregationFunctionsCache;
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
index 27d38a4..340bc32 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
@@ -30,9 +30,9 @@ import org.apache.iotdb.db.qp.logical.crud.LastQueryOperator;
import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
import org.apache.iotdb.db.qp.logical.crud.SelectComponent;
import org.apache.iotdb.db.qp.logical.crud.WhereComponent;
-import org.apache.iotdb.db.qp.sql.IoTDBSqlLexer;
import org.apache.iotdb.db.qp.sql.IoTDBSqlParser;
import org.apache.iotdb.db.qp.sql.IoTDBSqlVisitor;
+import org.apache.iotdb.db.qp.sql.SqlLexer;
import org.apache.iotdb.db.query.expression.ResultColumn;
import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
import org.apache.iotdb.db.utils.TestOnly;
@@ -64,7 +64,7 @@ public class LogicalGenerator {
CharStream charStream1 = CharStreams.fromString(sql);
- IoTDBSqlLexer lexer1 = new IoTDBSqlLexer(charStream1);
+ SqlLexer lexer1 = new SqlLexer(charStream1);
lexer1.removeErrorListeners();
lexer1.addErrorListener(SQLParseError.INSTANCE);
@@ -84,7 +84,7 @@ public class LogicalGenerator {
} catch (Exception ex) {
CharStream charStream2 = CharStreams.fromString(sql);
- IoTDBSqlLexer lexer2 = new IoTDBSqlLexer(charStream2);
+ SqlLexer lexer2 = new SqlLexer(charStream2);
lexer2.removeErrorListeners();
lexer2.addErrorListener(SQLParseError.INSTANCE);
diff --git a/server/src/test/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBLogicalGeneratorTest.java b/server/src/test/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBLogicalGeneratorTest.java
new file mode 100644
index 0000000..276b9d3
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/protocol/influxdb/sql/InfluxDBLogicalGeneratorTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.protocol.influxdb.sql;
+
+import org.apache.iotdb.db.protocol.influxdb.operator.*;
+import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator;
+import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
+import org.apache.iotdb.db.qp.logical.crud.WhereComponent;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+public class InfluxDBLogicalGeneratorTest {
+ @Test
+ public void testParserSql1() {
+ InfluxQueryOperator operator =
+ (InfluxQueryOperator) InfluxDBLogicalGenerator.generate("SELECT * FROM h2o_feet");
+ List<ResultColumn> resultColumnList = operator.getSelectComponent().getResultColumns();
+ assertEquals(resultColumnList.size(), 1);
+ TimeSeriesOperand timeSeriesOperand =
+ (TimeSeriesOperand) resultColumnList.get(0).getExpression();
+ assertEquals(timeSeriesOperand.getPath().getFullPath(), "*");
+ assertEquals(operator.getFromComponent().getPrefixPaths().get(0).getFullPath(), "h2o_feet");
+ assertNull(operator.getWhereComponent());
+ }
+
+ @Test
+ public void testParserSql2() {
+ InfluxQueryOperator operator =
+ (InfluxQueryOperator)
+ InfluxDBLogicalGenerator.generate("SELECT a,b,c FROM h2o_feet where a>1 and b<1");
+ List<ResultColumn> resultColumnList = operator.getSelectComponent().getResultColumns();
+ assertEquals(resultColumnList.size(), 3);
+ TimeSeriesOperand timeSeriesOperand =
+ (TimeSeriesOperand) resultColumnList.get(0).getExpression();
+ assertEquals(timeSeriesOperand.getPath().getFullPath(), "a");
+ WhereComponent whereComponent = operator.getWhereComponent();
+ FilterOperator filterOperator = (FilterOperator) whereComponent.getFilterOperator();
+ assertEquals(filterOperator.getFilterType().toString(), "KW_AND");
+ assertEquals(filterOperator.getChildren().size(), 2);
+ BasicFunctionOperator basicFunctionOperator =
+ (BasicFunctionOperator) filterOperator.getChildren().get(0);
+ assertEquals(basicFunctionOperator.getValue(), "1");
+ assertEquals(basicFunctionOperator.getSinglePath().getFullPath(), "a");
+ assertNotNull(basicFunctionOperator.getFilterType());
+ }
+}
diff --git a/thrift-influxdb/README.md b/thrift-influxdb/README.md
index 4801c89..af4fe2c 100644
--- a/thrift-influxdb/README.md
+++ b/thrift-influxdb/README.md
@@ -19,4 +19,4 @@
-->
-This modules maintains all influxdb RPC interfaces among servers for the influxdb protocol module.
\ No newline at end of file
+This module maintains all influxdb RPC interfaces among servers for the influxdb protocol module.
\ No newline at end of file