This is an automated email from the ASF dual-hosted git repository. lta pushed a commit to branch add_in_operation in repository https://gitbox.apache.org/repos/asf/incubator-iotdb.git
commit 6b6bfe49a56e1c42d14ae3b521716cc742a3b158 Author: lta <[email protected]> AuthorDate: Mon Feb 3 21:27:18 2020 +0800 add IN operation --- .../org/apache/iotdb/db/qp/strategy/SqlBase.g4 | 6 + .../apache/iotdb/db/qp/constant/SQLConstant.java | 3 + .../org/apache/iotdb/db/qp/logical/Operator.java | 2 +- .../db/qp/logical/crud/BasicFunctionOperator.java | 32 +--- .../iotdb/db/qp/logical/crud/FilterOperator.java | 28 +-- .../iotdb/db/qp/logical/crud/FunctionOperator.java | 17 ++ .../iotdb/db/qp/logical/crud/InOperator.java | 213 +++++++++++++++++++++ .../iotdb/db/qp/strategy/LogicalGenerator.java | 68 +++++-- .../iotdb/db/qp/strategy/PhysicalGenerator.java | 4 +- .../qp/strategy/optimizer/ConcatPathOptimizer.java | 6 +- .../optimizer/MergeSingleFilterOptimizer.java | 14 +- .../qp/strategy/optimizer/RemoveNotOptimizer.java | 3 +- .../iotdb/db/integration/IoTDBQueryDemoIT.java | 93 ++++++++- .../apache/iotdb/db/qp/plan/PhysicalPlanTest.java | 50 +++++ .../iotdb/tsfile/read/filter/TimeFilter.java | 13 ++ .../iotdb/tsfile/read/filter/ValueFilter.java | 13 ++ .../tsfile/read/filter/factory/FilterFactory.java | 2 - .../read/filter/factory/FilterSerializeId.java | 2 +- .../iotdb/tsfile/read/filter/operator/Eq.java | 4 +- .../read/filter/operator/{Eq.java => In.java} | 90 +++++---- 20 files changed, 546 insertions(+), 117 deletions(-) diff --git a/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4 b/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4 index 4e2e47f..ab0e68e 100644 --- a/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4 +++ b/server/src/main/antlr4/org/apache/iotdb/db/qp/strategy/SqlBase.g4 @@ -137,9 +137,13 @@ andExpression predicate : (suffixPath | prefixPath) comparisonOperator constant + | (suffixPath | prefixPath) inClause | OPERATOR_NOT? LR_BRACKET orExpression RR_BRACKET ; +inClause + : OPERATOR_NOT? OPERATOR_IN LR_BRACKET constant (COMMA constant)* RR_BRACKET + ; fromClause : FROM prefixPath (COMMA prefixPath)* @@ -746,6 +750,8 @@ OPERATOR_LTE : '<='; OPERATOR_NEQ : '!=' | '<>'; +OPERATOR_IN : 'IN' | 'in' | 'In' | 'iN'; + OPERATOR_AND : A N D | '&' 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 9a89fcc..b62287d 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 @@ -78,6 +78,7 @@ public class SQLConstant { public static final int GREATERTHANOREQUALTO = SqlBaseLexer.OPERATOR_GTE; public static final int GREATERTHAN = SqlBaseLexer.OPERATOR_GT; public static final int EQUAL_NS = SqlBaseLexer.OPERATOR_NEQ; + public static final int IN = SqlBaseLexer.OPERATOR_IN; public static final int TOK_SELECT = 21; public static final int TOK_FROM = 22; @@ -165,6 +166,7 @@ public class SQLConstant { tokenNames.put(LESSTHAN, "lessthan"); tokenNames.put(GREATERTHANOREQUALTO, "greaterthan_or_equalto"); tokenNames.put(GREATERTHAN, "greaterthan"); + tokenNames.put(IN, "in"); tokenNames.put(TOK_SELECT, "TOK_SELECT"); tokenNames.put(TOK_FROM, "TOK_FROM"); @@ -207,6 +209,7 @@ public class SQLConstant { static { reverseWords.put(KW_AND, KW_OR); + reverseWords.put(IN, IN); reverseWords.put(KW_OR, KW_AND); reverseWords.put(EQUAL, NOTEQUAL); reverseWords.put(NOTEQUAL, EQUAL); diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java index 50d87bc..2dfd9ad 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java @@ -67,7 +67,7 @@ public abstract class Operator { */ public enum OperatorType { SFW, JOIN, UNION, FILTER, GROUPBY, ORDERBY, LIMIT, SELECT, SEQTABLESCAN, HASHTABLESCAN, - MERGEJOIN, FILEREAD, NULL, TABLESCAN, UPDATE, INSERT, BATCHINSERT, DELETE, BASIC_FUNC, QUERY, MERGEQUERY, + MERGEJOIN, FILEREAD, NULL, TABLESCAN, UPDATE, INSERT, BATCHINSERT, DELETE, BASIC_FUNC, IN, QUERY, MERGEQUERY, AGGREGATION, AUTHOR, FROM, FUNC, LOADDATA, METADATA, PROPERTY, INDEX, INDEXQUERY, FILL, SET_STORAGE_GROUP, CREATE_TIMESERIES, DELETE_TIMESERIES, CREATE_USER, DELETE_USER, MODIFY_PASSWORD, GRANT_USER_PRIVILEGE, REVOKE_USER_PRIVILEGE, GRANT_USER_ROLE, REVOKE_USER_ROLE, CREATE_ROLE, diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/BasicFunctionOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/BasicFunctionOperator.java index 2fce08a..fe1d05f 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/BasicFunctionOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/BasicFunctionOperator.java @@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory; */ public class BasicFunctionOperator extends FunctionOperator { - protected Path path; protected String value; private Logger logger = LoggerFactory.getLogger(BasicFunctionOperator.class); private BasicOperatorType funcToken; @@ -57,44 +56,19 @@ public class BasicFunctionOperator extends FunctionOperator { super(tokenIntType); operatorType = Operator.OperatorType.BASIC_FUNC; funcToken = BasicOperatorType.getBasicOpBySymbol(tokenIntType); - this.path = this.singlePath = path; + this.path = path; this.value = value; isLeaf = true; isSingle = true; } - /** - * get path. - * - * @return path - */ - public String getPath() { - return path.toString(); - } - public String getValue() { return value; } - /** - * set reversed token. - * - * @throws LogicalOperatorException Logical Operator Exception - */ - public void setReversedTokenIntType() throws LogicalOperatorException { - int intType = SQLConstant.reverseWords.get(tokenIntType); - setTokenIntType(intType); - funcToken = BasicOperatorType.getBasicOpBySymbol(intType); - } - - @Override - public Path getSinglePath() { - return singlePath; - } - @Override - public void setSinglePath(Path singlePath) { - this.path = this.singlePath = singlePath; + protected void reverseFunc(){ + funcToken = BasicOperatorType.getBasicOpBySymbol(getTokenIntType()); } @Override diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java index b1f1903..a36522a 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FilterOperator.java @@ -55,7 +55,7 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato // isSingle being true means all recursive children of this filter belong to one seriesPath. protected boolean isSingle = false; // if isSingle = false, singlePath must be null - protected Path singlePath = null; + protected Path path = null; public FilterOperator(int tokenType) { super(tokenType); @@ -94,12 +94,12 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato this.isSingle = b; } - public Path getSinglePath() { - return singlePath; + public Path getPath() { + return path; } - public void setSinglePath(Path path) { - this.singlePath = path; + public void setPath(Path path) { + this.path = path; } public boolean addChildOperator(FilterOperator op) { @@ -114,7 +114,7 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato * @return QueryFilter in TsFile */ public IExpression transformToExpression(IQueryProcessExecutor executor) - throws QueryProcessException, LogicalOperatorException { + throws QueryProcessException { if (isSingle) { Pair<IUnaryExpression, String> ret = transformToSingleQueryFilter(executor); return ret.left; @@ -192,16 +192,16 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato */ @Override public int compareTo(FilterOperator fil) { - if (singlePath == null && fil.singlePath == null) { + if (path == null && fil.path == null) { return 0; } - if (singlePath == null) { + if (path == null) { return 1; } - if (fil.singlePath == null) { + if (fil.path == null) { return -1; } - return fil.singlePath.toString().compareTo(singlePath.toString()); + return fil.path.toString().compareTo(path.toString()); } @Override @@ -239,7 +239,7 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato } sc.addTail(this.tokenName); if (isSingle) { - sc.addTail("[single:", getSinglePath().toString(), "]"); + sc.addTail("[single:", getPath().toString(), "]"); } sc.addTail("\n"); for (FilterOperator filter : childOperators) { @@ -253,7 +253,7 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato StringContainer sc = new StringContainer(); sc.addTail("[", this.tokenName); if (isSingle) { - sc.addTail("[single:", getSinglePath().toString(), "]"); + sc.addTail("[single:", getPath().toString(), "]"); } sc.addTail(" "); for (FilterOperator filter : childOperators) { @@ -269,8 +269,8 @@ public class FilterOperator extends Operator implements Comparable<FilterOperato ret.tokenSymbol = tokenSymbol; ret.isLeaf = isLeaf; ret.isSingle = isSingle; - if (singlePath != null) { - ret.singlePath = singlePath.clone(); + if (path != null) { + ret.path = path.clone(); } for (FilterOperator filterOperator : this.childOperators) { ret.addChildOperator(filterOperator.clone()); diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FunctionOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FunctionOperator.java index 64039bd..87b492b 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FunctionOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/FunctionOperator.java @@ -18,6 +18,8 @@ */ package org.apache.iotdb.db.qp.logical.crud; +import org.apache.iotdb.db.exception.query.LogicalOperatorException; +import org.apache.iotdb.db.qp.constant.SQLConstant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,6 +39,21 @@ public class FunctionOperator extends FilterOperator { operatorType = OperatorType.FUNC; } + /** + * set reversed token. + * + * @throws LogicalOperatorException Logical Operator Exception + */ + public void setReversedTokenIntType() throws LogicalOperatorException { + int intType = SQLConstant.reverseWords.get(tokenIntType); + setTokenIntType(intType); + reverseFunc(); + } + + protected void reverseFunc(){ + + } + @Override public boolean addChildOperator(FilterOperator op) { logger.error("cannot add child to leaf FilterOperator, now it's FunctionOperator"); diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java new file mode 100644 index 0000000..f86c719 --- /dev/null +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InOperator.java @@ -0,0 +1,213 @@ +/* + * 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.qp.logical.crud; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import org.apache.iotdb.db.exception.path.PathException; +import org.apache.iotdb.db.exception.query.LogicalOperatorException; +import org.apache.iotdb.db.exception.runtime.SQLParserException; +import org.apache.iotdb.db.qp.executor.IQueryProcessExecutor; +import org.apache.iotdb.db.qp.logical.Operator; +import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; +import org.apache.iotdb.tsfile.read.common.Path; +import org.apache.iotdb.tsfile.read.expression.IUnaryExpression; +import org.apache.iotdb.tsfile.read.expression.impl.GlobalTimeExpression; +import org.apache.iotdb.tsfile.read.expression.impl.SingleSeriesExpression; +import org.apache.iotdb.tsfile.read.filter.TimeFilter; +import org.apache.iotdb.tsfile.read.filter.ValueFilter; +import org.apache.iotdb.tsfile.read.filter.basic.Filter; +import org.apache.iotdb.tsfile.utils.Binary; +import org.apache.iotdb.tsfile.utils.Pair; +import org.apache.iotdb.tsfile.utils.StringContainer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * operator 'in' 'not in' + */ +public class InOperator extends FunctionOperator { + + private boolean not; + protected Set<String> values; + private String valueToString; + private Logger logger = LoggerFactory.getLogger(InOperator.class); + + /** + * In Operator Constructor. + * + * @param tokenIntType token in Int Type + * @param path path + * @param value value + * @throws LogicalOperatorException Logical Operator Exception + */ + public InOperator(int tokenIntType, Path path, boolean not, Set<String> values) + throws SQLParserException { + super(tokenIntType); + operatorType = Operator.OperatorType.IN; + this.path = path; + this.values = values; + this.not = not; + List<String> valuesList = new ArrayList<>(values); + Collections.sort(valuesList); + this.valueToString = valuesList.toString(); + isLeaf = true; + isSingle = true; + } + + public Set<String> getValues() { + return values; + } + + @Override + protected void reverseFunc(){ + not = !not; + } + + @Override + protected Pair<IUnaryExpression, String> transformToSingleQueryFilter( + IQueryProcessExecutor executor) throws LogicalOperatorException, PathException { + TSDataType type = executor.getSeriesType(path); + if (type == null) { + throw new PathException( + "given seriesPath:{" + path.getFullPath() + "} don't exist in metadata"); + } + IUnaryExpression ret; + + switch (type) { + case INT32: + Set<Integer> integerValues = new HashSet<>(); + for (String val : values) { + integerValues.add(Integer.valueOf(val)); + } + ret = In.getUnaryExpression(path, integerValues, not, valueToString); + break; + case INT64: + Set<Long> longValues = new HashSet<>(); + for (String val : values) { + longValues.add(Long.valueOf(val)); + } + ret = In.getUnaryExpression(path, longValues, not, valueToString); + break; + case BOOLEAN: + Set<Boolean> booleanValues = new HashSet<>(); + for (String val : values) { + booleanValues.add(Boolean.valueOf(val)); + } + ret = In.getUnaryExpression(path, booleanValues, not, valueToString); + break; + case FLOAT: + Set<Float> floatValues = new HashSet<>(); + for (String val : values) { + floatValues.add(Float.parseFloat(val)); + } + ret = In.getUnaryExpression(path, floatValues, not, valueToString); + break; + case DOUBLE: + Set<Double> doubleValues = new HashSet<>(); + for (String val : values) { + doubleValues.add(Double.parseDouble(val)); + } + ret = In.getUnaryExpression(path, doubleValues, not, valueToString); + break; + case TEXT: + Set<Binary> binaryValues = new HashSet<>(); + for (String val : values) { + binaryValues.add( + (val.startsWith("'") && val.endsWith("'")) || (val.startsWith("\"") && val + .endsWith("\"")) ? new Binary(val.substring(1, val.length() - 1)) + : new Binary(val)); + } + ret = In.getUnaryExpression(path, binaryValues, not, valueToString); + break; + default: + throw new LogicalOperatorException(type.toString(), ""); + } + + return new Pair<>(ret, path.getFullPath()); + } + + @Override + public String showTree(int spaceNum) { + StringContainer sc = new StringContainer(); + for (int i = 0; i < spaceNum; i++) { + sc.addTail(" "); + } + sc.addTail(path.toString(), this.tokenSymbol, not, valueToString, ", single\n"); + return sc.toString(); + } + + @Override + public InOperator clone() { + InOperator ret; + try { + ret = new InOperator(this.tokenIntType, path.clone(), not, new HashSet<>(values)); + } catch (SQLParserException e) { + logger.error("error clone:", e); + return null; + } + ret.tokenSymbol = tokenSymbol; + ret.isLeaf = isLeaf; + ret.isSingle = isSingle; + return ret; + } + + @Override + public String toString() { + return "[" + path.getFullPath() + tokenSymbol + not + valueToString + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InOperator that = (InOperator) o; + return Objects.equals(path, that.path) && Objects.equals(valueToString, that.valueToString) + && not == that.not; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), path, not, valueToString); + } + + private static class In { + + public static <T extends Comparable<T>> IUnaryExpression getUnaryExpression(Path path, + Set<T> values, boolean not, String valueToString) { + if (path.equals("time")) { + return new GlobalTimeExpression(TimeFilter.in((Set<Long>) values, not, valueToString)); + } else { + return new SingleSeriesExpression(path, ValueFilter.in(values, not, valueToString)); + } + } + + public <T extends Comparable<T>> Filter getValueFilter(T value) { + return ValueFilter.notEq(value); + } + } +} 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 509912e..349d2ed 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 @@ -23,8 +23,10 @@ import java.time.ZoneId; import java.util.ArrayList; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.exception.runtime.SQLParserException; @@ -35,6 +37,7 @@ import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator; import org.apache.iotdb.db.qp.logical.crud.DeleteDataOperator; import org.apache.iotdb.db.qp.logical.crud.FilterOperator; import org.apache.iotdb.db.qp.logical.crud.FromOperator; +import org.apache.iotdb.db.qp.logical.crud.InOperator; import org.apache.iotdb.db.qp.logical.crud.InsertOperator; import org.apache.iotdb.db.qp.logical.crud.QueryOperator; import org.apache.iotdb.db.qp.logical.crud.SelectOperator; @@ -88,6 +91,7 @@ import org.apache.iotdb.db.qp.strategy.SqlBaseParser.GrantUserContext; import org.apache.iotdb.db.qp.strategy.SqlBaseParser.GrantWatermarkEmbeddingContext; import org.apache.iotdb.db.qp.strategy.SqlBaseParser.GroupByClauseContext; import org.apache.iotdb.db.qp.strategy.SqlBaseParser.GroupByDeviceClauseContext; +import org.apache.iotdb.db.qp.strategy.SqlBaseParser.InClauseContext; import org.apache.iotdb.db.qp.strategy.SqlBaseParser.InsertColumnSpecContext; import org.apache.iotdb.db.qp.strategy.SqlBaseParser.InsertStatementContext; import org.apache.iotdb.db.qp.strategy.SqlBaseParser.InsertValuesSpecContext; @@ -181,7 +185,7 @@ public class LogicalGenerator extends SqlBaseBaseListener { @Override public void enterCountTimeseries(CountTimeseriesContext ctx) { super.enterCountTimeseries(ctx); - if(ctx.INT() != null) { + if (ctx.INT() != null) { initializedOperator = new CountOperator(SQLConstant.TOK_COUNT_NODE_TIMESERIES, parsePrefixPath(ctx.prefixPath()), Integer.parseInt(ctx.INT().getText())); } else { @@ -200,20 +204,24 @@ public class LogicalGenerator extends SqlBaseBaseListener { @Override public void enterShowDevices(ShowDevicesContext ctx) { super.enterShowDevices(ctx); - if(ctx.prefixPath() != null) { - initializedOperator = new ShowDevicesOperator(SQLConstant.TOK_DEVICES, parsePrefixPath(ctx.prefixPath())); + if (ctx.prefixPath() != null) { + initializedOperator = new ShowDevicesOperator(SQLConstant.TOK_DEVICES, + parsePrefixPath(ctx.prefixPath())); } else { - initializedOperator = new ShowDevicesOperator(SQLConstant.TOK_DEVICES, new Path(SQLConstant.ROOT)); + initializedOperator = new ShowDevicesOperator(SQLConstant.TOK_DEVICES, + new Path(SQLConstant.ROOT)); } } @Override public void enterShowChildPaths(ShowChildPathsContext ctx) { super.enterShowChildPaths(ctx); - if(ctx.prefixPath()!= null) { - initializedOperator = new ShowChildPathsOperator(SQLConstant.TOK_CHILD_PATHS, parsePrefixPath(ctx.prefixPath())); + if (ctx.prefixPath() != null) { + initializedOperator = new ShowChildPathsOperator(SQLConstant.TOK_CHILD_PATHS, + parsePrefixPath(ctx.prefixPath())); } else { - initializedOperator = new ShowChildPathsOperator(SQLConstant.TOK_CHILD_PATHS, new Path(SQLConstant.ROOT)); + initializedOperator = new ShowChildPathsOperator(SQLConstant.TOK_CHILD_PATHS, + new Path(SQLConstant.ROOT)); } } @@ -284,11 +292,12 @@ public class LogicalGenerator extends SqlBaseBaseListener { @Override public void enterShowTimeseries(ShowTimeseriesContext ctx) { super.enterShowTimeseries(ctx); - if(ctx.prefixPath() != null) { + if (ctx.prefixPath() != null) { initializedOperator = new ShowTimeSeriesOperator(SQLConstant.TOK_TIMESERIES, parsePrefixPath(ctx.prefixPath())); } else { - initializedOperator = new ShowTimeSeriesOperator(SQLConstant.TOK_TIMESERIES, new Path("root")); + initializedOperator = new ShowTimeSeriesOperator(SQLConstant.TOK_TIMESERIES, + new Path("root")); } } @@ -384,7 +393,7 @@ public class LogicalGenerator extends SqlBaseBaseListener { super.enterAlterUser(ctx); AuthorOperator authorOperator = new AuthorOperator(SQLConstant.TOK_AUTHOR_UPDATE_USER, AuthorOperator.AuthorType.UPDATE_USER); - if(ctx.ID() != null) { + if (ctx.ID() != null) { authorOperator.setUserName(ctx.ID().getText()); } else { authorOperator.setUserName(ctx.ROOT().getText()); @@ -1167,28 +1176,49 @@ public class LogicalGenerator extends SqlBaseBaseListener { return parseOrExpression(ctx.orExpression()); } else { Path path = null; - BasicFunctionOperator basic = null; if (ctx.prefixPath() != null) { path = parsePrefixPath(ctx.prefixPath()); } if (ctx.suffixPath() != null) { path = parseSuffixPath(ctx.suffixPath()); } - if (ctx.constant().dateExpression() != null) { + if (ctx.inClause() != null) { + return parseInOperator(ctx.inClause(), path); + } else { + return parseBasicFunctionOperator(ctx, path); + } + } + } + + private FilterOperator parseInOperator(InClauseContext ctx, Path path) { + Set<String> values = new HashSet<>(); + boolean not = ctx.OPERATOR_NOT() != null; + for (ConstantContext constant : ctx.constant()) { + if (constant.dateExpression() != null) { if (!path.equals(SQLConstant.RESERVED_TIME)) { throw new SQLParserException(path.toString(), "Date can only be used to time"); } - basic = new BasicFunctionOperator(ctx.comparisonOperator().type.getType(), path, - Long.toString(parseDateExpression(ctx.constant().dateExpression()))); + values.add(Long.toString(parseDateExpression(constant.dateExpression()))); } else { - basic = new BasicFunctionOperator(ctx.comparisonOperator().type.getType(), path, - ctx.constant().getText()); + values.add(constant.getText()); } - if (!isNotWhereClause && !isAndWhereClause && !isOrWhereClause) { - return basic; + } + return new InOperator(ctx.OPERATOR_IN().getSymbol().getType(), path, not, values); + } + + private FilterOperator parseBasicFunctionOperator(PredicateContext ctx, Path path) { + BasicFunctionOperator basic; + if (ctx.constant().dateExpression() != null) { + if (!path.equals(SQLConstant.RESERVED_TIME)) { + throw new SQLParserException(path.toString(), "Date can only be used to time"); } - return basic; + basic = new BasicFunctionOperator(ctx.comparisonOperator().type.getType(), path, + Long.toString(parseDateExpression(ctx.constant().dateExpression()))); + } else { + basic = new BasicFunctionOperator(ctx.comparisonOperator().type.getType(), path, + ctx.constant().getText()); } + return basic; } private Path parseSuffixPath(SuffixPathContext ctx) { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java index 8b4d8f6..8b11890 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java @@ -392,7 +392,7 @@ public class PhysicalGenerator { return operator; } BasicFunctionOperator basicOperator = (BasicFunctionOperator) operator; - Path filterPath = basicOperator.getSinglePath(); + Path filterPath = basicOperator.getPath(); // do nothing in the cases of "where time > 5" or "where root.d1.s1 > 5" if (SQLConstant.isReservedPath(filterPath) || filterPath.startWith(SQLConstant.ROOT)) { @@ -400,7 +400,7 @@ public class PhysicalGenerator { } Path concatPath = filterPath.addPrefixPath(filterPath, prefix); - basicOperator.setSinglePath(concatPath); + basicOperator.setPath(concatPath); return basicOperator; } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java index 81e3041..6d5e7f9 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java @@ -216,8 +216,8 @@ public class ConcatPathOptimizer implements ILogicalOptimizer { operator.setChildren(newFilterList); return operator; } - BasicFunctionOperator basicOperator = (BasicFunctionOperator) operator; - Path filterPath = basicOperator.getSinglePath(); + FunctionOperator functionOperator = (FunctionOperator) operator; + Path filterPath = functionOperator.getPath(); // do nothing in the cases of "where time > 5" or "where root.d1.s1 > 5" if (SQLConstant.isReservedPath(filterPath) || filterPath.startWith(SQLConstant.ROOT)) { return operator; @@ -228,7 +228,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer { if (noStarPaths.size() == 1) { // Transform "select s1 from root.car.* where s1 > 10" to // "select s1 from root.car.* where root.car.*.s1 > 10" - basicOperator.setSinglePath(noStarPaths.get(0)); + functionOperator.setPath(noStarPaths.get(0)); return operator; } else { // Transform "select s1 from root.car.d1, root.car.d2 where s1 > 10" to diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/MergeSingleFilterOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/MergeSingleFilterOptimizer.java index d2e3046..298eaa9 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/MergeSingleFilterOptimizer.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/MergeSingleFilterOptimizer.java @@ -57,7 +57,7 @@ public class MergeSingleFilterOptimizer implements IFilterOptimizer { */ private Path mergeSamePathFilter(FilterOperator filter) throws LogicalOptimizeException { if (filter.isLeaf()) { - return filter.getSinglePath(); + return filter.getPath(); } List<FilterOperator> children = filter.getChildren(); checkInnerFilterLen(children); @@ -73,14 +73,14 @@ public class MergeSingleFilterOptimizer implements IFilterOptimizer { } if (childPath != null) { filter.setIsSingle(true); - filter.setSinglePath(childPath); + filter.setPath(childPath); return childPath; } // sort paths of BasicFunction by their single seriesPath. We don't sort children on non-leaf // layer. if (!children.isEmpty() && allIsBasic(children)) { - children.sort(Comparator.comparing(o -> o.getSinglePath().getFullPath())); + children.sort(Comparator.comparing(o -> o.getPath().getFullPath())); } List<FilterOperator> ret = new ArrayList<>(); int firstNonSingleIndex = mergeSingleFilters(ret, filter); @@ -96,7 +96,7 @@ public class MergeSingleFilterOptimizer implements IFilterOptimizer { Path childPath = null; int firstNonSingleIndex; for (firstNonSingleIndex = 0; firstNonSingleIndex < children.size(); firstNonSingleIndex++) { - tempPath = children.get(firstNonSingleIndex).getSinglePath(); + tempPath = children.get(firstNonSingleIndex).getPath(); // sorted by seriesPath, all non-single filters are in the end if (tempPath == null) { break; @@ -124,7 +124,7 @@ public class MergeSingleFilterOptimizer implements IFilterOptimizer { } else { // add a new inner node FilterOperator newFilter = new FilterOperator(filter.getTokenIntType(), true); - newFilter.setSinglePath(childPath); + newFilter.setPath(childPath); newFilter.setChildren(tempExtrNode); ret.add(newFilter); tempExtrNode = new ArrayList<>(); @@ -140,7 +140,7 @@ public class MergeSingleFilterOptimizer implements IFilterOptimizer { } else { // add a new inner node FilterOperator newFil = new FilterOperator(filter.getTokenIntType(), true); - newFil.setSinglePath(childPath); + newFil.setPath(childPath); newFil.setChildren(tempExtrNode); ret.add(newFil); } @@ -157,7 +157,7 @@ public class MergeSingleFilterOptimizer implements IFilterOptimizer { if (ret.size() == 1) { // all children have same seriesPath, which means this filter node is a single node filter.setIsSingle(true); - filter.setSinglePath(childPath); + filter.setPath(childPath); filter.setChildren(ret.get(0).getChildren()); return childPath; } else { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java index 9b1fde7..5b85bcf 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java @@ -28,6 +28,7 @@ import org.apache.iotdb.db.exception.query.LogicalOptimizeException; import org.apache.iotdb.db.qp.constant.SQLConstant; 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.FunctionOperator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,7 +79,7 @@ public class RemoveNotOptimizer implements IFilterOptimizer { int tokenInt = filter.getTokenIntType(); if (filter.isLeaf()) { try { - ((BasicFunctionOperator) filter).setReversedTokenIntType(); + ((FunctionOperator)filter).setReversedTokenIntType(); } catch (LogicalOperatorException e) { logger.error("meet error while converting BasicFunction.", e); throw new LogicalOperatorException( diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQueryDemoIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQueryDemoIT.java index 77191a6..de7832a 100644 --- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQueryDemoIT.java +++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBQueryDemoIT.java @@ -233,7 +233,6 @@ public class IoTDBQueryDemoIT { for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { builder.append(resultSet.getString(i)).append(","); } - System.out.println(builder.toString()); Assert.assertEquals(retArray[cnt], builder.toString()); cnt++; } @@ -251,7 +250,6 @@ public class IoTDBQueryDemoIT { for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { header.append(resultSetMetaData.getColumnName(i)).append(","); } - System.out.println(header.toString()); Assert.assertEquals( "Time,root.ln.wf01.wt01.status,root.ln.wf01.wt01.temperature," + "root.ln.wf02.wt02.hardware,root.ln.wf02.wt02.status,root.sgcc.wf03.wt01.status," @@ -270,7 +268,96 @@ public class IoTDBQueryDemoIT { for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { builder.append(resultSet.getString(i)).append(","); } - System.out.println(builder.toString()); + Assert.assertEquals(retArray[cnt], builder.toString()); + cnt++; + } + Assert.assertEquals(5, cnt); + } + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void InTest() throws ClassNotFoundException { + String[] retArray = new String[]{ + "1509465780000,false,20.18,v1,false,false,20.18,", + "1509465840000,false,21.13,v1,false,false,21.13,", + "1509465900000,false,22.72,v1,false,false,22.72,", + "1509465960000,false,20.71,v1,false,false,20.71,", + "1509466020000,false,21.45,v1,false,false,21.45,", + }; + + Class.forName(Config.JDBC_DRIVER_NAME); + try (Connection connection = DriverManager + .getConnection(Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + + // test 1: fetchSize < limitNumber + statement.setFetchSize(4); + Assert.assertEquals(4, statement.getFetchSize()); + boolean hasResultSet = statement.execute("select * from root where time in (1509465780000, 1509465840000, 1509465900000, 1509465960000, 1509466020000)"); + Assert.assertTrue(hasResultSet); + try (ResultSet resultSet = statement.getResultSet()) { + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + StringBuilder header = new StringBuilder(); + for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { + header.append(resultSetMetaData.getColumnName(i)).append(","); + } + Assert.assertEquals( + "Time,root.ln.wf01.wt01.status,root.ln.wf01.wt01.temperature," + + "root.ln.wf02.wt02.hardware,root.ln.wf02.wt02.status,root.sgcc.wf03.wt01.status," + + "root.sgcc.wf03.wt01.temperature,", header.toString()); + Assert.assertEquals(Types.TIMESTAMP, resultSetMetaData.getColumnType(1)); + Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(2)); + Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(3)); + Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(4)); + Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(5)); + Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(6)); + Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7)); + + int cnt = 0; + while (resultSet.next()) { + StringBuilder builder = new StringBuilder(); + for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { + builder.append(resultSet.getString(i)).append(","); + } + Assert.assertEquals(retArray[cnt], builder.toString()); + cnt++; + } + Assert.assertEquals(5, cnt); + } + + // test 1: fetchSize > limitNumber + statement.setFetchSize(10000); + Assert.assertEquals(10000, statement.getFetchSize()); + hasResultSet = statement.execute("select * from root where time>10 limit 5 offset 3"); + Assert.assertTrue(hasResultSet); + try (ResultSet resultSet = statement.getResultSet()) { + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + StringBuilder header = new StringBuilder(); + for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { + header.append(resultSetMetaData.getColumnName(i)).append(","); + } + Assert.assertEquals( + "Time,root.ln.wf01.wt01.status,root.ln.wf01.wt01.temperature," + + "root.ln.wf02.wt02.hardware,root.ln.wf02.wt02.status,root.sgcc.wf03.wt01.status," + + "root.sgcc.wf03.wt01.temperature,", header.toString()); + Assert.assertEquals(Types.TIMESTAMP, resultSetMetaData.getColumnType(1)); + Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(2)); + Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(3)); + Assert.assertEquals(Types.VARCHAR, resultSetMetaData.getColumnType(4)); + Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(5)); + Assert.assertEquals(Types.BOOLEAN, resultSetMetaData.getColumnType(6)); + Assert.assertEquals(Types.FLOAT, resultSetMetaData.getColumnType(7)); + + int cnt = 0; + while (resultSet.next()) { + StringBuilder builder = new StringBuilder(); + for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { + builder.append(resultSet.getString(i)).append(","); + } Assert.assertEquals(retArray[cnt], builder.toString()); cnt++; } diff --git a/server/src/test/java/org/apache/iotdb/db/qp/plan/PhysicalPlanTest.java b/server/src/test/java/org/apache/iotdb/db/qp/plan/PhysicalPlanTest.java index 9f38f50..f6f3ce2 100644 --- a/server/src/test/java/org/apache/iotdb/db/qp/plan/PhysicalPlanTest.java +++ b/server/src/test/java/org/apache/iotdb/db/qp/plan/PhysicalPlanTest.java @@ -23,6 +23,11 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.apache.iotdb.db.exception.StartupException; import org.apache.iotdb.db.exception.metadata.MetadataException; import org.apache.iotdb.db.exception.query.QueryProcessException; @@ -510,6 +515,51 @@ public class PhysicalPlanTest { } @Test + public void testInOperator() throws QueryProcessException { + String sqlStr = "SELECT s1 FROM root.vehicle.d1 WHERE s1 in (25, 30, 40)"; + PhysicalPlan plan = processor.parseSQLToPhysicalPlan(sqlStr); + IExpression queryFilter = ((QueryPlan) plan).getExpression(); + List<String> valuesList = new ArrayList<>(); + valuesList.add("25"); + valuesList.add("30"); + valuesList.add("40"); + Collections.sort(valuesList); + Set<Float> values = new HashSet<>(); + values.add(25.0f); + values.add(30.0f); + values.add(40.0f); + IExpression expect = new SingleSeriesExpression(new Path("root.vehicle.d1.s1"), + ValueFilter.in(values, false, valuesList.toString())); + assertEquals(expect.toString(), queryFilter.toString()); + } + + @Test + public void testNotInOperator() throws QueryProcessException { + String sqlStr = "SELECT s1 FROM root.vehicle.d1 WHERE s1 not in (25, 30, 40)"; + PhysicalPlan plan = processor.parseSQLToPhysicalPlan(sqlStr); + IExpression queryFilter = ((QueryPlan) plan).getExpression(); + List<String> valuesList = new ArrayList<>(); + valuesList.add("25"); + valuesList.add("30"); + valuesList.add("40"); + Collections.sort(valuesList); + Set<Float> values = new HashSet<>(); + values.add(25.0f); + values.add(30.0f); + values.add(40.0f); + IExpression expect = new SingleSeriesExpression(new Path("root.vehicle.d1.s1"), + ValueFilter.in(values, true, valuesList.toString())); + assertEquals(expect.toString(), queryFilter.toString()); + + sqlStr = "SELECT s1 FROM root.vehicle.d1 WHERE not(s1 not in (25, 30, 40))"; + plan = processor.parseSQLToPhysicalPlan(sqlStr); + queryFilter = ((QueryPlan) plan).getExpression(); + expect = new SingleSeriesExpression(new Path("root.vehicle.d1.s1"), + ValueFilter.in(values, false, valuesList.toString())); + assertEquals(expect.toString(), queryFilter.toString()); + } + + @Test public void testGrantWatermarkEmbedding() throws QueryProcessException, MetadataException { String sqlStr = "GRANT WATERMARK_EMBEDDING to a,b"; diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/TimeFilter.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/TimeFilter.java index d2a663a..007c813 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/TimeFilter.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/TimeFilter.java @@ -18,11 +18,13 @@ */ package org.apache.iotdb.tsfile.read.filter; +import java.util.Set; import org.apache.iotdb.tsfile.read.filter.basic.Filter; import org.apache.iotdb.tsfile.read.filter.factory.FilterType; import org.apache.iotdb.tsfile.read.filter.operator.Eq; import org.apache.iotdb.tsfile.read.filter.operator.Gt; import org.apache.iotdb.tsfile.read.filter.operator.GtEq; +import org.apache.iotdb.tsfile.read.filter.operator.In; import org.apache.iotdb.tsfile.read.filter.operator.Lt; import org.apache.iotdb.tsfile.read.filter.operator.LtEq; import org.apache.iotdb.tsfile.read.filter.operator.NotEq; @@ -58,6 +60,17 @@ public class TimeFilter { return new TimeNotEq(value); } + public static TimeIn in(Set<Long> values, boolean not, String valueToString) { + return new TimeIn(values, not, valueToString); + } + + public static class TimeIn extends In { + + private TimeIn(Set<Long> values, boolean not, String valueToString) { + super(values, FilterType.TIME_FILTER,not, valueToString); + } + } + public static class TimeEq extends Eq { private TimeEq(long value) { diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java index 18b1285..fa0c7c4 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/ValueFilter.java @@ -18,11 +18,13 @@ */ package org.apache.iotdb.tsfile.read.filter; +import java.util.Set; import org.apache.iotdb.tsfile.read.filter.basic.Filter; import org.apache.iotdb.tsfile.read.filter.factory.FilterType; import org.apache.iotdb.tsfile.read.filter.operator.Eq; import org.apache.iotdb.tsfile.read.filter.operator.Gt; import org.apache.iotdb.tsfile.read.filter.operator.GtEq; +import org.apache.iotdb.tsfile.read.filter.operator.In; import org.apache.iotdb.tsfile.read.filter.operator.Lt; import org.apache.iotdb.tsfile.read.filter.operator.LtEq; import org.apache.iotdb.tsfile.read.filter.operator.NotEq; @@ -50,6 +52,10 @@ public class ValueFilter { return new ValueLtEq(value); } + public static <T extends Comparable<T>> ValueIn<T> in(Set<T> values, boolean not, String valueToString){ + return new ValueIn(values, not, valueToString); + } + public static ValueNotFilter not(Filter filter) { return new ValueNotFilter(filter); } @@ -58,6 +64,13 @@ public class ValueFilter { return new ValueNotEq(value); } + public static class ValueIn<T extends Comparable<T>> extends In<T> { + + private ValueIn(Set<T> values, boolean not, String valueToString) { + super(values, FilterType.VALUE_FILTER, not, valueToString); + } + } + public static class ValueEq<T extends Comparable<T>> extends Eq<T> { private ValueEq(T value) { diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterFactory.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterFactory.java index 7781e42..07f849a 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterFactory.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterFactory.java @@ -30,8 +30,6 @@ import org.apache.iotdb.tsfile.read.filter.operator.LtEq; import org.apache.iotdb.tsfile.read.filter.operator.NotEq; import org.apache.iotdb.tsfile.read.filter.operator.NotFilter; import org.apache.iotdb.tsfile.read.filter.operator.OrFilter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class FilterFactory { diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterSerializeId.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterSerializeId.java index 1b20251..a76f1fa 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterSerializeId.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/factory/FilterSerializeId.java @@ -20,5 +20,5 @@ package org.apache.iotdb.tsfile.read.filter.factory; public enum FilterSerializeId { - AND, EQ, GROUP_BY, GT, GTEQ, LT, LTEQ, NEQ, NOT, OR + AND, EQ, GROUP_BY, GT, GTEQ, LT, LTEQ, NEQ, NOT, OR, IN } diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java index 9a6cc0e..931d046 100755 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java @@ -18,7 +18,6 @@ */ package org.apache.iotdb.tsfile.read.filter.operator; -import java.util.Objects; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; import org.apache.iotdb.tsfile.file.metadata.statistics.Statistics; import org.apache.iotdb.tsfile.read.filter.basic.Filter; @@ -45,7 +44,8 @@ public class Eq<T extends Comparable<T>> extends UnaryFilter<T> { @Override public boolean satisfy(Statistics statistics) { if (filterType == FilterType.TIME_FILTER) { - return ((Long) value) >= statistics.getStartTime() && ((Long) value) <= statistics.getEndTime(); + return ((Long) value) >= statistics.getStartTime() && ((Long) value) <= statistics + .getEndTime(); } else { if (statistics.getType() == TSDataType.TEXT || statistics.getType() == TSDataType.BOOLEAN) { return true; diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/In.java old mode 100755 new mode 100644 similarity index 50% copy from tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java copy to tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/In.java index 9a6cc0e..eb2c4c8 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/Eq.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/filter/operator/In.java @@ -18,81 +18,105 @@ */ package org.apache.iotdb.tsfile.read.filter.operator; -import java.util.Objects; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashSet; +import java.util.Set; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; import org.apache.iotdb.tsfile.file.metadata.statistics.Statistics; import org.apache.iotdb.tsfile.read.filter.basic.Filter; -import org.apache.iotdb.tsfile.read.filter.basic.UnaryFilter; import org.apache.iotdb.tsfile.read.filter.factory.FilterSerializeId; import org.apache.iotdb.tsfile.read.filter.factory.FilterType; +import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils; /** - * Equals. + * in clause. * * @param <T> comparable data type */ -public class Eq<T extends Comparable<T>> extends UnaryFilter<T> { +public class In<T extends Comparable<T>> implements Filter { - private static final long serialVersionUID = -6668083116644568248L; + private static final long serialVersionUID = 8572705136773595399L; - public Eq() { + private Set<T> values; + + private boolean not; + + private String valueToString; + + private FilterType filterType; + + public In() { } - public Eq(T value, FilterType filterType) { - super(value, filterType); + public In(Set<T> values, FilterType filterType, boolean not, String valueToString) { + this.values = values; + this.filterType = filterType; + this.not = not; + this.valueToString = valueToString; } @Override public boolean satisfy(Statistics statistics) { - if (filterType == FilterType.TIME_FILTER) { - return ((Long) value) >= statistics.getStartTime() && ((Long) value) <= statistics.getEndTime(); - } else { - if (statistics.getType() == TSDataType.TEXT || statistics.getType() == TSDataType.BOOLEAN) { - return true; - } - return value.compareTo((T) statistics.getMinValue()) >= 0 - && value.compareTo((T) statistics.getMaxValue()) <= 0; - } + return true; } @Override public boolean satisfy(long time, Object value) { Object v = filterType == FilterType.TIME_FILTER ? time : value; - return this.value.equals(v); + return this.values.contains(v) != not; } @Override public boolean satisfyStartEndTime(long startTime, long endTime) { - if (filterType == FilterType.TIME_FILTER) { - long time = (Long) value; - return time <= endTime && time >= startTime; - } else { - return true; - } + return true; } @Override public boolean containStartEndTime(long startTime, long endTime) { - if (filterType == FilterType.TIME_FILTER) { - long time = (Long) value; - return time == startTime && time == endTime; - } else { - return true; - } + return true; } @Override public Filter clone() { - return new Eq(value, filterType); + return new In(values, filterType, not, valueToString); + } + + @Override + public void serialize(DataOutputStream outputStream) { + try { + outputStream.write(getSerializeId().ordinal()); + outputStream.write(filterType.ordinal()); + ReadWriteIOUtils.write(not, outputStream); + ReadWriteIOUtils.write(valueToString, outputStream); + outputStream.write(values.size()); + for (T value : values) { + ReadWriteIOUtils.writeObject(value, outputStream); + } + } catch (IOException ignored) { + // ignored + } + } + + @Override + public void deserialize(ByteBuffer buffer) { + filterType = FilterType.values()[buffer.get()]; + not = ReadWriteIOUtils.readBool(buffer); + valueToString = ReadWriteIOUtils.readString(buffer); + values = new HashSet<>(); + for (int i = 0; i < buffer.get(); i++) { + values.add((T) ReadWriteIOUtils.readObject(buffer)); + } } @Override public String toString() { - return getFilterType() + " == " + value; + return filterType + " < " + "reverse: " + not + ", " + valueToString; } @Override public FilterSerializeId getSerializeId() { - return FilterSerializeId.EQ; + return FilterSerializeId.IN; } }
