This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch QueryWithoutNull in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 7dff4607e20afc1db57cf4b0f7dd7083b9b99e38 Author: JackieTien97 <[email protected]> AuthorDate: Fri May 7 08:58:20 2021 +0800 init --- .../antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 | 11 +- .../apache/iotdb/db/qp/executor/PlanExecutor.java | 88 ++++---- .../iotdb/db/qp/logical/crud/QueryOperator.java | 20 ++ .../iotdb/db/qp/physical/crud/QueryPlan.java | 20 ++ .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 181 ++++++++++++++-- .../iotdb/db/qp/strategy/PhysicalGenerator.java | 5 +- .../dataset/RawQueryDataSetWithoutValueFilter.java | 79 +++++-- .../apache/iotdb/db/utils/QueryDataSetUtils.java | 22 +- .../db/integration/IoTDBWithoutAnyNullIT.java | 227 +++++++++++++++++++++ .../apache/iotdb/tsfile/read/common/RowRecord.java | 38 +++- .../tsfile/read/query/dataset/QueryDataSet.java | 22 ++ 11 files changed, 606 insertions(+), 107 deletions(-) diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 index c753069..67a9a10 100644 --- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 +++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 @@ -106,7 +106,8 @@ statement | SELECT topClause? selectElements fromClause whereClause? - specialClause? #selectStatement + specialClause? + WITHOUT (ALL | ANY) NULL #selectStatement ; selectElements @@ -1308,6 +1309,14 @@ NULL : N U L L ; +WITHOUT + : W I T H O U T + ; + +ANY + : A N Y + ; + //============================ // End of the keywords list //============================ diff --git a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java index 456e69b..4eb68ad 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java @@ -18,6 +18,48 @@ */ package org.apache.iotdb.db.qp.executor; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CANCELLED; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CHILD_NODES; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CHILD_PATHS; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_COLUMN; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_COUNT; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CREATED_TIME; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_DEVICES; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_DONE; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_FUNCTION_CLASS; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_FUNCTION_NAME; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_FUNCTION_TYPE; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_ITEM; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_PRIVILEGE; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_PROGRESS; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_ROLE; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_STORAGE_GROUP; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_TASK_NAME; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_TTL; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_USER; +import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_VALUE; +import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_UDAF; +import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_UDTF; +import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_EXTERNAL_UDAF; +import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_EXTERNAL_UDTF; +import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_NATIVE; +import static org.apache.iotdb.db.conf.IoTDBConstant.QUERY_ID; +import static org.apache.iotdb.db.conf.IoTDBConstant.STATEMENT; +import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.TSFILE_SUFFIX; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import org.apache.iotdb.db.auth.AuthException; import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.auth.authorizer.BasicAuthorizer; @@ -147,53 +189,9 @@ import org.apache.iotdb.tsfile.utils.Binary; import org.apache.iotdb.tsfile.utils.Pair; import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema; import org.apache.iotdb.tsfile.write.writer.RestorableTsFileIOWriter; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CANCELLED; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CHILD_NODES; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CHILD_PATHS; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_COLUMN; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_COUNT; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_CREATED_TIME; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_DEVICES; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_DONE; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_FUNCTION_CLASS; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_FUNCTION_NAME; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_FUNCTION_TYPE; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_ITEM; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_PRIVILEGE; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_PROGRESS; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_ROLE; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_STORAGE_GROUP; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_TASK_NAME; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_TTL; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_USER; -import static org.apache.iotdb.db.conf.IoTDBConstant.COLUMN_VALUE; -import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_UDAF; -import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_BUILTIN_UDTF; -import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_EXTERNAL_UDAF; -import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_EXTERNAL_UDTF; -import static org.apache.iotdb.db.conf.IoTDBConstant.FUNCTION_TYPE_NATIVE; -import static org.apache.iotdb.db.conf.IoTDBConstant.QUERY_ID; -import static org.apache.iotdb.db.conf.IoTDBConstant.STATEMENT; -import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.TSFILE_SUFFIX; - public class PlanExecutor implements IPlanExecutor { private static final Logger logger = LoggerFactory.getLogger(PlanExecutor.class); @@ -542,6 +540,8 @@ public class PlanExecutor implements IPlanExecutor { } queryDataSet.setRowLimit(queryPlan.getRowLimit()); queryDataSet.setRowOffset(queryPlan.getRowOffset()); + queryDataSet.setWithoutAllNull(queryPlan.isWithoutAllNull()); + queryDataSet.setWithoutAnyNull(queryPlan.isWithoutAnyNull()); return queryDataSet; } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java index 87aa1d9..c71805c 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java @@ -62,6 +62,10 @@ public class QueryOperator extends SFWOperator { private IndexType indexType; + private boolean withoutAnyNull; + + private boolean withoutAllNull; + public QueryOperator(int tokenIntType) { super(tokenIntType); operatorType = Operator.OperatorType.QUERY; @@ -250,4 +254,20 @@ public class QueryOperator extends SFWOperator { public void setAscending(boolean ascending) { this.ascending = ascending; } + + public boolean isWithoutAnyNull() { + return withoutAnyNull; + } + + public void setWithoutAnyNull(boolean withoutAnyNull) { + this.withoutAnyNull = withoutAnyNull; + } + + public boolean isWithoutAllNull() { + return withoutAllNull; + } + + public void setWithoutAllNull(boolean withoutAllNull) { + this.withoutAllNull = withoutAllNull; + } } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java index 2de90a5..9dfac95 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java @@ -46,6 +46,10 @@ public abstract class QueryPlan extends PhysicalPlan { private boolean enableRedirect = false; + private boolean withoutAnyNull; + + private boolean withoutAllNull; + public QueryPlan() { super(true); setOperatorType(Operator.OperatorType.QUERY); @@ -150,4 +154,20 @@ public abstract class QueryPlan extends PhysicalPlan { public void setVectorPathToIndex(Map<String, Integer> vectorPathToIndex) { this.vectorPathToIndex = vectorPathToIndex; } + + public boolean isWithoutAnyNull() { + return withoutAnyNull; + } + + public void setWithoutAnyNull(boolean withoutAnyNull) { + this.withoutAnyNull = withoutAnyNull; + } + + public boolean isWithoutAllNull() { + return withoutAllNull; + } + + public void setWithoutAllNull(boolean withoutAllNull) { + this.withoutAllNull = withoutAllNull; + } } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java index 9003016..5ce5665 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java @@ -18,6 +18,24 @@ */ package org.apache.iotdb.db.qp.sql; +import static org.apache.iotdb.db.index.common.IndexConstant.PATTERN; +import static org.apache.iotdb.db.index.common.IndexConstant.THRESHOLD; +import static org.apache.iotdb.db.index.common.IndexConstant.TOP_K; +import static org.apache.iotdb.db.qp.constant.SQLConstant.TIME_PATH; +import static org.apache.iotdb.db.qp.constant.SQLConstant.TOK_KILL_QUERY; + +import java.io.File; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import org.antlr.v4.runtime.tree.TerminalNode; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.engine.trigger.executor.TriggerEvent; import org.apache.iotdb.db.exception.index.UnsupportedIndexTypeException; @@ -78,7 +96,144 @@ import org.apache.iotdb.db.qp.logical.sys.StartTriggerOperator; import org.apache.iotdb.db.qp.logical.sys.StopTriggerOperator; import org.apache.iotdb.db.qp.logical.sys.TracingOperator; import org.apache.iotdb.db.qp.physical.crud.GroupByTimePlan; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.*; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AggregationCallContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AggregationElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AliasClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseOrDisableAlignInSpecialLimitContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceStatementOrDisableAlignInSpecialClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterTimeseriesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AndExpressionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AsClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AsElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AttributeClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.AttributeClausesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.BuiltInFunctionCallContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ClearcacheContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ConstantContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CountDevicesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CountNodesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CountStorageGroupContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CountTimeseriesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateFunctionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateIndexContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateSnapshotContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateTimeseriesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateTriggerContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.CreateUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DateExpressionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DeletePartitionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DeleteStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DeleteStorageGroupContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DeleteTimeseriesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropFunctionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropIndexContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropTriggerContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FillClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FillStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FlushContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FromClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FullMergeContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FullPathContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAsClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAsElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleToUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantWatermarkEmbeddingContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByFillClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByFillStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByLevelClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByLevelStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByTimeClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.GroupByTimeStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.InClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.IndexPredicateClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.IndexWithClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertColumnsSpecContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertMultiValueContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertValuesSpecContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.KillQueryContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LastClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LastElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LimitClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LimitStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListAllRoleOfUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListAllUserOfRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListPrivilegesRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListPrivilegesUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListRolePrivilegesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListUserPrivilegesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LoadConfigurationStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LoadFilesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.LoadStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.MeasurementNameContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.MeasurementValueContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.MergeContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.MoveFileContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.NodeNameContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.NodeNameWithoutStarContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.OffsetClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.OrExpressionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.OrderByTimeClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.OrderByTimeStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.PredicateContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.PrefixPathContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.PrivilegesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.PropertyContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.PropertyValueContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.RemoveFileContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeRoleContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeRoleFromUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeWatermarkEmbeddingContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.RootOrIdContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SelectStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SequenceClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SetStorageGroupContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SetTTLStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowAllTTLStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowChildNodesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowChildPathsContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowDevicesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowFlushTaskInfoContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowFunctionsContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowMergeStatusContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowQueryProcesslistContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowStorageGroupContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowTTLStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowTimeseriesContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowTriggersContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowVersionContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ShowWhereClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SingleStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SlimitClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SlimitStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SoffsetClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SpecialLimitStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.StartTriggerContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.StopTriggerContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.StringLiteralContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SuffixPathContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TableCallContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TableElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TagClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TimeIntervalContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TracingOffContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TracingOnContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TriggerAttributeContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TypeClauseContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.UdfAttributeContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.UdfCallContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.UnsetTTLStatementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.WhereClauseContext; import org.apache.iotdb.db.qp.utils.DatetimeUtils; import org.apache.iotdb.db.query.executor.fill.IFill; import org.apache.iotdb.db.query.executor.fill.LinearFill; @@ -92,26 +247,6 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding; import org.apache.iotdb.tsfile.utils.Pair; import org.apache.iotdb.tsfile.utils.StringContainer; -import org.antlr.v4.runtime.tree.TerminalNode; - -import java.io.File; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import static org.apache.iotdb.db.index.common.IndexConstant.PATTERN; -import static org.apache.iotdb.db.index.common.IndexConstant.THRESHOLD; -import static org.apache.iotdb.db.index.common.IndexConstant.TOP_K; -import static org.apache.iotdb.db.qp.constant.SQLConstant.TIME_PATH; -import static org.apache.iotdb.db.qp.constant.SQLConstant.TOK_KILL_QUERY; - public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { private static final String DELETE_RANGE_ERROR_MSG = @@ -893,6 +1028,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { if (ctx.specialClause() != null) { visit(ctx.specialClause()); } + if (ctx.WITHOUT() != null) { + queryOp.setWithoutAllNull(ctx.ALL() != null); + queryOp.setWithoutAnyNull(ctx.ANY() != null); + } return queryOp; } 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 fdb331b..217a3bb 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 @@ -540,7 +540,7 @@ public class PhysicalGenerator { @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning private PhysicalPlan transformQuery(QueryOperator queryOperator) throws QueryProcessException { - QueryPlan queryPlan = null; + QueryPlan queryPlan; if (queryOperator.hasAggregation()) { queryPlan = new AggPhysicalPlanRule().transform(queryOperator); @@ -587,6 +587,9 @@ public class PhysicalGenerator { } } + queryPlan.setWithoutAllNull(queryOperator.isWithoutAllNull()); + queryPlan.setWithoutAnyNull(queryOperator.isWithoutAnyNull()); + if (queryOperator.getIndexType() != null) { if (queryPlan instanceof QueryIndexPlan) { ((QueryIndexPlan) queryPlan).setIndexType(queryOperator.getIndexType()); diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/RawQueryDataSetWithoutValueFilter.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/RawQueryDataSetWithoutValueFilter.java index dbcea9d..73435ec 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/dataset/RawQueryDataSetWithoutValueFilter.java +++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/RawQueryDataSetWithoutValueFilter.java @@ -57,7 +57,7 @@ public class RawQueryDataSetWithoutValueFilter extends QueryDataSet private final ManagedSeriesReader reader; private final String pathName; - private BlockingQueue<BatchData> blockingQueue; + private final BlockingQueue<BatchData> blockingQueue; public ReadTask( ManagedSeriesReader reader, BlockingQueue<BatchData> blockingQueue, String pathName) { @@ -256,6 +256,10 @@ public class RawQueryDataSetWithoutValueFilter extends QueryDataSet long minTime = timeHeap.pollFirst(); + if (withoutAnyNull && filterRowRecord(seriesNum, minTime)) { + continue; + } + if (rowOffset == 0) { timeBAOS.write(BytesUtils.longToBytes(minTime)); } @@ -388,22 +392,7 @@ public class RawQueryDataSetWithoutValueFilter extends QueryDataSet } } - // move next - cachedBatchDataArray[seriesIndex].next(); - - // check the interrupted status of query before taking next batch - QueryTimeManager.checkQueryAlive(queryId); - - // get next batch if current batch is empty and still have remaining batch data in queue - if (!cachedBatchDataArray[seriesIndex].hasCurrent() - && !noMoreDataInQueueArray[seriesIndex]) { - fillCache(seriesIndex); - } - - // try to put the next timestamp into the heap - if (cachedBatchDataArray[seriesIndex].hasCurrent()) { - timeHeap.add(cachedBatchDataArray[seriesIndex].currentTime()); - } + prepareForNext(seriesIndex); } } @@ -465,6 +454,60 @@ public class RawQueryDataSetWithoutValueFilter extends QueryDataSet return tsQueryDataSet; } + /** if any column in the row record, we filter it. */ + private boolean filterRowRecord(int seriesNum, long minTime) + throws IOException, InterruptedException { + boolean hasNull = false; + for (int seriesIndex = 0; seriesIndex < seriesNum; seriesIndex++) { + if (cachedBatchDataArray[seriesIndex] == null + || !cachedBatchDataArray[seriesIndex].hasCurrent() + || cachedBatchDataArray[seriesIndex].currentTime() != minTime) { + hasNull = true; + } else { + if (TSDataType.VECTOR == cachedBatchDataArray[seriesIndex].getDataType()) { + for (TsPrimitiveType primitiveVal : cachedBatchDataArray[seriesIndex].getVector()) { + if (primitiveVal == null) { + hasNull = true; + break; + } + } + } + } + if (hasNull) { + break; + } + } + if (hasNull) { + for (int seriesIndex = 0; seriesIndex < seriesNum; seriesIndex++) { + if (cachedBatchDataArray[seriesIndex] != null + && cachedBatchDataArray[seriesIndex].hasCurrent() + && cachedBatchDataArray[seriesIndex].currentTime() == minTime) { + prepareForNext(seriesIndex); + } + } + return true; + } + return false; + } + + private void prepareForNext(int seriesIndex) throws IOException, InterruptedException { + // move next + cachedBatchDataArray[seriesIndex].next(); + + // check the interrupted status of query before taking next batch + QueryTimeManager.checkQueryAlive(queryId); + + // get next batch if current batch is empty and still have remaining batch data in queue + if (!cachedBatchDataArray[seriesIndex].hasCurrent() && !noMoreDataInQueueArray[seriesIndex]) { + fillCache(seriesIndex); + } + + // try to put the next timestamp into the heap + if (cachedBatchDataArray[seriesIndex].hasCurrent()) { + timeHeap.add(cachedBatchDataArray[seriesIndex].currentTime()); + } + } + protected void fillCache(int seriesIndex) throws IOException, InterruptedException { BatchData batchData = blockingQueueArray[seriesIndex].take(); // no more batch data in this time series queue @@ -565,7 +608,7 @@ public class RawQueryDataSetWithoutValueFilter extends QueryDataSet public Object[] nextRowInObjects() throws IOException { int seriesNumber = seriesReaderList.size(); - Long minTime = timeHeap.pollFirst(); + long minTime = timeHeap.pollFirst(); Object[] rowInObjects = new Object[seriesNumber + 1]; rowInObjects[seriesNumber] = minTime; diff --git a/server/src/main/java/org/apache/iotdb/db/utils/QueryDataSetUtils.java b/server/src/main/java/org/apache/iotdb/db/utils/QueryDataSetUtils.java index 4c32123..046f219 100644 --- a/server/src/main/java/org/apache/iotdb/db/utils/QueryDataSetUtils.java +++ b/server/src/main/java/org/apache/iotdb/db/utils/QueryDataSetUtils.java @@ -43,18 +43,6 @@ public class QueryDataSetUtils { private QueryDataSetUtils() {} - /** - * convert query data set by fetch size. - * - * @param queryDataSet -query dataset - * @param fetchSize -fetch size - * @return -convert query dataset - */ - public static TSQueryDataSet convertQueryDataSetByFetchSize( - QueryDataSet queryDataSet, int fetchSize) throws IOException { - return convertQueryDataSetByFetchSize(queryDataSet, fetchSize, null); - } - @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning public static TSQueryDataSet convertQueryDataSetByFetchSize( QueryDataSet queryDataSet, int fetchSize, WatermarkEncoder watermarkEncoder) @@ -79,6 +67,16 @@ public class QueryDataSetUtils { for (int i = 0; i < fetchSize; i++) { if (queryDataSet.hasNext()) { RowRecord rowRecord = queryDataSet.next(); + // filter the row that all columns are null + if (queryDataSet.isWithoutAllNull() && rowRecord.isAllNull()) { + i--; + continue; + } + // filter the row that any column is null + if (queryDataSet.isWithoutAnyNull() && rowRecord.hasNullField()) { + i--; + continue; + } if (watermarkEncoder != null) { rowRecord = watermarkEncoder.encodeRecord(rowRecord); } diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBWithoutAnyNullIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBWithoutAnyNullIT.java new file mode 100644 index 0000000..4f0aee4 --- /dev/null +++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBWithoutAnyNullIT.java @@ -0,0 +1,227 @@ +/* + * 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.integration; + +import static org.apache.iotdb.db.constant.TestConstant.TIMESTAMP_STR; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; +import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.utils.EnvironmentUtils; +import org.apache.iotdb.jdbc.Config; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class IoTDBWithoutAnyNullIT { + + private static final String[] dataSet = + new String[]{ + "SET STORAGE GROUP TO root.testWithoutAnyNull", + "CREATE TIMESERIES root.testWithoutAnyNull.d1.s1 WITH DATATYPE=INT32, ENCODING=PLAIN", + "CREATE TIMESERIES root.testWithoutAnyNull.d1.s2 WITH DATATYPE=BOOLEAN, ENCODING=PLAIN", + "CREATE TIMESERIES root.testWithoutAnyNull.d1.s3 WITH DATATYPE=DOUBLE, ENCODING=PLAIN", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(1, 21, false, 11.1)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2) " + + "values(2, 22, true)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(3, 23, false, 33.3)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s3) " + + "values(4, 24, 44.4)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s2,s3) " + + "values(5, true, 55.5)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1) " + + "values(6, 26)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s2) " + + "values(7, false)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s3) " + + "values(8, 88.8)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(9, 29, true, 99.9)", + "flush", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(10, 20, true, 10.0)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(11, 21, false, 11.1)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2) " + + "values(12, 22, true)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(13, 23, false, 33.3)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s3) " + + "values(14, 24, 44.4)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s2,s3) " + + "values(15, true, 55.5)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1) " + + "values(16, 26)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s2) " + + "values(17, false)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s3) " + + "values(18, 88.8)", + "INSERT INTO root.testWithoutAnyNull.d1(timestamp,s1,s2,s3) " + + "values(19, 29, true, 99.9)" + }; + + @BeforeClass + public static void setUp() throws Exception { + EnvironmentUtils.closeStatMonitor(); + EnvironmentUtils.envSetUp(); + IoTDBDescriptor.getInstance().getConfig().setPartitionInterval(1000); + Class.forName(Config.JDBC_DRIVER_NAME); + prepareData(); + } + + @AfterClass + public static void tearDown() throws Exception { + IoTDBDescriptor.getInstance().getConfig().setPartitionInterval(86400); + EnvironmentUtils.cleanEnv(); + } + + @Test + public void withoutAnyNullTest1() { + String[] retArray1 = + new String[]{ + "1,21,false,11.1", + "3,23,false,33.3", + "9,29,true,99.9", + "10,20,true,10.0", + "11,21,false,11.1", + "13,23,false,33.3", + "19,29,true,99.9" + }; + try (Connection connection = + DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + boolean hasResultSet = + statement.execute( + "select * from root.testWithoutAnyNull.d1 WITHOUT ANY NULL"); + + assertTrue(hasResultSet); + int cnt; + try (ResultSet resultSet = statement.getResultSet()) { + cnt = 0; + while (resultSet.next()) { + String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s1") + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s2") + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s3"); + assertEquals(retArray1[cnt], ans); + cnt++; + } + assertEquals(retArray1.length, cnt); + } + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void withoutAnyNullTest2() { + String[] retArray = + new String[]{ + "10,20,true,10.0", + "11,21,false,11.1", + "13,23,false,33.3", + "19,29,true,99.9" + }; + try (Connection connection = + DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + boolean hasResultSet = + statement.execute( + "select * from root.testWithoutAnyNull.d1 WHERE time >= 10 WITHOUT ANY NULL"); + + int cnt; + assertTrue(hasResultSet); + try (ResultSet resultSet = statement.getResultSet()) { + cnt = 0; + while (resultSet.next()) { + String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s1") + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s2") + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s3"); + assertEquals(retArray[cnt], ans); + cnt++; + } + assertEquals(retArray.length, cnt); + } + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void withoutAnyNullTest3() { + String[] retArray1 = + new String[]{ + "3,23,false,33.3", + "9,29,true,99.9", + "10,20,true,10.0", + "11,21,false,11.1", + "13,23,false,33.3" + }; + try (Connection connection = + DriverManager.getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + boolean hasResultSet = + statement.execute( + "select * from root.testWithoutAnyNull.d1 limit 5 offset 1 WITHOUT ANY NULL"); + + assertTrue(hasResultSet); + int cnt; + try (ResultSet resultSet = statement.getResultSet()) { + cnt = 0; + while (resultSet.next()) { + String ans = resultSet.getString(TIMESTAMP_STR) + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s1") + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s2") + "," + resultSet + .getString("root.testWithoutAnyNull.d1.s3"); + assertEquals(retArray1[cnt], ans); + cnt++; + } + assertEquals(retArray1.length, cnt); + } + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + private static void prepareData() { + try (Connection connection = + DriverManager.getConnection( + Config.IOTDB_URL_PREFIX + "127.0.0.1:6667/", "root", "root"); + Statement statement = connection.createStatement()) { + + for (String sql : dataSet) { + statement.execute(sql); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java index a413f56..4365732 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/common/RowRecord.java @@ -25,8 +25,13 @@ import java.util.List; public class RowRecord { - private long timestamp; - private List<Field> fields; + private final long timestamp; + private final List<Field> fields; + /** if any column is null, this field should be set to true; otherwise false */ + private boolean hasNullField = false; + + /** if any column is not null, this field should be set to false; otherwise true */ + private boolean allNull = true; public RowRecord(long timestamp) { this.timestamp = timestamp; @@ -36,14 +41,31 @@ public class RowRecord { public RowRecord(long timestamp, List<Field> fields) { this.timestamp = timestamp; this.fields = fields; + for (Field field : fields) { + if (field == null || field.getDataType() == null) { + hasNullField = true; + } else { + allNull = false; + } + } } public void addField(Field f) { this.fields.add(f); + if (f == null || f.getDataType() == null) { + hasNullField = true; + } else { + allNull = false; + } } public void addField(Object value, TSDataType dataType) { this.fields.add(Field.getField(value, dataType)); + if (value == null || dataType == null) { + hasNullField = true; + } else { + allNull = false; + } } @Override @@ -61,19 +83,15 @@ public class RowRecord { return timestamp; } - public void setTimestamp(long timestamp) { - this.timestamp = timestamp; - } - public List<Field> getFields() { return fields; } - public void setFields(List<Field> fields) { - this.fields = fields; + public boolean hasNullField() { + return hasNullField; } - public void setField(int index, Field field) { - this.fields.set(index, field); + public boolean isAllNull() { + return allNull; } } diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/query/dataset/QueryDataSet.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/query/dataset/QueryDataSet.java index 453403e..2d4be4d 100644 --- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/query/dataset/QueryDataSet.java +++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/query/dataset/QueryDataSet.java @@ -42,6 +42,12 @@ public abstract class QueryDataSet { */ protected EndPoint endPoint = null; + /** if any column is null, we don't need that row */ + protected boolean withoutAnyNull; + + /** Only if all columns are null, we don't need that row */ + protected boolean withoutAllNull; + /** For redirect query. Need keep consistent with EndPoint in rpc.thrift. */ public static class EndPoint { private String ip = null; @@ -167,4 +173,20 @@ public abstract class QueryDataSet { public void setEndPoint(EndPoint endPoint) { this.endPoint = endPoint; } + + public boolean isWithoutAnyNull() { + return withoutAnyNull; + } + + public void setWithoutAnyNull(boolean withoutAnyNull) { + this.withoutAnyNull = withoutAnyNull; + } + + public boolean isWithoutAllNull() { + return withoutAllNull; + } + + public void setWithoutAllNull(boolean withoutAllNull) { + this.withoutAllNull = withoutAllNull; + } }
