| /* |
| * 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.queryengine.plan.parser; |
| |
| import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType; |
| import org.apache.iotdb.common.rpc.thrift.TTimedQuota; |
| import org.apache.iotdb.common.rpc.thrift.ThrottleType; |
| import org.apache.iotdb.commons.auth.entity.PrivilegeType; |
| import org.apache.iotdb.commons.cluster.NodeStatus; |
| import org.apache.iotdb.commons.conf.IoTDBConstant; |
| import org.apache.iotdb.commons.cq.TimeoutPolicy; |
| import org.apache.iotdb.commons.path.PartialPath; |
| import org.apache.iotdb.commons.schema.filter.SchemaFilter; |
| import org.apache.iotdb.commons.schema.filter.SchemaFilterFactory; |
| import org.apache.iotdb.commons.utils.CommonDateTimeUtils; |
| import org.apache.iotdb.commons.utils.PathUtils; |
| import org.apache.iotdb.db.conf.IoTDBConfig; |
| import org.apache.iotdb.db.conf.IoTDBDescriptor; |
| import org.apache.iotdb.db.exception.sql.SemanticException; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ConnectorAttributeClauseContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ConstantContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.CountDatabasesContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.CountDevicesContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.CountNodesContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.CountTimeseriesContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.CreateFunctionContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.DropFunctionContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ExpressionContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ExtractorAttributeClauseContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.GroupByAttributeClauseContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.IdentifierContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ProcessorAttributeClauseContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ShowFunctionsContext; |
| import org.apache.iotdb.db.qp.sql.IoTDBSqlParserBaseVisitor; |
| import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; |
| import org.apache.iotdb.db.queryengine.execution.operator.window.WindowType; |
| import org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer; |
| import org.apache.iotdb.db.queryengine.plan.expression.Expression; |
| import org.apache.iotdb.db.queryengine.plan.expression.ExpressionType; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.AdditionExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.CompareBinaryExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.DivisionExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.EqualToExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.GreaterEqualExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.GreaterThanExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.LessEqualExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.LessThanExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.LogicAndExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.LogicOrExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.ModuloExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.MultiplicationExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.NonEqualExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.SubtractionExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.binary.WhenThenExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.leaf.ConstantOperand; |
| import org.apache.iotdb.db.queryengine.plan.expression.leaf.NullOperand; |
| import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimeSeriesOperand; |
| import org.apache.iotdb.db.queryengine.plan.expression.leaf.TimestampOperand; |
| import org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.multi.builtin.BuiltInScalarFunctionHelperFactory; |
| import org.apache.iotdb.db.queryengine.plan.expression.other.CaseWhenThenExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.ternary.BetweenExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.unary.InExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.unary.IsNullExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.unary.LikeExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.unary.LogicNotExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.unary.NegationExpression; |
| import org.apache.iotdb.db.queryengine.plan.expression.unary.RegularExpression; |
| import org.apache.iotdb.db.queryengine.plan.statement.AuthorType; |
| import org.apache.iotdb.db.queryengine.plan.statement.Statement; |
| import org.apache.iotdb.db.queryengine.plan.statement.StatementType; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.FillComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.FillPolicy; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.FromComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByConditionComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByCountComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByLevelComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupBySessionComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByTagComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByTimeComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.GroupByVariationComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.HavingCondition; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.IntoComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.IntoItem; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.NullOrdering; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.OrderByComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.OrderByKey; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.Ordering; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.ResultColumn; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.ResultSetFormat; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.SelectComponent; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.SortItem; |
| import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition; |
| import org.apache.iotdb.db.queryengine.plan.statement.crud.DeleteDataStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.literal.BooleanLiteral; |
| import org.apache.iotdb.db.queryengine.plan.statement.literal.DoubleLiteral; |
| import org.apache.iotdb.db.queryengine.plan.statement.literal.Literal; |
| import org.apache.iotdb.db.queryengine.plan.statement.literal.LongLiteral; |
| import org.apache.iotdb.db.queryengine.plan.statement.literal.StringLiteral; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDatabaseStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountNodesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountTimeSlotListStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateContinuousQueryStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateFunctionStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTriggerStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.DatabaseSchemaStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.DeleteDatabaseStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.DeleteTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.DropContinuousQueryStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.DropFunctionStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.DropTriggerStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.GetRegionIdStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.GetSeriesSlotListStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.GetTimeSlotListStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.MigrateRegionStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.SetTTLStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildNodesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowChildPathsStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterIdStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowClusterStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowConfigNodesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowContinuousQueriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowCurrentTimestampStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDataNodesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDatabaseStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowDevicesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowFunctionsStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowRegionStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTTLStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTimeSeriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowTriggersStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.ShowVariablesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.UnSetTTLStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.AlterPipeStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.CreatePipePluginStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.CreatePipeStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.DropPipePluginStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.DropPipeStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipePluginsStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.ShowPipesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StartPipeStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.pipe.StopPipeStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.CreateTopicStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.DropTopicStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowSubscriptionsStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.subscription.ShowTopicsStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ActivateTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.AlterSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.CreateSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.DeactivateTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.DropSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.SetSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowNodesInSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowPathSetTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowPathsUsingTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.ShowSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.template.UnsetSchemaTemplateStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.AlterLogicalViewStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.CreateLogicalViewStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.DeleteLogicalViewStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.metadata.view.ShowLogicalViewStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.ClearCacheStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainAnalyzeStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.ExplainStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.FlushStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.KillQueryStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.LoadConfigurationStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.SetSystemStatusStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowQueriesStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowVersionStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.StartRepairDataStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.StopRepairDataStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetSpaceQuotaStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetThrottleQuotaStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.ShowSpaceQuotaStatement; |
| import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.ShowThrottleQuotaStatement; |
| import org.apache.iotdb.db.schemaengine.template.TemplateAlterOperationType; |
| import org.apache.iotdb.db.utils.DateTimeUtils; |
| import org.apache.iotdb.db.utils.TimestampPrecisionUtils; |
| import org.apache.iotdb.db.utils.constant.SqlConstant; |
| import org.apache.iotdb.trigger.api.enums.TriggerEvent; |
| import org.apache.iotdb.trigger.api.enums.TriggerType; |
| import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor; |
| import org.apache.iotdb.tsfile.common.constant.TsFileConstant; |
| import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType; |
| import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; |
| import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding; |
| import org.apache.iotdb.tsfile.read.common.TimeRange; |
| import org.apache.iotdb.tsfile.utils.TimeDuration; |
| |
| import com.google.common.collect.ImmutableSet; |
| import org.antlr.v4.runtime.tree.TerminalNode; |
| |
| import java.io.FileNotFoundException; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.time.ZoneId; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.function.BiConsumer; |
| import java.util.function.Consumer; |
| import java.util.regex.Pattern; |
| import java.util.stream.Collectors; |
| |
| import static org.apache.iotdb.commons.schema.SchemaConstant.ALL_RESULT_NODES; |
| import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetToGroupByTime; |
| import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetToTimeParameter; |
| import static org.apache.iotdb.db.utils.TimestampPrecisionUtils.currPrecision; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.CAST_FUNCTION; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.CAST_TYPE; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.REPLACE_FROM; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.REPLACE_FUNCTION; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.REPLACE_TO; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.ROUND_FUNCTION; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.ROUND_PLACES; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.SUBSTRING_FUNCTION; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.SUBSTRING_IS_STANDARD; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.SUBSTRING_LENGTH; |
| import static org.apache.iotdb.db.utils.constant.SqlConstant.SUBSTRING_START; |
| |
| /** Parse AST to Statement. */ |
| public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> { |
| |
| private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig(); |
| |
| private static final String DELETE_RANGE_ERROR_MSG = |
| "For delete statement, where clause can only contain atomic expressions like : " |
| + "time > XXX, time <= XXX, or two atomic expressions connected by 'AND'"; |
| private static final String DELETE_ONLY_SUPPORT_TIME_EXP_ERROR_MSG = |
| "For delete statement, where clause can only contain time expressions, " |
| + "value filter is not currently supported."; |
| |
| private static final String GROUP_BY_COMMON_ONLY_ONE_MSG = |
| "Only one of group by time or group by variation/series/session can be supported at a time"; |
| |
| private static final String LIMIT_CONFIGURATION_ENABLED_ERROR_MSG = |
| "Limit configuration is not enabled, please enable it first."; |
| |
| private static final String NODE_NAME_IN_INTO_PATH_MATCHER = "([a-zA-Z0-9_${}\\u2E80-\\u9FFF]+)"; |
| private static final Pattern NODE_NAME_IN_INTO_PATH_PATTERN = |
| Pattern.compile(NODE_NAME_IN_INTO_PATH_MATCHER); |
| |
| private static final String IGNORENULL = "IgnoreNull"; |
| private ZoneId zoneId; |
| |
| private boolean useWildcard = false; |
| |
| private boolean lastLevelUseWildcard = false; |
| |
| public void setZoneId(ZoneId zoneId) { |
| this.zoneId = zoneId; |
| } |
| |
| /** Top Level Description. */ |
| @Override |
| public Statement visitSingleStatement(IoTDBSqlParser.SingleStatementContext ctx) { |
| Statement statement = visit(ctx.statement()); |
| if (ctx.DEBUG() != null) { |
| statement.setDebug(true); |
| } |
| return statement; |
| } |
| |
| /** Data Definition Language (DDL). */ |
| |
| // Create Timeseries ======================================================================== |
| @Override |
| public Statement visitCreateNonAlignedTimeseries( |
| IoTDBSqlParser.CreateNonAlignedTimeseriesContext ctx) { |
| CreateTimeSeriesStatement createTimeSeriesStatement = new CreateTimeSeriesStatement(); |
| createTimeSeriesStatement.setPath(parseFullPath(ctx.fullPath())); |
| if (ctx.attributeClauses() != null) { |
| parseAttributeClausesForCreateNonAlignedTimeSeries( |
| ctx.attributeClauses(), createTimeSeriesStatement); |
| } |
| return createTimeSeriesStatement; |
| } |
| |
| @Override |
| public Statement visitCreateAlignedTimeseries(IoTDBSqlParser.CreateAlignedTimeseriesContext ctx) { |
| CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement = |
| new CreateAlignedTimeSeriesStatement(); |
| createAlignedTimeSeriesStatement.setDevicePath(parseFullPath(ctx.fullPath())); |
| parseAlignedMeasurements(ctx.alignedMeasurements(), createAlignedTimeSeriesStatement); |
| return createAlignedTimeSeriesStatement; |
| } |
| |
| public void parseAlignedMeasurements( |
| IoTDBSqlParser.AlignedMeasurementsContext ctx, |
| CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement) { |
| for (int i = 0; i < ctx.nodeNameWithoutWildcard().size(); i++) { |
| createAlignedTimeSeriesStatement.addMeasurement( |
| parseNodeNameWithoutWildCard(ctx.nodeNameWithoutWildcard(i))); |
| parseAttributeClausesForCreateAlignedTimeSeries( |
| ctx.attributeClauses(i), createAlignedTimeSeriesStatement); |
| } |
| } |
| |
| public void parseAttributeClausesForCreateNonAlignedTimeSeries( |
| IoTDBSqlParser.AttributeClausesContext ctx, |
| CreateTimeSeriesStatement createTimeSeriesStatement) { |
| if (ctx.aliasNodeName() != null) { |
| createTimeSeriesStatement.setAlias(parseNodeName(ctx.aliasNodeName().nodeName())); |
| } |
| |
| Map<String, String> props = new HashMap<>(); |
| TSDataType dataType = parseDataTypeAttribute(ctx); |
| if (dataType != null) { |
| props.put( |
| IoTDBConstant.COLUMN_TIMESERIES_DATATYPE.toLowerCase(), |
| dataType.toString().toLowerCase()); |
| } |
| List<IoTDBSqlParser.AttributePairContext> attributePairs = ctx.attributePair(); |
| if (ctx.attributePair(0) != null) { |
| for (IoTDBSqlParser.AttributePairContext attributePair : attributePairs) { |
| props.put( |
| parseAttributeKey(attributePair.attributeKey()).toLowerCase(), |
| parseAttributeValue(attributePair.attributeValue()).toLowerCase()); |
| } |
| } |
| |
| createTimeSeriesStatement.setProps(props); |
| checkPropsInCreateTimeSeries(createTimeSeriesStatement); |
| |
| if (ctx.tagClause() != null) { |
| parseTagClause(ctx.tagClause(), createTimeSeriesStatement); |
| } |
| if (ctx.attributeClause() != null) { |
| parseAttributeClauseForTimeSeries(ctx.attributeClause(), createTimeSeriesStatement); |
| } |
| } |
| |
| /** |
| * Check and set datatype, encoding, compressor. |
| * |
| * @throws SemanticException if encoding or dataType meets error handling |
| */ |
| private void checkPropsInCreateTimeSeries(CreateTimeSeriesStatement createTimeSeriesStatement) { |
| Map<String, String> props = createTimeSeriesStatement.getProps(); |
| if (props != null |
| && props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE.toLowerCase())) { |
| String datatypeString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE.toLowerCase()).toUpperCase(); |
| try { |
| createTimeSeriesStatement.setDataType(TSDataType.valueOf(datatypeString)); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("Unsupported datatype: %s", datatypeString)); |
| } |
| } |
| if (createTimeSeriesStatement.getDataType() == null) { |
| throw new SemanticException("datatype must be declared"); |
| } |
| |
| final IoTDBDescriptor ioTDBDescriptor = IoTDBDescriptor.getInstance(); |
| createTimeSeriesStatement.setEncoding( |
| ioTDBDescriptor.getDefaultEncodingByType(createTimeSeriesStatement.getDataType())); |
| if (props != null |
| && props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase())) { |
| String encodingString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase()).toUpperCase(); |
| try { |
| createTimeSeriesStatement.setEncoding(TSEncoding.valueOf(encodingString)); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("Unsupported encoding: %s", encodingString)); |
| } |
| } |
| |
| createTimeSeriesStatement.setCompressor( |
| TSFileDescriptor.getInstance().getConfig().getCompressor()); |
| if (props != null |
| && props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase())) { |
| String compressionString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase()).toUpperCase(); |
| try { |
| createTimeSeriesStatement.setCompressor(CompressionType.valueOf(compressionString)); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException( |
| String.format("Unsupported compression: %s", compressionString)); |
| } |
| } else if (props != null |
| && props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase())) { |
| String compressorString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase()).toUpperCase(); |
| try { |
| createTimeSeriesStatement.setCompressor(CompressionType.valueOf(compressorString)); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("Unsupported compression: %s", compressorString)); |
| } |
| } |
| createTimeSeriesStatement.setProps(props); |
| } |
| |
| public void parseAttributeClausesForCreateAlignedTimeSeries( |
| IoTDBSqlParser.AttributeClausesContext ctx, |
| CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement) { |
| if (ctx.aliasNodeName() != null) { |
| createAlignedTimeSeriesStatement.addAliasList(parseNodeName(ctx.aliasNodeName().nodeName())); |
| } else { |
| createAlignedTimeSeriesStatement.addAliasList(null); |
| } |
| |
| TSDataType dataType = parseDataTypeAttribute(ctx); |
| createAlignedTimeSeriesStatement.addDataType(dataType); |
| |
| Map<String, String> props = new HashMap<>(); |
| if (ctx.attributePair() != null) { |
| for (int i = 0; i < ctx.attributePair().size(); i++) { |
| props.put( |
| parseAttributeKey(ctx.attributePair(i).attributeKey()).toLowerCase(), |
| parseAttributeValue(ctx.attributePair(i).attributeValue())); |
| } |
| } |
| |
| TSEncoding encoding = IoTDBDescriptor.getInstance().getDefaultEncodingByType(dataType); |
| if (props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase())) { |
| String encodingString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase()).toUpperCase(); |
| try { |
| encoding = TSEncoding.valueOf(encodingString); |
| createAlignedTimeSeriesStatement.addEncoding(encoding); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("unsupported encoding: %s", encodingString)); |
| } |
| } else { |
| createAlignedTimeSeriesStatement.addEncoding(encoding); |
| } |
| |
| CompressionType compressor = TSFileDescriptor.getInstance().getConfig().getCompressor(); |
| if (props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase())) { |
| String compressorString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase()).toUpperCase(); |
| try { |
| compressor = CompressionType.valueOf(compressorString); |
| createAlignedTimeSeriesStatement.addCompressor(compressor); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("unsupported compressor: %s", compressorString)); |
| } |
| } else if (props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase())) { |
| String compressionString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase()).toUpperCase(); |
| try { |
| compressor = CompressionType.valueOf(compressionString); |
| createAlignedTimeSeriesStatement.addCompressor(compressor); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException( |
| String.format("unsupported compression: %s", compressionString)); |
| } |
| } else { |
| createAlignedTimeSeriesStatement.addCompressor(compressor); |
| } |
| |
| if (props.size() > 0) { |
| throw new SemanticException("create aligned timeseries: property is not supported yet."); |
| } |
| |
| if (ctx.tagClause() != null) { |
| parseTagClause(ctx.tagClause(), createAlignedTimeSeriesStatement); |
| } else { |
| createAlignedTimeSeriesStatement.addTagsList(null); |
| } |
| |
| if (ctx.attributeClause() != null) { |
| parseAttributeClauseForTimeSeries(ctx.attributeClause(), createAlignedTimeSeriesStatement); |
| } else { |
| createAlignedTimeSeriesStatement.addAttributesList(null); |
| } |
| } |
| |
| // Tag & Property & Attribute |
| |
| public void parseTagClause(IoTDBSqlParser.TagClauseContext ctx, Statement statement) { |
| Map<String, String> tags = extractMap(ctx.attributePair(), ctx.attributePair(0)); |
| if (statement instanceof CreateTimeSeriesStatement) { |
| ((CreateTimeSeriesStatement) statement).setTags(tags); |
| } else if (statement instanceof CreateAlignedTimeSeriesStatement) { |
| ((CreateAlignedTimeSeriesStatement) statement).addTagsList(tags); |
| } else if (statement instanceof AlterTimeSeriesStatement) { |
| ((AlterTimeSeriesStatement) statement).setTagsMap(tags); |
| } |
| } |
| |
| public void parseAttributeClauseForTimeSeries( |
| IoTDBSqlParser.AttributeClauseContext ctx, Statement statement) { |
| Map<String, String> attributes = extractMap(ctx.attributePair(), ctx.attributePair(0)); |
| if (statement instanceof CreateTimeSeriesStatement) { |
| ((CreateTimeSeriesStatement) statement).setAttributes(attributes); |
| } else if (statement instanceof CreateAlignedTimeSeriesStatement) { |
| ((CreateAlignedTimeSeriesStatement) statement).addAttributesList(attributes); |
| } else if (statement instanceof AlterTimeSeriesStatement) { |
| ((AlterTimeSeriesStatement) statement).setAttributesMap(attributes); |
| } |
| } |
| |
| // Alter Timeseries ======================================================================== |
| |
| @Override |
| public Statement visitAlterTimeseries(IoTDBSqlParser.AlterTimeseriesContext ctx) { |
| AlterTimeSeriesStatement alterTimeSeriesStatement = new AlterTimeSeriesStatement(); |
| alterTimeSeriesStatement.setPath(parseFullPath(ctx.fullPath())); |
| parseAlterClause(ctx.alterClause(), alterTimeSeriesStatement); |
| return alterTimeSeriesStatement; |
| } |
| |
| private void parseAlterClause( |
| IoTDBSqlParser.AlterClauseContext ctx, AlterTimeSeriesStatement alterTimeSeriesStatement) { |
| Map<String, String> alterMap = new HashMap<>(); |
| // Rename |
| if (ctx.RENAME() != null) { |
| alterTimeSeriesStatement.setAlterType(AlterTimeSeriesStatement.AlterType.RENAME); |
| alterMap.put(parseAttributeKey(ctx.beforeName), parseAttributeKey(ctx.currentName)); |
| } else if (ctx.SET() != null) { |
| // Set |
| alterTimeSeriesStatement.setAlterType(AlterTimeSeriesStatement.AlterType.SET); |
| setMap(ctx, alterMap); |
| } else if (ctx.DROP() != null) { |
| // Drop |
| alterTimeSeriesStatement.setAlterType(AlterTimeSeriesStatement.AlterType.DROP); |
| for (int i = 0; i < ctx.attributeKey().size(); i++) { |
| alterMap.put(parseAttributeKey(ctx.attributeKey().get(i)), null); |
| } |
| } else if (ctx.TAGS() != null) { |
| // Add tag |
| alterTimeSeriesStatement.setAlterType((AlterTimeSeriesStatement.AlterType.ADD_TAGS)); |
| setMap(ctx, alterMap); |
| } else if (ctx.ATTRIBUTES() != null) { |
| // Add attribute |
| alterTimeSeriesStatement.setAlterType(AlterTimeSeriesStatement.AlterType.ADD_ATTRIBUTES); |
| setMap(ctx, alterMap); |
| } else { |
| // Upsert |
| alterTimeSeriesStatement.setAlterType(AlterTimeSeriesStatement.AlterType.UPSERT); |
| if (ctx.aliasClause() != null) { |
| parseAliasClause(ctx.aliasClause(), alterTimeSeriesStatement); |
| } |
| if (ctx.tagClause() != null) { |
| parseTagClause(ctx.tagClause(), alterTimeSeriesStatement); |
| } |
| if (ctx.attributeClause() != null) { |
| parseAttributeClauseForTimeSeries(ctx.attributeClause(), alterTimeSeriesStatement); |
| } |
| } |
| alterTimeSeriesStatement.setAlterMap(alterMap); |
| } |
| |
| public void parseAliasClause( |
| IoTDBSqlParser.AliasClauseContext ctx, AlterTimeSeriesStatement alterTimeSeriesStatement) { |
| if (alterTimeSeriesStatement != null && ctx.ALIAS() != null) { |
| alterTimeSeriesStatement.setAlias(parseAliasNode(ctx.alias())); |
| } |
| } |
| |
| // Drop Timeseries ====================================================================== |
| |
| @Override |
| public Statement visitDropTimeseries(IoTDBSqlParser.DropTimeseriesContext ctx) { |
| DeleteTimeSeriesStatement deleteTimeSeriesStatement = new DeleteTimeSeriesStatement(); |
| List<PartialPath> partialPaths = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| partialPaths.add(parsePrefixPath(prefixPathContext)); |
| } |
| deleteTimeSeriesStatement.setPathPatternList(partialPaths); |
| return deleteTimeSeriesStatement; |
| } |
| |
| // Show Timeseries ======================================================================== |
| |
| @Override |
| public Statement visitShowTimeseries(IoTDBSqlParser.ShowTimeseriesContext ctx) { |
| boolean orderByHeat = ctx.LATEST() != null; |
| ShowTimeSeriesStatement showTimeSeriesStatement; |
| if (ctx.prefixPath() != null) { |
| showTimeSeriesStatement = |
| new ShowTimeSeriesStatement(parsePrefixPath(ctx.prefixPath()), orderByHeat); |
| } else { |
| showTimeSeriesStatement = |
| new ShowTimeSeriesStatement( |
| new PartialPath(SqlConstant.getSingleRootArray()), orderByHeat); |
| } |
| if (ctx.timeseriesWhereClause() != null) { |
| SchemaFilter schemaFilter = parseTimeseriesWhereClause(ctx.timeseriesWhereClause()); |
| showTimeSeriesStatement.setSchemaFilter(schemaFilter); |
| } |
| if (ctx.rowPaginationClause() != null) { |
| if (ctx.rowPaginationClause().limitClause() != null) { |
| showTimeSeriesStatement.setLimit(parseLimitClause(ctx.rowPaginationClause().limitClause())); |
| } |
| if (ctx.rowPaginationClause().offsetClause() != null) { |
| showTimeSeriesStatement.setOffset( |
| parseOffsetClause(ctx.rowPaginationClause().offsetClause())); |
| } |
| } |
| return showTimeSeriesStatement; |
| } |
| |
| private SchemaFilter parseTimeseriesWhereClause(IoTDBSqlParser.TimeseriesWhereClauseContext ctx) { |
| if (ctx.timeseriesContainsExpression() != null) { |
| // path contains filter |
| return SchemaFilterFactory.createPathContainsFilter( |
| parseStringLiteral(ctx.timeseriesContainsExpression().value.getText())); |
| } else if (ctx.columnEqualsExpression() != null) { |
| return parseColumnEqualsExpressionContext(ctx.columnEqualsExpression()); |
| } else { |
| // tag filter |
| if (ctx.tagContainsExpression() != null) { |
| return SchemaFilterFactory.createTagFilter( |
| parseAttributeKey(ctx.tagContainsExpression().attributeKey()), |
| parseStringLiteral(ctx.tagContainsExpression().value.getText()), |
| true); |
| } else { |
| return SchemaFilterFactory.createTagFilter( |
| parseAttributeKey(ctx.tagEqualsExpression().attributeKey()), |
| parseAttributeValue(ctx.tagEqualsExpression().attributeValue()), |
| false); |
| } |
| } |
| } |
| |
| private SchemaFilter parseColumnEqualsExpressionContext( |
| IoTDBSqlParser.ColumnEqualsExpressionContext ctx) { |
| String column = parseAttributeKey(ctx.attributeKey()); |
| String value = parseAttributeValue(ctx.attributeValue()); |
| if (column.equalsIgnoreCase(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE)) { |
| try { |
| TSDataType dataType = TSDataType.valueOf(value.toUpperCase()); |
| return SchemaFilterFactory.createDataTypeFilter(dataType); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("unsupported datatype: %s", value)); |
| } |
| } else { |
| throw new SemanticException("unexpected filter key"); |
| } |
| } |
| |
| // SHOW DATABASES |
| |
| @Override |
| public Statement visitShowDatabases(IoTDBSqlParser.ShowDatabasesContext ctx) { |
| ShowDatabaseStatement showDatabaseStatement; |
| |
| // Parse prefixPath |
| if (ctx.prefixPath() != null) { |
| showDatabaseStatement = new ShowDatabaseStatement(parsePrefixPath(ctx.prefixPath())); |
| } else { |
| showDatabaseStatement = |
| new ShowDatabaseStatement(new PartialPath(SqlConstant.getSingleRootArray())); |
| } |
| |
| // Is detailed |
| showDatabaseStatement.setDetailed(ctx.DETAILS() != null); |
| |
| return showDatabaseStatement; |
| } |
| |
| // Show Devices ======================================================================== |
| |
| @Override |
| public Statement visitShowDevices(IoTDBSqlParser.ShowDevicesContext ctx) { |
| ShowDevicesStatement showDevicesStatement; |
| if (ctx.prefixPath() != null) { |
| showDevicesStatement = new ShowDevicesStatement(parsePrefixPath(ctx.prefixPath())); |
| } else { |
| showDevicesStatement = |
| new ShowDevicesStatement(new PartialPath(SqlConstant.getSingleRootArray())); |
| } |
| if (ctx.devicesWhereClause() != null) { |
| showDevicesStatement.setSchemaFilter(parseDevicesWhereClause(ctx.devicesWhereClause())); |
| } |
| |
| if (ctx.rowPaginationClause() != null) { |
| if (ctx.rowPaginationClause().limitClause() != null) { |
| showDevicesStatement.setLimit(parseLimitClause(ctx.rowPaginationClause().limitClause())); |
| } |
| if (ctx.rowPaginationClause().offsetClause() != null) { |
| showDevicesStatement.setOffset(parseOffsetClause(ctx.rowPaginationClause().offsetClause())); |
| } |
| } |
| // show devices with database |
| if (ctx.WITH() != null) { |
| showDevicesStatement.setSgCol(true); |
| } |
| return showDevicesStatement; |
| } |
| |
| private SchemaFilter parseDevicesWhereClause(IoTDBSqlParser.DevicesWhereClauseContext ctx) { |
| // path contains filter |
| if (ctx.deviceContainsExpression() != null) { |
| return SchemaFilterFactory.createPathContainsFilter( |
| parseStringLiteral(ctx.deviceContainsExpression().value.getText())); |
| } else { |
| String templateName = null; |
| boolean isEqual = true; |
| if (ctx.templateEqualExpression().operator_is() != null) { |
| if (ctx.templateEqualExpression().operator_not() != null) { |
| isEqual = false; |
| } |
| } else { |
| templateName = parseStringLiteral(ctx.templateEqualExpression().templateName.getText()); |
| if (ctx.templateEqualExpression().OPERATOR_NEQ() != null) { |
| isEqual = false; |
| } |
| } |
| return SchemaFilterFactory.createTemplateNameFilter(templateName, isEqual); |
| } |
| } |
| |
| // Count Devices ======================================================================== |
| |
| @Override |
| public Statement visitCountDevices(CountDevicesContext ctx) { |
| PartialPath path; |
| if (ctx.prefixPath() != null) { |
| path = parsePrefixPath(ctx.prefixPath()); |
| } else { |
| path = new PartialPath(SqlConstant.getSingleRootArray()); |
| } |
| return new CountDevicesStatement(path); |
| } |
| |
| // Count TimeSeries ======================================================================== |
| @Override |
| public Statement visitCountTimeseries(CountTimeseriesContext ctx) { |
| Statement statement; |
| PartialPath path; |
| if (ctx.prefixPath() != null) { |
| path = parsePrefixPath(ctx.prefixPath()); |
| } else { |
| path = new PartialPath(SqlConstant.getSingleRootArray()); |
| } |
| if (ctx.INTEGER_LITERAL() != null) { |
| int level = Integer.parseInt(ctx.INTEGER_LITERAL().getText()); |
| statement = new CountLevelTimeSeriesStatement(path, level); |
| } else { |
| statement = new CountTimeSeriesStatement(path); |
| } |
| if (ctx.timeseriesWhereClause() != null) { |
| SchemaFilter schemaFilter = parseTimeseriesWhereClause(ctx.timeseriesWhereClause()); |
| if (statement instanceof CountTimeSeriesStatement) { |
| ((CountTimeSeriesStatement) statement).setSchemaFilter(schemaFilter); |
| } else if (statement instanceof CountLevelTimeSeriesStatement) { |
| ((CountLevelTimeSeriesStatement) statement).setSchemaFilter(schemaFilter); |
| } |
| } |
| return statement; |
| } |
| |
| // Count Nodes ======================================================================== |
| @Override |
| public Statement visitCountNodes(CountNodesContext ctx) { |
| PartialPath path; |
| if (ctx.prefixPath() != null) { |
| path = parsePrefixPath(ctx.prefixPath()); |
| } else { |
| path = new PartialPath(SqlConstant.getSingleRootArray()); |
| } |
| int level = Integer.parseInt(ctx.INTEGER_LITERAL().getText()); |
| return new CountNodesStatement(path, level); |
| } |
| |
| // Count StorageGroup ======================================================================== |
| @Override |
| public Statement visitCountDatabases(CountDatabasesContext ctx) { |
| PartialPath path; |
| if (ctx.prefixPath() != null) { |
| path = parsePrefixPath(ctx.prefixPath()); |
| } else { |
| path = new PartialPath(SqlConstant.getSingleRootArray()); |
| } |
| return new CountDatabaseStatement(path); |
| } |
| |
| // Show version |
| @Override |
| public Statement visitShowVersion(IoTDBSqlParser.ShowVersionContext ctx) { |
| return new ShowVersionStatement(); |
| } |
| |
| // Create Function |
| @Override |
| public Statement visitCreateFunction(CreateFunctionContext ctx) { |
| if (ctx.uriClause() == null) { |
| return new CreateFunctionStatement( |
| parseIdentifier(ctx.udfName.getText()), |
| parseStringLiteral(ctx.className.getText()), |
| false); |
| } else { |
| String uriString = parseAndValidateURI(ctx.uriClause()); |
| return new CreateFunctionStatement( |
| parseIdentifier(ctx.udfName.getText()), |
| parseStringLiteral(ctx.className.getText()), |
| true, |
| uriString); |
| } |
| } |
| |
| private String parseAndValidateURI(IoTDBSqlParser.UriClauseContext ctx) { |
| String uriString = parseStringLiteral(ctx.uri().getText()); |
| try { |
| new URI(uriString); |
| } catch (URISyntaxException e) { |
| throw new SemanticException(String.format("Invalid URI: %s", uriString)); |
| } |
| return uriString; |
| } |
| |
| // Drop Function |
| @Override |
| public Statement visitDropFunction(DropFunctionContext ctx) { |
| return new DropFunctionStatement(parseIdentifier(ctx.udfName.getText())); |
| } |
| |
| // Show Functions |
| @Override |
| public Statement visitShowFunctions(ShowFunctionsContext ctx) { |
| return new ShowFunctionsStatement(); |
| } |
| |
| // Create Trigger ===================================================================== |
| @Override |
| public Statement visitCreateTrigger(IoTDBSqlParser.CreateTriggerContext ctx) { |
| if (ctx.triggerEventClause().DELETE() != null) { |
| throw new SemanticException("Trigger does not support DELETE as TRIGGER_EVENT for now."); |
| } |
| if (ctx.triggerType() == null) { |
| throw new SemanticException("Please specify trigger type: STATELESS or STATEFUL."); |
| } |
| Map<String, String> attributes = new HashMap<>(); |
| if (ctx.triggerAttributeClause() != null) { |
| for (IoTDBSqlParser.TriggerAttributeContext triggerAttributeContext : |
| ctx.triggerAttributeClause().triggerAttribute()) { |
| attributes.put( |
| parseAttributeKey(triggerAttributeContext.key), |
| parseAttributeValue(triggerAttributeContext.value)); |
| } |
| } |
| if (ctx.uriClause() == null) { |
| return new CreateTriggerStatement( |
| parseIdentifier(ctx.triggerName.getText()), |
| parseStringLiteral(ctx.className.getText()), |
| "", |
| false, |
| ctx.triggerEventClause().BEFORE() != null |
| ? TriggerEvent.BEFORE_INSERT |
| : TriggerEvent.AFTER_INSERT, |
| ctx.triggerType().STATELESS() != null ? TriggerType.STATELESS : TriggerType.STATEFUL, |
| parsePrefixPath(ctx.prefixPath()), |
| attributes); |
| } else { |
| String uriString = parseAndValidateURI(ctx.uriClause()); |
| return new CreateTriggerStatement( |
| parseIdentifier(ctx.triggerName.getText()), |
| parseStringLiteral(ctx.className.getText()), |
| uriString, |
| true, |
| ctx.triggerEventClause().BEFORE() != null |
| ? TriggerEvent.BEFORE_INSERT |
| : TriggerEvent.AFTER_INSERT, |
| ctx.triggerType().STATELESS() != null ? TriggerType.STATELESS : TriggerType.STATEFUL, |
| parsePrefixPath(ctx.prefixPath()), |
| attributes); |
| } |
| } |
| |
| // Drop Trigger ===================================================================== |
| @Override |
| public Statement visitDropTrigger(IoTDBSqlParser.DropTriggerContext ctx) { |
| return new DropTriggerStatement(parseIdentifier(ctx.triggerName.getText())); |
| } |
| |
| // Show Trigger ===================================================================== |
| @Override |
| public Statement visitShowTriggers(IoTDBSqlParser.ShowTriggersContext ctx) { |
| return new ShowTriggersStatement(); |
| } |
| |
| // Create PipePlugin ===================================================================== |
| @Override |
| public Statement visitCreatePipePlugin(IoTDBSqlParser.CreatePipePluginContext ctx) { |
| return new CreatePipePluginStatement( |
| parseIdentifier(ctx.pluginName.getText()), |
| parseStringLiteral(ctx.className.getText()), |
| parseAndValidateURI(ctx.uriClause())); |
| } |
| |
| // Drop PipePlugin ===================================================================== |
| @Override |
| public Statement visitDropPipePlugin(IoTDBSqlParser.DropPipePluginContext ctx) { |
| return new DropPipePluginStatement(parseIdentifier(ctx.pluginName.getText())); |
| } |
| |
| // Show PipePlugins ===================================================================== |
| @Override |
| public Statement visitShowPipePlugins(IoTDBSqlParser.ShowPipePluginsContext ctx) { |
| return new ShowPipePluginsStatement(); |
| } |
| |
| // Show Child Paths ===================================================================== |
| @Override |
| public Statement visitShowChildPaths(IoTDBSqlParser.ShowChildPathsContext ctx) { |
| if (ctx.prefixPath() != null) { |
| return new ShowChildPathsStatement(parsePrefixPath(ctx.prefixPath())); |
| } else { |
| return new ShowChildPathsStatement(new PartialPath(SqlConstant.getSingleRootArray())); |
| } |
| } |
| |
| // Show Child Nodes ===================================================================== |
| @Override |
| public Statement visitShowChildNodes(IoTDBSqlParser.ShowChildNodesContext ctx) { |
| if (ctx.prefixPath() != null) { |
| return new ShowChildNodesStatement(parsePrefixPath(ctx.prefixPath())); |
| } else { |
| return new ShowChildNodesStatement(new PartialPath(SqlConstant.getSingleRootArray())); |
| } |
| } |
| |
| // Create CQ ===================================================================== |
| @Override |
| public Statement visitCreateContinuousQuery(IoTDBSqlParser.CreateContinuousQueryContext ctx) { |
| CreateContinuousQueryStatement statement = new CreateContinuousQueryStatement(); |
| |
| statement.setCqId(parseIdentifier(ctx.cqId.getText())); |
| |
| QueryStatement queryBodyStatement = |
| (QueryStatement) visitSelectStatement(ctx.selectStatement()); |
| queryBodyStatement.setCqQueryBody(true); |
| statement.setQueryBodyStatement(queryBodyStatement); |
| |
| if (ctx.resampleClause() != null) { |
| parseResampleClause(ctx.resampleClause(), statement); |
| } else { |
| QueryStatement queryStatement = statement.getQueryBodyStatement(); |
| if (!queryStatement.isGroupByTime()) { |
| throw new SemanticException( |
| "CQ: At least one of the parameters `every_interval` and `group_by_interval` needs to be specified."); |
| } |
| |
| long interval = |
| queryStatement.getGroupByTimeComponent().getInterval().getTotalDuration(currPrecision); |
| statement.setEveryInterval(interval); |
| statement.setStartTimeOffset(interval); |
| } |
| |
| if (ctx.timeoutPolicyClause() != null) { |
| parseTimeoutPolicyClause(ctx.timeoutPolicyClause(), statement); |
| } |
| |
| return statement; |
| } |
| |
| private void parseResampleClause( |
| IoTDBSqlParser.ResampleClauseContext ctx, CreateContinuousQueryStatement statement) { |
| if (ctx.EVERY() != null) { |
| statement.setEveryInterval( |
| DateTimeUtils.convertDurationStrToLong(ctx.everyInterval.getText())); |
| } else { |
| QueryStatement queryStatement = statement.getQueryBodyStatement(); |
| if (!queryStatement.isGroupByTime()) { |
| throw new SemanticException( |
| "CQ: At least one of the parameters `every_interval` and `group_by_interval` needs to be specified."); |
| } |
| statement.setEveryInterval( |
| queryStatement.getGroupByTimeComponent().getInterval().getTotalDuration(currPrecision)); |
| } |
| |
| if (ctx.BOUNDARY() != null) { |
| statement.setBoundaryTime( |
| parseTimeValue(ctx.boundaryTime, CommonDateTimeUtils.currentTime())); |
| } |
| |
| if (ctx.RANGE() != null) { |
| statement.setStartTimeOffset( |
| DateTimeUtils.convertDurationStrToLong(ctx.startTimeOffset.getText())); |
| if (ctx.endTimeOffset != null) { |
| statement.setEndTimeOffset( |
| DateTimeUtils.convertDurationStrToLong(ctx.endTimeOffset.getText())); |
| } |
| } else { |
| statement.setStartTimeOffset(statement.getEveryInterval()); |
| } |
| } |
| |
| private void parseTimeoutPolicyClause( |
| IoTDBSqlParser.TimeoutPolicyClauseContext ctx, CreateContinuousQueryStatement statement) { |
| if (ctx.DISCARD() != null) { |
| statement.setTimeoutPolicy(TimeoutPolicy.DISCARD); |
| } |
| } |
| |
| // Drop CQ ===================================================================== |
| @Override |
| public Statement visitDropContinuousQuery(IoTDBSqlParser.DropContinuousQueryContext ctx) { |
| return new DropContinuousQueryStatement(parseIdentifier(ctx.cqId.getText())); |
| } |
| |
| // Show CQs ===================================================================== |
| @Override |
| public Statement visitShowContinuousQueries(IoTDBSqlParser.ShowContinuousQueriesContext ctx) { |
| return new ShowContinuousQueriesStatement(); |
| } |
| |
| // Create Logical View |
| @Override |
| public Statement visitCreateLogicalView(IoTDBSqlParser.CreateLogicalViewContext ctx) { |
| CreateLogicalViewStatement createLogicalViewStatement = new CreateLogicalViewStatement(); |
| // parse target |
| parseViewTargetPaths( |
| ctx.viewTargetPaths(), |
| createLogicalViewStatement::setTargetFullPaths, |
| createLogicalViewStatement::setTargetPathsGroup, |
| createLogicalViewStatement::setTargetIntoItem); |
| // parse source |
| parseViewSourcePaths( |
| ctx.viewSourcePaths(), |
| createLogicalViewStatement::setSourceFullPaths, |
| createLogicalViewStatement::setSourcePathsGroup, |
| createLogicalViewStatement::setSourceQueryStatement); |
| |
| return createLogicalViewStatement; |
| } |
| |
| @Override |
| public Statement visitDropLogicalView(IoTDBSqlParser.DropLogicalViewContext ctx) { |
| DeleteLogicalViewStatement deleteLogicalViewStatement = new DeleteLogicalViewStatement(); |
| List<PartialPath> partialPaths = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| partialPaths.add(parsePrefixPath(prefixPathContext)); |
| } |
| deleteLogicalViewStatement.setPathPatternList(partialPaths); |
| return deleteLogicalViewStatement; |
| } |
| |
| @Override |
| public Statement visitShowLogicalView(IoTDBSqlParser.ShowLogicalViewContext ctx) { |
| ShowLogicalViewStatement showLogicalViewStatement; |
| if (ctx.prefixPath() != null) { |
| showLogicalViewStatement = new ShowLogicalViewStatement(parsePrefixPath(ctx.prefixPath())); |
| } else { |
| showLogicalViewStatement = |
| new ShowLogicalViewStatement(new PartialPath(SqlConstant.getSingleRootArray())); |
| } |
| if (ctx.timeseriesWhereClause() != null) { |
| SchemaFilter schemaFilter = parseTimeseriesWhereClause(ctx.timeseriesWhereClause()); |
| showLogicalViewStatement.setSchemaFilter(schemaFilter); |
| } |
| if (ctx.rowPaginationClause() != null) { |
| if (ctx.rowPaginationClause().limitClause() != null) { |
| showLogicalViewStatement.setLimit( |
| parseLimitClause(ctx.rowPaginationClause().limitClause())); |
| } |
| if (ctx.rowPaginationClause().offsetClause() != null) { |
| showLogicalViewStatement.setOffset( |
| parseOffsetClause(ctx.rowPaginationClause().offsetClause())); |
| } |
| } |
| return showLogicalViewStatement; |
| } |
| |
| @Override |
| public Statement visitRenameLogicalView(IoTDBSqlParser.RenameLogicalViewContext ctx) { |
| throw new SemanticException("Renaming view is not supported."); |
| } |
| |
| @Override |
| public Statement visitAlterLogicalView(IoTDBSqlParser.AlterLogicalViewContext ctx) { |
| if (ctx.alterClause() == null) { |
| final AlterLogicalViewStatement alterLogicalViewStatement = new AlterLogicalViewStatement(); |
| // parse target |
| parseViewTargetPaths( |
| ctx.viewTargetPaths(), |
| alterLogicalViewStatement::setTargetFullPaths, |
| alterLogicalViewStatement::setTargetPathsGroup, |
| intoItem -> { |
| if (intoItem != null) { |
| throw new SemanticException( |
| "Can not use char '$' or into item in alter view statement."); |
| } |
| }); |
| // parse source |
| parseViewSourcePaths( |
| ctx.viewSourcePaths(), |
| alterLogicalViewStatement::setSourceFullPaths, |
| alterLogicalViewStatement::setSourcePathsGroup, |
| alterLogicalViewStatement::setSourceQueryStatement); |
| |
| return alterLogicalViewStatement; |
| } else { |
| final AlterTimeSeriesStatement alterTimeSeriesStatement = new AlterTimeSeriesStatement(true); |
| alterTimeSeriesStatement.setPath(parseFullPath(ctx.fullPath())); |
| parseAlterClause(ctx.alterClause(), alterTimeSeriesStatement); |
| if (alterTimeSeriesStatement.getAlias() != null) { |
| throw new SemanticException("View doesn't support alias."); |
| } |
| return alterTimeSeriesStatement; |
| } |
| } |
| |
| // Parse suffix paths in logical view with into item |
| private PartialPath parseViewPrefixPathWithInto(IoTDBSqlParser.PrefixPathContext ctx) { |
| final List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName(); |
| final String[] path = new String[nodeNames.size() + 1]; |
| path[0] = ctx.ROOT().getText(); |
| for (int i = 0; i < nodeNames.size(); i++) { |
| path[i + 1] = parseNodeStringInIntoPath(nodeNames.get(i).getText()); |
| } |
| return new PartialPath(path); |
| } |
| |
| private PartialPath parseViewSuffixPatWithInto(IoTDBSqlParser.ViewSuffixPathsContext ctx) { |
| final List<IoTDBSqlParser.NodeNameWithoutWildcardContext> nodeNamesWithoutStar = |
| ctx.nodeNameWithoutWildcard(); |
| final String[] nodeList = new String[nodeNamesWithoutStar.size()]; |
| for (int i = 0; i < nodeNamesWithoutStar.size(); i++) { |
| nodeList[i] = parseNodeStringInIntoPath(nodeNamesWithoutStar.get(i).getText()); |
| } |
| return new PartialPath(nodeList); |
| } |
| |
| private PartialPath parseViewSuffixPath(IoTDBSqlParser.ViewSuffixPathsContext ctx) { |
| final List<IoTDBSqlParser.NodeNameWithoutWildcardContext> nodeNamesWithoutStar = |
| ctx.nodeNameWithoutWildcard(); |
| final String[] nodeList = new String[nodeNamesWithoutStar.size()]; |
| for (int i = 0; i < nodeNamesWithoutStar.size(); i++) { |
| nodeList[i] = parseNodeNameWithoutWildCard(nodeNamesWithoutStar.get(i)); |
| } |
| return new PartialPath(nodeList); |
| } |
| |
| // parse target paths in CreateLogicalView statement |
| private void parseViewTargetPaths( |
| IoTDBSqlParser.ViewTargetPathsContext ctx, |
| Consumer<List<PartialPath>> setTargetFullPaths, |
| BiConsumer<PartialPath, List<PartialPath>> setTargetPathsGroup, |
| Consumer<IntoItem> setTargetIntoItem) { |
| // Full paths |
| if (ctx.fullPath() != null && !ctx.fullPath().isEmpty()) { |
| final List<IoTDBSqlParser.FullPathContext> fullPathContextList = ctx.fullPath(); |
| final List<PartialPath> pathList = new ArrayList<>(); |
| for (IoTDBSqlParser.FullPathContext pathContext : fullPathContextList) { |
| pathList.add(parseFullPath(pathContext)); |
| } |
| setTargetFullPaths.accept(pathList); |
| } |
| // Prefix path and suffix paths |
| if (ctx.prefixPath() != null |
| && ctx.viewSuffixPaths() != null |
| && !ctx.viewSuffixPaths().isEmpty()) { |
| final IoTDBSqlParser.PrefixPathContext prefixPathContext = ctx.prefixPath(); |
| final List<IoTDBSqlParser.ViewSuffixPathsContext> suffixPathContextList = |
| ctx.viewSuffixPaths(); |
| final List<PartialPath> suffixPathList = new ArrayList<>(); |
| PartialPath prefixPath = null; |
| boolean isMultipleCreating = false; |
| try { |
| prefixPath = parsePrefixPath(prefixPathContext); |
| for (IoTDBSqlParser.ViewSuffixPathsContext suffixPathContext : suffixPathContextList) { |
| suffixPathList.add(parseViewSuffixPath(suffixPathContext)); |
| } |
| } catch (SemanticException e) { |
| // There is '$', '{', '}' in this statement |
| isMultipleCreating = true; |
| suffixPathList.clear(); |
| } |
| if (!isMultipleCreating) { |
| setTargetPathsGroup.accept(prefixPath, suffixPathList); |
| } else { |
| prefixPath = parseViewPrefixPathWithInto(prefixPathContext); |
| for (final IoTDBSqlParser.ViewSuffixPathsContext suffixPathContext : |
| suffixPathContextList) { |
| suffixPathList.add(parseViewSuffixPatWithInto(suffixPathContext)); |
| } |
| final List<String> intoMeasurementList = new ArrayList<>(); |
| for (PartialPath path : suffixPathList) { |
| intoMeasurementList.add(path.toString()); |
| } |
| final IntoItem intoItem = new IntoItem(prefixPath, intoMeasurementList, false); |
| setTargetIntoItem.accept(intoItem); |
| } |
| } |
| } |
| |
| // Parse source paths in CreateLogicalView statement |
| private void parseViewSourcePaths( |
| IoTDBSqlParser.ViewSourcePathsContext ctx, |
| Consumer<List<PartialPath>> setSourceFullPaths, |
| BiConsumer<PartialPath, List<PartialPath>> setSourcePathsGroup, |
| Consumer<QueryStatement> setSourceQueryStatement) { |
| // Full paths |
| if (ctx.fullPath() != null && !ctx.fullPath().isEmpty()) { |
| List<IoTDBSqlParser.FullPathContext> fullPathContextList = ctx.fullPath(); |
| List<PartialPath> pathList = new ArrayList<>(); |
| for (IoTDBSqlParser.FullPathContext pathContext : fullPathContextList) { |
| pathList.add(parseFullPath(pathContext)); |
| } |
| setSourceFullPaths.accept(pathList); |
| } |
| // prefix path and suffix paths |
| if (ctx.prefixPath() != null |
| && ctx.viewSuffixPaths() != null |
| && !ctx.viewSuffixPaths().isEmpty()) { |
| final IoTDBSqlParser.PrefixPathContext prefixPathContext = ctx.prefixPath(); |
| final PartialPath prefixPath = parsePrefixPath(prefixPathContext); |
| final List<IoTDBSqlParser.ViewSuffixPathsContext> suffixPathContextList = |
| ctx.viewSuffixPaths(); |
| final List<PartialPath> suffixPathList = new ArrayList<>(); |
| for (final IoTDBSqlParser.ViewSuffixPathsContext suffixPathContext : suffixPathContextList) { |
| suffixPathList.add(parseViewSuffixPath(suffixPathContext)); |
| } |
| setSourcePathsGroup.accept(prefixPath, suffixPathList); |
| } |
| if (ctx.selectClause() != null && ctx.fromClause() != null) { |
| final QueryStatement queryStatement = new QueryStatement(); |
| queryStatement.setSelectComponent(parseSelectClause(ctx.selectClause(), queryStatement)); |
| queryStatement.setFromComponent(parseFromClause(ctx.fromClause())); |
| setSourceQueryStatement.accept(queryStatement); |
| } |
| } |
| |
| /** Data Manipulation Language (DML). */ |
| |
| // Select Statement ======================================================================== |
| @Override |
| public Statement visitSelectStatement(IoTDBSqlParser.SelectStatementContext ctx) { |
| QueryStatement queryStatement = new QueryStatement(); |
| |
| // parse SELECT & FROM |
| queryStatement.setSelectComponent(parseSelectClause(ctx.selectClause(), queryStatement)); |
| queryStatement.setFromComponent(parseFromClause(ctx.fromClause())); |
| |
| // parse INTO |
| if (ctx.intoClause() != null) { |
| queryStatement.setIntoComponent(parseIntoClause(ctx.intoClause())); |
| } |
| |
| // parse WHERE |
| if (ctx.whereClause() != null) { |
| queryStatement.setWhereCondition(parseWhereClause(ctx.whereClause())); |
| } |
| |
| // parse GROUP BY |
| if (ctx.groupByClause() != null) { |
| Set<String> groupByKeys = new HashSet<>(); |
| List<IoTDBSqlParser.GroupByAttributeClauseContext> groupByAttributes = |
| ctx.groupByClause().groupByAttributeClause(); |
| for (IoTDBSqlParser.GroupByAttributeClauseContext groupByAttribute : groupByAttributes) { |
| if (groupByAttribute.TIME() != null || groupByAttribute.interval != null) { |
| if (groupByKeys.contains("COMMON")) { |
| throw new SemanticException(GROUP_BY_COMMON_ONLY_ONE_MSG); |
| } |
| |
| groupByKeys.add("COMMON"); |
| queryStatement.setGroupByTimeComponent(parseGroupByTimeClause(groupByAttribute)); |
| } else if (groupByAttribute.LEVEL() != null) { |
| if (groupByKeys.contains("LEVEL")) { |
| throw new SemanticException("duplicated group by key: LEVEL"); |
| } |
| |
| groupByKeys.add("LEVEL"); |
| queryStatement.setGroupByLevelComponent(parseGroupByLevelClause(groupByAttribute)); |
| } else if (groupByAttribute.TAGS() != null) { |
| if (groupByKeys.contains("TAGS")) { |
| throw new SemanticException("duplicated group by key: TAGS"); |
| } |
| |
| groupByKeys.add("TAGS"); |
| queryStatement.setGroupByTagComponent(parseGroupByTagClause(groupByAttribute)); |
| } else if (groupByAttribute.VARIATION() != null) { |
| if (groupByKeys.contains("COMMON")) { |
| throw new SemanticException(GROUP_BY_COMMON_ONLY_ONE_MSG); |
| } |
| |
| groupByKeys.add("COMMON"); |
| queryStatement.setGroupByComponent( |
| parseGroupByClause(groupByAttribute, WindowType.VARIATION_WINDOW)); |
| } else if (groupByAttribute.CONDITION() != null) { |
| if (groupByKeys.contains("COMMON")) { |
| throw new SemanticException(GROUP_BY_COMMON_ONLY_ONE_MSG); |
| } |
| |
| groupByKeys.add("COMMON"); |
| queryStatement.setGroupByComponent( |
| parseGroupByClause(groupByAttribute, WindowType.CONDITION_WINDOW)); |
| } else if (groupByAttribute.SESSION() != null) { |
| if (groupByKeys.contains("COMMON")) { |
| throw new SemanticException(GROUP_BY_COMMON_ONLY_ONE_MSG); |
| } |
| |
| groupByKeys.add("COMMON"); |
| queryStatement.setGroupByComponent( |
| parseGroupByClause(groupByAttribute, WindowType.SESSION_WINDOW)); |
| } else if (groupByAttribute.COUNT() != null) { |
| if (groupByKeys.contains("COMMON")) { |
| throw new SemanticException(GROUP_BY_COMMON_ONLY_ONE_MSG); |
| } |
| |
| groupByKeys.add("COMMON"); |
| queryStatement.setGroupByComponent( |
| parseGroupByClause(groupByAttribute, WindowType.COUNT_WINDOW)); |
| |
| } else { |
| throw new SemanticException("Unknown GROUP BY type."); |
| } |
| } |
| } |
| |
| // parse HAVING |
| if (ctx.havingClause() != null) { |
| queryStatement.setHavingCondition(parseHavingClause(ctx.havingClause())); |
| } |
| |
| // parse ORDER BY |
| if (ctx.orderByClause() != null) { |
| queryStatement.setOrderByComponent( |
| parseOrderByClause( |
| ctx.orderByClause(), |
| ImmutableSet.of(OrderByKey.TIME, OrderByKey.DEVICE, OrderByKey.TIMESERIES))); |
| } |
| |
| // parse FILL |
| if (ctx.fillClause() != null) { |
| queryStatement.setFillComponent(parseFillClause(ctx.fillClause())); |
| } |
| |
| // parse ALIGN BY |
| if (ctx.alignByClause() != null) { |
| queryStatement.setResultSetFormat(parseAlignBy(ctx.alignByClause())); |
| } |
| |
| if (ctx.paginationClause() != null) { |
| // parse SLIMIT & SOFFSET |
| if (ctx.paginationClause().seriesPaginationClause() != null) { |
| if (ctx.paginationClause().seriesPaginationClause().slimitClause() != null) { |
| queryStatement.setSeriesLimit( |
| parseSLimitClause(ctx.paginationClause().seriesPaginationClause().slimitClause())); |
| } |
| if (ctx.paginationClause().seriesPaginationClause().soffsetClause() != null) { |
| queryStatement.setSeriesOffset( |
| parseSOffsetClause(ctx.paginationClause().seriesPaginationClause().soffsetClause())); |
| } |
| } |
| |
| // parse LIMIT & OFFSET |
| if (ctx.paginationClause().rowPaginationClause() != null) { |
| if (ctx.paginationClause().rowPaginationClause().limitClause() != null) { |
| queryStatement.setRowLimit( |
| parseLimitClause(ctx.paginationClause().rowPaginationClause().limitClause())); |
| } |
| if (ctx.paginationClause().rowPaginationClause().offsetClause() != null) { |
| queryStatement.setRowOffset( |
| parseOffsetClause(ctx.paginationClause().rowPaginationClause().offsetClause())); |
| } |
| if (canPushDownLimitOffsetToGroupByTime(queryStatement)) { |
| pushDownLimitOffsetToTimeParameter(queryStatement); |
| } |
| } |
| } |
| |
| queryStatement.setUseWildcard(useWildcard); |
| queryStatement.setLastLevelUseWildcard(lastLevelUseWildcard); |
| return queryStatement; |
| } |
| |
| // ---- Select Clause |
| private SelectComponent parseSelectClause( |
| IoTDBSqlParser.SelectClauseContext ctx, QueryStatement queryStatement) { |
| SelectComponent selectComponent = new SelectComponent(); |
| |
| // parse LAST |
| if (ctx.LAST() != null) { |
| selectComponent.setHasLast(true); |
| } |
| |
| // parse resultColumn |
| Map<String, Expression> aliasToColumnMap = new HashMap<>(); |
| for (IoTDBSqlParser.ResultColumnContext resultColumnContext : ctx.resultColumn()) { |
| ResultColumn resultColumn = parseResultColumn(resultColumnContext); |
| // __endTime shouldn't be included in resultColumns |
| if (resultColumn.getExpression().getExpressionString().equals(ColumnHeaderConstant.ENDTIME)) { |
| queryStatement.setOutputEndTime(true); |
| continue; |
| } |
| if (resultColumn.hasAlias()) { |
| String alias = resultColumn.getAlias(); |
| if (aliasToColumnMap.containsKey(alias)) { |
| throw new SemanticException("duplicate alias in select clause"); |
| } |
| aliasToColumnMap.put(alias, resultColumn.getExpression()); |
| } |
| selectComponent.addResultColumn(resultColumn); |
| } |
| selectComponent.setAliasToColumnMap(aliasToColumnMap); |
| |
| return selectComponent; |
| } |
| |
| private ResultColumn parseResultColumn(IoTDBSqlParser.ResultColumnContext resultColumnContext) { |
| Expression expression = parseExpression(resultColumnContext.expression(), false); |
| if (expression.isConstantOperand()) { |
| throw new SemanticException("Constant operand is not allowed: " + expression); |
| } |
| String alias = null; |
| if (resultColumnContext.AS() != null) { |
| alias = parseAlias(resultColumnContext.alias()); |
| } |
| ResultColumn.ColumnType columnType = |
| ExpressionAnalyzer.identifyOutputColumnType(expression, true); |
| return new ResultColumn(expression, alias, columnType); |
| } |
| |
| // ---- From Clause |
| private FromComponent parseFromClause(IoTDBSqlParser.FromClauseContext ctx) { |
| FromComponent fromComponent = new FromComponent(); |
| List<IoTDBSqlParser.PrefixPathContext> prefixFromPaths = ctx.prefixPath(); |
| for (IoTDBSqlParser.PrefixPathContext prefixFromPath : prefixFromPaths) { |
| PartialPath path = parsePrefixPath(prefixFromPath); |
| fromComponent.addPrefixPath(path); |
| } |
| return fromComponent; |
| } |
| |
| // ---- Into Clause |
| private IntoComponent parseIntoClause(IoTDBSqlParser.IntoClauseContext ctx) { |
| List<IntoItem> intoItems = new ArrayList<>(); |
| for (IoTDBSqlParser.IntoItemContext intoItemContext : ctx.intoItem()) { |
| intoItems.add(parseIntoItem(intoItemContext)); |
| } |
| return new IntoComponent(intoItems); |
| } |
| |
| private IntoItem parseIntoItem(IoTDBSqlParser.IntoItemContext intoItemContext) { |
| boolean isAligned = intoItemContext.ALIGNED() != null; |
| PartialPath intoDevice = parseIntoPath(intoItemContext.intoPath()); |
| List<String> intoMeasurements = |
| intoItemContext.nodeNameInIntoPath().stream() |
| .map(this::parseNodeNameInIntoPath) |
| .collect(Collectors.toList()); |
| return new IntoItem(intoDevice, intoMeasurements, isAligned); |
| } |
| |
| private PartialPath parseIntoPath(IoTDBSqlParser.IntoPathContext intoPathContext) { |
| if (intoPathContext instanceof IoTDBSqlParser.FullPathInIntoPathContext) { |
| return parseFullPathInIntoPath((IoTDBSqlParser.FullPathInIntoPathContext) intoPathContext); |
| } else { |
| List<IoTDBSqlParser.NodeNameInIntoPathContext> nodeNames = |
| ((IoTDBSqlParser.SuffixPathInIntoPathContext) intoPathContext).nodeNameInIntoPath(); |
| String[] path = new String[nodeNames.size()]; |
| for (int i = 0; i < nodeNames.size(); i++) { |
| path[i] = parseNodeNameInIntoPath(nodeNames.get(i)); |
| } |
| return new PartialPath(path); |
| } |
| } |
| |
| // ---- Where Clause |
| private WhereCondition parseWhereClause(IoTDBSqlParser.WhereClauseContext ctx) { |
| Expression predicate = parseExpression(ctx.expression(), true); |
| return new WhereCondition(predicate); |
| } |
| |
| // ---- Group By Clause |
| private GroupByTimeComponent parseGroupByTimeClause( |
| IoTDBSqlParser.GroupByAttributeClauseContext ctx) { |
| GroupByTimeComponent groupByTimeComponent = new GroupByTimeComponent(); |
| |
| // Parse time range |
| if (ctx.timeRange() != null) { |
| parseTimeRangeForGroupByTime(ctx.timeRange(), groupByTimeComponent); |
| groupByTimeComponent.setLeftCRightO(ctx.timeRange().LS_BRACKET() != null); |
| } |
| |
| // Parse time interval |
| groupByTimeComponent.setInterval(DateTimeUtils.constructTimeDuration(ctx.interval.getText())); |
| groupByTimeComponent.setOriginalInterval(ctx.interval.getText()); |
| if (groupByTimeComponent.getInterval().monthDuration == 0 |
| && groupByTimeComponent.getInterval().nonMonthDuration == 0) { |
| throw new SemanticException( |
| "The second parameter time interval should be a positive integer."); |
| } |
| |
| // parse sliding step |
| if (ctx.step != null) { |
| groupByTimeComponent.setSlidingStep(DateTimeUtils.constructTimeDuration(ctx.step.getText())); |
| groupByTimeComponent.setOriginalSlidingStep(ctx.step.getText()); |
| } else { |
| groupByTimeComponent.setSlidingStep(groupByTimeComponent.getInterval()); |
| groupByTimeComponent.setOriginalSlidingStep(groupByTimeComponent.getOriginalInterval()); |
| } |
| TimeDuration slidingStep = groupByTimeComponent.getSlidingStep(); |
| if (slidingStep.containsMonth() |
| && Math.ceil( |
| ((groupByTimeComponent.getEndTime() - groupByTimeComponent.getStartTime()) |
| / (double) slidingStep.getMinTotalDuration(currPrecision))) |
| >= 10000) { |
| throw new SemanticException("The time windows may exceed 10000, please ensure your input."); |
| } |
| if (groupByTimeComponent.getSlidingStep().monthDuration == 0 |
| && groupByTimeComponent.getSlidingStep().nonMonthDuration == 0) { |
| throw new SemanticException( |
| "The third parameter time slidingStep should be a positive integer."); |
| } |
| return groupByTimeComponent; |
| } |
| |
| /** |
| * Parse time range (startTime and endTime) in group by time. |
| * |
| * @throws SemanticException if startTime is larger or equals to endTime in timeRange |
| */ |
| private void parseTimeRangeForGroupByTime( |
| IoTDBSqlParser.TimeRangeContext timeRange, GroupByTimeComponent groupByClauseComponent) { |
| long currentTime = CommonDateTimeUtils.currentTime(); |
| long startTime = parseTimeValue(timeRange.timeValue(0), currentTime); |
| long endTime = parseTimeValue(timeRange.timeValue(1), currentTime); |
| groupByClauseComponent.setStartTime(startTime); |
| groupByClauseComponent.setEndTime(endTime); |
| if (startTime >= endTime) { |
| throw new SemanticException("Start time should be smaller than endTime in GroupBy"); |
| } |
| } |
| |
| private GroupByComponent parseGroupByClause( |
| GroupByAttributeClauseContext ctx, WindowType windowType) { |
| |
| boolean ignoringNull = true; |
| if (ctx.attributePair() != null |
| && !ctx.attributePair().isEmpty() |
| && ctx.attributePair().key.getText().equalsIgnoreCase(IGNORENULL)) { |
| ignoringNull = Boolean.parseBoolean(ctx.attributePair().value.getText()); |
| } |
| List<ExpressionContext> expressions = ctx.expression(); |
| if (windowType == WindowType.VARIATION_WINDOW) { |
| ExpressionContext expressionContext = expressions.get(0); |
| GroupByVariationComponent groupByVariationComponent = new GroupByVariationComponent(); |
| Expression expression = parseExpression(expressionContext, true); |
| if (expression.isConstantOperand()) { |
| throw new SemanticException( |
| String.format( |
| "Constant operand [%s] is not allowed in group by variation, there should be an expression", |
| expression.getExpressionString())); |
| } |
| groupByVariationComponent.setControlColumnExpression(expression); |
| groupByVariationComponent.setDelta( |
| ctx.delta == null ? 0 : Double.parseDouble(ctx.delta.getText())); |
| groupByVariationComponent.setIgnoringNull(ignoringNull); |
| return groupByVariationComponent; |
| } else if (windowType == WindowType.CONDITION_WINDOW) { |
| ExpressionContext conditionExpressionContext = expressions.get(0); |
| GroupByConditionComponent groupByConditionComponent = new GroupByConditionComponent(); |
| groupByConditionComponent.setControlColumnExpression( |
| parseExpression(conditionExpressionContext, true)); |
| if (expressions.size() == 2) { |
| groupByConditionComponent.setKeepExpression(parseExpression(expressions.get(1), true)); |
| } else { |
| throw new SemanticException("Keep threshold in group by condition should be set"); |
| } |
| groupByConditionComponent.setIgnoringNull(ignoringNull); |
| return groupByConditionComponent; |
| } else if (windowType == WindowType.SESSION_WINDOW) { |
| long interval = DateTimeUtils.convertDurationStrToLong(ctx.timeInterval.getText()); |
| return new GroupBySessionComponent(interval); |
| } else if (windowType == WindowType.COUNT_WINDOW) { |
| ExpressionContext countExpressionContext = expressions.get(0); |
| long countNumber = Long.parseLong(ctx.countNumber.getText()); |
| GroupByCountComponent groupByCountComponent = new GroupByCountComponent(countNumber); |
| Expression expression = parseExpression(countExpressionContext, true); |
| if (expression.isConstantOperand()) { |
| throw new SemanticException( |
| String.format( |
| "Constant operand [%s] is not allowed in group by count, there should be an expression", |
| expression.getExpressionString())); |
| } |
| groupByCountComponent.setControlColumnExpression(expression); |
| groupByCountComponent.setIgnoringNull(ignoringNull); |
| return groupByCountComponent; |
| } else { |
| throw new SemanticException("Unsupported window type"); |
| } |
| } |
| |
| private GroupByLevelComponent parseGroupByLevelClause( |
| IoTDBSqlParser.GroupByAttributeClauseContext ctx) { |
| GroupByLevelComponent groupByLevelComponent = new GroupByLevelComponent(); |
| int[] levels = new int[ctx.INTEGER_LITERAL().size()]; |
| for (int i = 0; i < ctx.INTEGER_LITERAL().size(); i++) { |
| levels[i] = Integer.parseInt(ctx.INTEGER_LITERAL().get(i).getText()); |
| } |
| groupByLevelComponent.setLevels(levels); |
| return groupByLevelComponent; |
| } |
| |
| private GroupByTagComponent parseGroupByTagClause( |
| IoTDBSqlParser.GroupByAttributeClauseContext ctx) { |
| Set<String> tagKeys = new LinkedHashSet<>(); |
| for (IdentifierContext identifierContext : ctx.identifier()) { |
| String key = parseIdentifier(identifierContext.getText()); |
| if (tagKeys.contains(key)) { |
| throw new SemanticException("duplicated key in GROUP BY TAGS: " + key); |
| } |
| tagKeys.add(key); |
| } |
| return new GroupByTagComponent(new ArrayList<>(tagKeys)); |
| } |
| |
| // ---- Having Clause |
| private HavingCondition parseHavingClause(IoTDBSqlParser.HavingClauseContext ctx) { |
| Expression predicate = parseExpression(ctx.expression(), true); |
| return new HavingCondition(predicate); |
| } |
| |
| // ---- Order By Clause |
| // all SortKeys should be contained by limitSet |
| private OrderByComponent parseOrderByClause( |
| IoTDBSqlParser.OrderByClauseContext ctx, ImmutableSet<String> limitSet) { |
| OrderByComponent orderByComponent = new OrderByComponent(); |
| Set<String> sortKeySet = new HashSet<>(); |
| for (IoTDBSqlParser.OrderByAttributeClauseContext orderByAttributeClauseContext : |
| ctx.orderByAttributeClause()) { |
| // if the order by clause is unique, then the following sort keys will be ignored |
| if (orderByComponent.isUnique()) { |
| break; |
| } |
| SortItem sortItem = parseOrderByAttributeClause(orderByAttributeClauseContext, limitSet); |
| |
| String sortKey = sortItem.getSortKey(); |
| if (sortKeySet.contains(sortKey)) { |
| continue; |
| } else { |
| sortKeySet.add(sortKey); |
| } |
| |
| if (sortItem.isExpression()) { |
| orderByComponent.addExpressionSortItem(sortItem); |
| } else { |
| orderByComponent.addSortItem(sortItem); |
| } |
| } |
| return orderByComponent; |
| } |
| |
| private SortItem parseOrderByAttributeClause( |
| IoTDBSqlParser.OrderByAttributeClauseContext ctx, ImmutableSet<String> limitSet) { |
| if (ctx.sortKey() != null) { |
| String sortKey = ctx.sortKey().getText().toUpperCase(); |
| if (!limitSet.contains(sortKey)) { |
| throw new SemanticException( |
| String.format("ORDER BY: sort key[%s] is not contained in '%s'", sortKey, limitSet)); |
| } |
| return new SortItem(sortKey, ctx.DESC() != null ? Ordering.DESC : Ordering.ASC); |
| } else { |
| Expression sortExpression = parseExpression(ctx.expression(), true); |
| return new SortItem( |
| sortExpression, |
| ctx.DESC() != null ? Ordering.DESC : Ordering.ASC, |
| ctx.FIRST() != null ? NullOrdering.FIRST : NullOrdering.LAST); |
| } |
| } |
| |
| // ---- Fill Clause |
| public FillComponent parseFillClause(IoTDBSqlParser.FillClauseContext ctx) { |
| FillComponent fillComponent = new FillComponent(); |
| if (ctx.LINEAR() != null) { |
| fillComponent.setFillPolicy(FillPolicy.LINEAR); |
| } else if (ctx.PREVIOUS() != null) { |
| fillComponent.setFillPolicy(FillPolicy.PREVIOUS); |
| |
| } else if (ctx.constant() != null) { |
| fillComponent.setFillPolicy(FillPolicy.VALUE); |
| Literal fillValue = parseLiteral(ctx.constant()); |
| fillComponent.setFillValue(fillValue); |
| } else { |
| throw new SemanticException("Unknown FILL type."); |
| } |
| if (ctx.interval != null) { |
| if (fillComponent.getFillPolicy() != FillPolicy.PREVIOUS) { |
| throw new SemanticException( |
| "Only FILL(PREVIOUS) support specifying the time duration threshold."); |
| } |
| fillComponent.setTimeDurationThreshold( |
| DateTimeUtils.constructTimeDuration(ctx.interval.getText())); |
| } |
| return fillComponent; |
| } |
| |
| private Literal parseLiteral(ConstantContext constantContext) { |
| String text = constantContext.getText(); |
| if (constantContext.boolean_literal() != null) { |
| return new BooleanLiteral(text); |
| } else if (constantContext.STRING_LITERAL() != null) { |
| return new StringLiteral(parseStringLiteral(text)); |
| } else if (constantContext.INTEGER_LITERAL() != null) { |
| return new LongLiteral(text); |
| } else if (constantContext.realLiteral() != null) { |
| return new DoubleLiteral(text); |
| } else if (constantContext.dateExpression() != null) { |
| return new LongLiteral(parseDateExpression(constantContext.dateExpression())); |
| } else { |
| throw new SemanticException("Unsupported constant value in FILL: " + text); |
| } |
| } |
| |
| // parse LIMIT & OFFSET |
| private long parseLimitClause(IoTDBSqlParser.LimitClauseContext ctx) { |
| long limit; |
| try { |
| limit = Long.parseLong(ctx.INTEGER_LITERAL().getText()); |
| } catch (NumberFormatException e) { |
| throw new SemanticException("Out of range. LIMIT <N>: N should be Int64."); |
| } |
| if (limit <= 0) { |
| throw new SemanticException("LIMIT <N>: N should be greater than 0."); |
| } |
| return limit; |
| } |
| |
| private long parseOffsetClause(IoTDBSqlParser.OffsetClauseContext ctx) { |
| long offset; |
| try { |
| offset = Long.parseLong(ctx.INTEGER_LITERAL().getText()); |
| } catch (NumberFormatException e) { |
| throw new SemanticException( |
| "Out of range. OFFSET <OFFSETValue>: OFFSETValue should be Int64."); |
| } |
| if (offset < 0) { |
| throw new SemanticException("OFFSET <OFFSETValue>: OFFSETValue should >= 0."); |
| } |
| return offset; |
| } |
| |
| // parse SLIMIT & SOFFSET |
| private int parseSLimitClause(IoTDBSqlParser.SlimitClauseContext ctx) { |
| int slimit; |
| try { |
| slimit = Integer.parseInt(ctx.INTEGER_LITERAL().getText()); |
| } catch (NumberFormatException e) { |
| throw new SemanticException("Out of range. SLIMIT <SN>: SN should be Int32."); |
| } |
| if (slimit <= 0) { |
| throw new SemanticException("SLIMIT <SN>: SN should be greater than 0."); |
| } |
| return slimit; |
| } |
| |
| // parse SOFFSET |
| public int parseSOffsetClause(IoTDBSqlParser.SoffsetClauseContext ctx) { |
| int soffset; |
| try { |
| soffset = Integer.parseInt(ctx.INTEGER_LITERAL().getText()); |
| } catch (NumberFormatException e) { |
| throw new SemanticException( |
| "Out of range. SOFFSET <SOFFSETValue>: SOFFSETValue should be Int32."); |
| } |
| if (soffset < 0) { |
| throw new SemanticException("SOFFSET <SOFFSETValue>: SOFFSETValue should >= 0."); |
| } |
| return soffset; |
| } |
| |
| // ---- Align By Clause |
| private ResultSetFormat parseAlignBy(IoTDBSqlParser.AlignByClauseContext ctx) { |
| if (ctx.DEVICE() != null) { |
| return ResultSetFormat.ALIGN_BY_DEVICE; |
| } else { |
| return ResultSetFormat.ALIGN_BY_TIME; |
| } |
| } |
| |
| // Insert Statement ======================================================================== |
| |
| @Override |
| public Statement visitInsertStatement(IoTDBSqlParser.InsertStatementContext ctx) { |
| InsertStatement insertStatement = new InsertStatement(); |
| insertStatement.setDevice(parsePrefixPath(ctx.prefixPath())); |
| int timeIndex = parseInsertColumnSpec(ctx.insertColumnsSpec(), insertStatement); |
| parseInsertValuesSpec(ctx.insertValuesSpec(), insertStatement, timeIndex); |
| insertStatement.setAligned(ctx.ALIGNED() != null); |
| return insertStatement; |
| } |
| |
| private int parseInsertColumnSpec( |
| IoTDBSqlParser.InsertColumnsSpecContext ctx, InsertStatement insertStatement) { |
| List<String> measurementList = new ArrayList<>(); |
| int timeIndex = -1; |
| |
| for (int i = 0, size = ctx.insertColumn().size(); i < size; i++) { |
| String measurement = parseInsertColumn(ctx.insertColumn(i)); |
| if ("time".equalsIgnoreCase(measurement) || "timestamp".equalsIgnoreCase(measurement)) { |
| if (timeIndex != -1) { |
| throw new SemanticException("One row should only have one time value"); |
| } else { |
| timeIndex = i; |
| } |
| } else { |
| measurementList.add(measurement); |
| } |
| } |
| if (measurementList.isEmpty()) { |
| throw new SemanticException("InsertStatement should contain at least one measurement"); |
| } |
| insertStatement.setMeasurementList(measurementList.toArray(new String[0])); |
| return timeIndex; |
| } |
| |
| private String parseInsertColumn(IoTDBSqlParser.InsertColumnContext columnContext) { |
| return parseNodeString(columnContext.getText()); |
| } |
| |
| private void parseInsertValuesSpec( |
| IoTDBSqlParser.InsertValuesSpecContext ctx, InsertStatement insertStatement, int timeIndex) { |
| List<IoTDBSqlParser.RowContext> rows = ctx.row(); |
| if (timeIndex == -1 && rows.size() != 1) { |
| throw new SemanticException("need timestamps when insert multi rows"); |
| } |
| List<String[]> valuesList = new ArrayList<>(); |
| long[] timeArray = new long[rows.size()]; |
| for (int i = 0, size = rows.size(); i < size; i++) { |
| IoTDBSqlParser.RowContext row = rows.get(i); |
| // parse timestamp |
| long timestamp; |
| List<String> valueList = new ArrayList<>(); |
| // using now() instead |
| if (timeIndex == -1) { |
| timestamp = CommonDateTimeUtils.currentTime(); |
| } else { |
| timestamp = parseTimeValue(row.constant(timeIndex)); |
| TimestampPrecisionUtils.checkTimestampPrecision(timestamp); |
| } |
| timeArray[i] = timestamp; |
| |
| // parse values |
| List<ConstantContext> values = row.constant(); |
| for (int j = 0, columnCount = values.size(); j < columnCount; j++) { |
| if (j != timeIndex) { |
| if (values.get(j).STRING_LITERAL() != null) { |
| valueList.add(parseStringLiteralInInsertValue(values.get(j).getText())); |
| } else { |
| valueList.add(values.get(j).getText()); |
| } |
| } |
| } |
| |
| valuesList.add(valueList.toArray(new String[0])); |
| } |
| insertStatement.setTimes(timeArray); |
| insertStatement.setValuesList(valuesList); |
| } |
| |
| private long parseTimeValue(ConstantContext constant) { |
| if (constant.INTEGER_LITERAL() != null) { |
| try { |
| if (constant.MINUS() != null) { |
| return -Long.parseLong(constant.INTEGER_LITERAL().getText()); |
| } |
| return Long.parseLong(constant.INTEGER_LITERAL().getText()); |
| } catch (NumberFormatException e) { |
| throw new SemanticException( |
| String.format("Can not parse %s to long value", constant.INTEGER_LITERAL().getText())); |
| } |
| } else if (constant.dateExpression() != null) { |
| return parseDateExpression(constant.dateExpression(), CommonDateTimeUtils.currentTime()); |
| } else { |
| throw new SemanticException(String.format("Can not parse %s to time", constant)); |
| } |
| } |
| |
| // Load File |
| |
| @Override |
| public Statement visitLoadFile(IoTDBSqlParser.LoadFileContext ctx) { |
| try { |
| LoadTsFileStatement loadTsFileStatement = |
| new LoadTsFileStatement(parseStringLiteral(ctx.fileName.getText())); |
| if (ctx.loadFileAttributeClauses() != null) { |
| for (IoTDBSqlParser.LoadFileAttributeClauseContext attributeContext : |
| ctx.loadFileAttributeClauses().loadFileAttributeClause()) { |
| parseLoadFileAttributeClause(loadTsFileStatement, attributeContext); |
| } |
| } |
| return loadTsFileStatement; |
| } catch (FileNotFoundException e) { |
| throw new SemanticException(e.getMessage()); |
| } |
| } |
| |
| /** |
| * Used for parsing load tsfile, context will be one of "SCHEMA, LEVEL, METADATA", and maybe |
| * followed by a recursion property statement. |
| * |
| * @param loadTsFileStatement the result statement, setting by clause context |
| * @param ctx context of property statement |
| * @throws SemanticException if AUTOREGISTER | SGLEVEL | VERIFY are not specified |
| */ |
| private void parseLoadFileAttributeClause( |
| LoadTsFileStatement loadTsFileStatement, IoTDBSqlParser.LoadFileAttributeClauseContext ctx) { |
| if (ctx.ONSUCCESS() != null) { |
| loadTsFileStatement.setDeleteAfterLoad(ctx.DELETE() != null); |
| } else if (ctx.SGLEVEL() != null) { |
| loadTsFileStatement.setDatabaseLevel(Integer.parseInt(ctx.INTEGER_LITERAL().getText())); |
| } else if (ctx.VERIFY() != null) { |
| loadTsFileStatement.setVerifySchema(Boolean.parseBoolean(ctx.boolean_literal().getText())); |
| } else { |
| throw new SemanticException( |
| String.format( |
| "Load tsfile format %s error, please input AUTOREGISTER | SGLEVEL | VERIFY.", |
| ctx.getText())); |
| } |
| } |
| |
| /** Common Parsers. */ |
| |
| // IoTDB Objects ======================================================================== |
| private PartialPath parseFullPath(IoTDBSqlParser.FullPathContext ctx) { |
| List<IoTDBSqlParser.NodeNameWithoutWildcardContext> nodeNamesWithoutStar = |
| ctx.nodeNameWithoutWildcard(); |
| String[] path = new String[nodeNamesWithoutStar.size() + 1]; |
| int i = 0; |
| if (ctx.ROOT() != null) { |
| path[0] = ctx.ROOT().getText(); |
| } |
| for (IoTDBSqlParser.NodeNameWithoutWildcardContext nodeNameWithoutStar : nodeNamesWithoutStar) { |
| i++; |
| path[i] = parseNodeNameWithoutWildCard(nodeNameWithoutStar); |
| } |
| return new PartialPath(path); |
| } |
| |
| private PartialPath parseFullPathInExpression( |
| IoTDBSqlParser.FullPathInExpressionContext ctx, boolean canUseFullPath) { |
| List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName(); |
| int size = nodeNames.size(); |
| if (ctx.ROOT() != null) { |
| if (!canUseFullPath) { |
| // now full path cannot occur in SELECT only |
| throw new SemanticException("Path can not start with root in select clause."); |
| } |
| size++; |
| } |
| String[] path = new String[size]; |
| if (ctx.ROOT() != null) { |
| path[0] = ctx.ROOT().getText(); |
| for (int i = 0; i < nodeNames.size(); i++) { |
| path[i + 1] = parseNodeName(nodeNames.get(i)); |
| } |
| } else { |
| for (int i = 0; i < nodeNames.size(); i++) { |
| path[i] = parseNodeName(nodeNames.get(i)); |
| } |
| } |
| if (!lastLevelUseWildcard |
| && !nodeNames.isEmpty() |
| && !nodeNames.get(nodeNames.size() - 1).wildcard().isEmpty()) { |
| lastLevelUseWildcard = true; |
| } |
| return new PartialPath(path); |
| } |
| |
| private PartialPath parseFullPathInIntoPath(IoTDBSqlParser.FullPathInIntoPathContext ctx) { |
| List<IoTDBSqlParser.NodeNameInIntoPathContext> nodeNames = ctx.nodeNameInIntoPath(); |
| String[] path = new String[nodeNames.size() + 1]; |
| int i = 0; |
| if (ctx.ROOT() != null) { |
| path[0] = ctx.ROOT().getText(); |
| } |
| for (IoTDBSqlParser.NodeNameInIntoPathContext nodeName : nodeNames) { |
| i++; |
| path[i] = parseNodeNameInIntoPath(nodeName); |
| } |
| return new PartialPath(path); |
| } |
| |
| private PartialPath parsePrefixPath(IoTDBSqlParser.PrefixPathContext ctx) { |
| List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName(); |
| String[] path = new String[nodeNames.size() + 1]; |
| path[0] = ctx.ROOT().getText(); |
| for (int i = 0; i < nodeNames.size(); i++) { |
| path[i + 1] = parseNodeName(nodeNames.get(i)); |
| } |
| return new PartialPath(path); |
| } |
| |
| private String parseNodeName(IoTDBSqlParser.NodeNameContext ctx) { |
| if (!useWildcard && !ctx.wildcard().isEmpty()) { |
| useWildcard = true; |
| } |
| return parseNodeString(ctx.getText()); |
| } |
| |
| private String parseNodeNameWithoutWildCard(IoTDBSqlParser.NodeNameWithoutWildcardContext ctx) { |
| return parseNodeString(ctx.getText()); |
| } |
| |
| private String parseNodeNameInIntoPath(IoTDBSqlParser.NodeNameInIntoPathContext ctx) { |
| return parseNodeStringInIntoPath(ctx.getText()); |
| } |
| |
| public static String parseNodeString(String nodeName) { |
| if (nodeName.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD) |
| || nodeName.equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) { |
| return nodeName; |
| } |
| if (nodeName.startsWith(TsFileConstant.BACK_QUOTE_STRING) |
| && nodeName.endsWith(TsFileConstant.BACK_QUOTE_STRING)) { |
| return PathUtils.removeBackQuotesIfNecessary(nodeName); |
| } |
| checkNodeName(nodeName); |
| return nodeName; |
| } |
| |
| private static String parseNodeStringInIntoPath(String nodeName) { |
| if (nodeName.equals(IoTDBConstant.DOUBLE_COLONS)) { |
| return nodeName; |
| } |
| if (nodeName.startsWith(TsFileConstant.BACK_QUOTE_STRING) |
| && nodeName.endsWith(TsFileConstant.BACK_QUOTE_STRING)) { |
| // needn't remove back_quotes here, we will remove them after placeholders applied |
| return nodeName; |
| } |
| checkNodeNameInIntoPath(nodeName); |
| return nodeName; |
| } |
| |
| private static void checkNodeName(String src) { |
| // node name could start with * and end with * |
| if (!TsFileConstant.NODE_NAME_PATTERN.matcher(src).matches()) { |
| throw new SemanticException( |
| String.format( |
| "%s is illegal, unquoted node name can only consist of digits, characters and underscore, or start or end with wildcard", |
| src)); |
| } |
| } |
| |
| private static void checkNodeNameInIntoPath(String src) { |
| // ${} are allowed |
| if (!NODE_NAME_IN_INTO_PATH_PATTERN.matcher(src).matches()) { |
| throw new SemanticException( |
| String.format( |
| "%s is illegal, unquoted node name in select into clause can only consist of digits, characters, $, { and }", |
| src)); |
| } |
| } |
| |
| private static void checkIdentifier(String src) { |
| if (!TsFileConstant.IDENTIFIER_PATTERN.matcher(src).matches() || PathUtils.isRealNumber(src)) { |
| throw new SemanticException( |
| String.format( |
| "%s is illegal, identifier not enclosed with backticks can only consist of digits, characters and underscore.", |
| src)); |
| } |
| } |
| |
| // Literals ======================================================================== |
| |
| public long parseDateFormat(String timestampStr) { |
| if (timestampStr == null || "".equals(timestampStr.trim())) { |
| throw new SemanticException("input timestamp cannot be empty"); |
| } |
| if (timestampStr.equalsIgnoreCase(SqlConstant.NOW_FUNC)) { |
| return CommonDateTimeUtils.currentTime(); |
| } |
| try { |
| return DateTimeUtils.convertDatetimeStrToLong(timestampStr, zoneId); |
| } catch (Exception e) { |
| throw new SemanticException( |
| 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)); |
| } |
| } |
| |
| public long parseDateFormat(String timestampStr, long currentTime) { |
| if (timestampStr == null || "".equals(timestampStr.trim())) { |
| throw new SemanticException("input timestamp cannot be empty"); |
| } |
| if (timestampStr.equalsIgnoreCase(SqlConstant.NOW_FUNC)) { |
| return currentTime; |
| } |
| try { |
| return DateTimeUtils.convertDatetimeStrToLong(timestampStr, zoneId); |
| } catch (Exception e) { |
| throw new SemanticException( |
| 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 String parseStringLiteral(String src) { |
| if (2 <= src.length()) { |
| // do not unescape string |
| String unWrappedString = src.substring(1, src.length() - 1); |
| if (src.charAt(0) == '\"' && src.charAt(src.length() - 1) == '\"') { |
| // replace "" with " |
| String replaced = unWrappedString.replace("\"\"", "\""); |
| return replaced.length() == 0 ? "" : replaced; |
| } |
| if ((src.charAt(0) == '\'' && src.charAt(src.length() - 1) == '\'')) { |
| // replace '' with ' |
| String replaced = unWrappedString.replace("''", "'"); |
| return replaced.length() == 0 ? "" : replaced; |
| } |
| } |
| return src; |
| } |
| |
| private String parseStringLiteralInInsertValue(String src) { |
| if (2 <= src.length() |
| && ((src.charAt(0) == '\"' && src.charAt(src.length() - 1) == '\"') |
| || (src.charAt(0) == '\'' && src.charAt(src.length() - 1) == '\''))) { |
| return "'" + parseStringLiteral(src) + "'"; |
| } |
| return src; |
| } |
| |
| public static String parseIdentifier(String src) { |
| if (src.startsWith(TsFileConstant.BACK_QUOTE_STRING) |
| && src.endsWith(TsFileConstant.BACK_QUOTE_STRING)) { |
| return src.substring(1, src.length() - 1) |
| .replace(TsFileConstant.DOUBLE_BACK_QUOTE_STRING, TsFileConstant.BACK_QUOTE_STRING); |
| } |
| checkIdentifier(src); |
| return src; |
| } |
| |
| // Alias |
| |
| /** Function for parsing Alias of ResultColumn. */ |
| private String parseAlias(IoTDBSqlParser.AliasContext ctx) { |
| String alias; |
| if (ctx.constant() != null) { |
| alias = parseConstant(ctx.constant()); |
| } else { |
| alias = parseIdentifier(ctx.identifier().getText()); |
| } |
| return alias; |
| } |
| |
| /** |
| * Function for parsing AliasNode. |
| * |
| * @throws SemanticException if the alias pattern is not supported |
| */ |
| private String parseAliasNode(IoTDBSqlParser.AliasContext ctx) { |
| String alias; |
| if (ctx.constant() != null) { |
| alias = parseConstant(ctx.constant()); |
| if (PathUtils.isRealNumber(alias) |
| || !TsFileConstant.IDENTIFIER_PATTERN.matcher(alias).matches()) { |
| throw new SemanticException("Not support for this alias, Please enclose in back quotes."); |
| } |
| } else { |
| alias = parseNodeString(ctx.identifier().getText()); |
| } |
| return alias; |
| } |
| |
| /** Data Control Language (DCL). */ |
| |
| // Create User |
| @Override |
| public Statement visitCreateUser(IoTDBSqlParser.CreateUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.CREATE_USER); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| authorStatement.setPassWord(parseStringLiteral(ctx.password.getText())); |
| return authorStatement; |
| } |
| |
| // Create Role |
| |
| @Override |
| public Statement visitCreateRole(IoTDBSqlParser.CreateRoleContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.CREATE_ROLE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| return authorStatement; |
| } |
| |
| // Alter Password |
| @Override |
| public Statement visitAlterUser(IoTDBSqlParser.AlterUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.UPDATE_USER); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| authorStatement.setNewPassword(parseStringLiteral(ctx.password.getText())); |
| return authorStatement; |
| } |
| |
| // Grant User Privileges |
| @Override |
| public Statement visitGrantUser(IoTDBSqlParser.GrantUserContext ctx) { |
| String[] privileges = parsePrivilege(ctx.privileges()); |
| List<PartialPath> nodeNameList = |
| ctx.prefixPath().stream() |
| .map(this::parsePrefixPath) |
| .distinct() |
| .collect(Collectors.toList()); |
| checkGrantRevokePrivileges(privileges, nodeNameList); |
| String[] priviParsed = parsePrivilege(privileges); |
| |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.GRANT_USER); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| authorStatement.setPrivilegeList(priviParsed); |
| authorStatement.setNodeNameList(nodeNameList); |
| authorStatement.setGrantOpt(ctx.grantOpt() != null); |
| return authorStatement; |
| } |
| |
| // Grant Role Privileges |
| |
| @Override |
| public Statement visitGrantRole(IoTDBSqlParser.GrantRoleContext ctx) { |
| String[] privileges = parsePrivilege(ctx.privileges()); |
| List<PartialPath> nodeNameList = |
| ctx.prefixPath().stream() |
| .map(this::parsePrefixPath) |
| .distinct() |
| .collect(Collectors.toList()); |
| checkGrantRevokePrivileges(privileges, nodeNameList); |
| String[] priviParsed = parsePrivilege(privileges); |
| |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.GRANT_ROLE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| authorStatement.setPrivilegeList(priviParsed); |
| authorStatement.setNodeNameList(nodeNameList); |
| authorStatement.setGrantOpt(ctx.grantOpt() != null); |
| return authorStatement; |
| } |
| |
| // Grant User Role |
| |
| @Override |
| public Statement visitGrantRoleToUser(IoTDBSqlParser.GrantRoleToUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.GRANT_USER_ROLE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| return authorStatement; |
| } |
| |
| // Revoke User Privileges |
| |
| @Override |
| public Statement visitRevokeUser(IoTDBSqlParser.RevokeUserContext ctx) { |
| String[] privileges = parsePrivilege(ctx.privileges()); |
| List<PartialPath> nodeNameList = |
| ctx.prefixPath().stream() |
| .map(this::parsePrefixPath) |
| .distinct() |
| .collect(Collectors.toList()); |
| checkGrantRevokePrivileges(privileges, nodeNameList); |
| String[] priviParsed = parsePrivilege(privileges); |
| |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.REVOKE_USER); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| authorStatement.setPrivilegeList(priviParsed); |
| authorStatement.setNodeNameList(nodeNameList); |
| return authorStatement; |
| } |
| |
| // Revoke Role Privileges |
| |
| @Override |
| public Statement visitRevokeRole(IoTDBSqlParser.RevokeRoleContext ctx) { |
| String[] privileges = parsePrivilege(ctx.privileges()); |
| List<PartialPath> nodeNameList = |
| ctx.prefixPath().stream() |
| .map(this::parsePrefixPath) |
| .distinct() |
| .collect(Collectors.toList()); |
| checkGrantRevokePrivileges(privileges, nodeNameList); |
| String[] priviParsed = parsePrivilege(privileges); |
| |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.REVOKE_ROLE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| authorStatement.setPrivilegeList(priviParsed); |
| authorStatement.setNodeNameList(nodeNameList); |
| return authorStatement; |
| } |
| |
| private void checkGrantRevokePrivileges(String[] privileges, List<PartialPath> nodeNameList) { |
| // 1. all grant or revoke statements need target path. |
| if (nodeNameList.isEmpty()) { |
| throw new SemanticException("Statement needs target paths"); |
| } |
| |
| // 2. if privilege list has system privilege or "ALL", nodeNameList must only contain "root.**". |
| boolean hasSystemPri = false; |
| String errorPrivilegeName = ""; |
| |
| for (String privilege : privileges) { |
| if ("ALL".equalsIgnoreCase(privilege) |
| || (!"READ".equalsIgnoreCase(privilege) |
| && !"WRITE".equalsIgnoreCase(privilege) |
| && !PrivilegeType.valueOf(privilege.toUpperCase()).isPathRelevant())) { |
| hasSystemPri = true; |
| errorPrivilegeName = privilege.toUpperCase(); |
| break; |
| } |
| } |
| if (hasSystemPri |
| && !(nodeNameList.size() == 1 |
| && nodeNameList.contains(new PartialPath(ALL_RESULT_NODES)))) { |
| throw new SemanticException( |
| String.format("[%s] can only be set on path: root.**", errorPrivilegeName)); |
| } |
| } |
| |
| private String[] parsePrivilege(String[] privileges) { |
| Set<String> privSet = new HashSet<>(); |
| for (String priv : privileges) { |
| if (priv.equalsIgnoreCase("READ")) { |
| privSet.add("READ_SCHEMA"); |
| privSet.add("READ_DATA"); |
| continue; |
| } else if (priv.equalsIgnoreCase("WRITE")) { |
| privSet.add("WRITE_DATA"); |
| privSet.add("WRITE_SCHEMA"); |
| continue; |
| } else if (priv.equalsIgnoreCase("ALL")) { |
| for (PrivilegeType type : PrivilegeType.values()) { |
| privSet.add(type.toString()); |
| } |
| continue; |
| } |
| privSet.add(priv); |
| } |
| return privSet.toArray(new String[0]); |
| } |
| |
| // Revoke Role From User |
| @Override |
| public Statement visitRevokeRoleFromUser(IoTDBSqlParser.RevokeRoleFromUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.REVOKE_USER_ROLE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| return authorStatement; |
| } |
| |
| // Drop User |
| |
| @Override |
| public Statement visitDropUser(IoTDBSqlParser.DropUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.DROP_USER); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| return authorStatement; |
| } |
| |
| // Drop Role |
| |
| @Override |
| public Statement visitDropRole(IoTDBSqlParser.DropRoleContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.DROP_ROLE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| return authorStatement; |
| } |
| |
| // List Users |
| |
| @Override |
| public Statement visitListUser(IoTDBSqlParser.ListUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.LIST_USER); |
| if (ctx.roleName != null) { |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| } |
| return authorStatement; |
| } |
| |
| // List Roles |
| |
| @Override |
| public Statement visitListRole(IoTDBSqlParser.ListRoleContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.LIST_ROLE); |
| if (ctx.userName != null) { |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| } |
| return authorStatement; |
| } |
| |
| // List Privileges |
| |
| @Override |
| public Statement visitListPrivilegesUser(IoTDBSqlParser.ListPrivilegesUserContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.LIST_USER_PRIVILEGE); |
| authorStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| return authorStatement; |
| } |
| |
| // List Privileges of Roles On Specific Path |
| |
| @Override |
| public Statement visitListPrivilegesRole(IoTDBSqlParser.ListPrivilegesRoleContext ctx) { |
| AuthorStatement authorStatement = new AuthorStatement(AuthorType.LIST_ROLE_PRIVILEGE); |
| authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText())); |
| return authorStatement; |
| } |
| |
| private String[] parsePrivilege(IoTDBSqlParser.PrivilegesContext ctx) { |
| List<IoTDBSqlParser.PrivilegeValueContext> privilegeList = ctx.privilegeValue(); |
| List<String> privileges = new ArrayList<>(); |
| for (IoTDBSqlParser.PrivilegeValueContext privilegeValue : privilegeList) { |
| privileges.add(privilegeValue.getText()); |
| } |
| return privileges.toArray(new String[0]); |
| } |
| |
| // Create database |
| @Override |
| public Statement visitCreateDatabase(IoTDBSqlParser.CreateDatabaseContext ctx) { |
| DatabaseSchemaStatement databaseSchemaStatement = |
| new DatabaseSchemaStatement(DatabaseSchemaStatement.DatabaseSchemaStatementType.CREATE); |
| PartialPath path = parsePrefixPath(ctx.prefixPath()); |
| databaseSchemaStatement.setDatabasePath(path); |
| if (ctx.databaseAttributesClause() != null) { |
| parseDatabaseAttributesClause(databaseSchemaStatement, ctx.databaseAttributesClause()); |
| } |
| return databaseSchemaStatement; |
| } |
| |
| @Override |
| public Statement visitAlterDatabase(IoTDBSqlParser.AlterDatabaseContext ctx) { |
| DatabaseSchemaStatement databaseSchemaStatement = |
| new DatabaseSchemaStatement(DatabaseSchemaStatement.DatabaseSchemaStatementType.ALTER); |
| PartialPath path = parsePrefixPath(ctx.prefixPath()); |
| databaseSchemaStatement.setDatabasePath(path); |
| parseDatabaseAttributesClause(databaseSchemaStatement, ctx.databaseAttributesClause()); |
| return databaseSchemaStatement; |
| } |
| |
| private void parseDatabaseAttributesClause( |
| DatabaseSchemaStatement databaseSchemaStatement, |
| IoTDBSqlParser.DatabaseAttributesClauseContext ctx) { |
| for (IoTDBSqlParser.DatabaseAttributeClauseContext attribute : ctx.databaseAttributeClause()) { |
| IoTDBSqlParser.DatabaseAttributeKeyContext attributeKey = attribute.databaseAttributeKey(); |
| if (attributeKey.TTL() != null) { |
| long ttl = Long.parseLong(attribute.INTEGER_LITERAL().getText()); |
| databaseSchemaStatement.setTtl(ttl); |
| } else if (attributeKey.SCHEMA_REPLICATION_FACTOR() != null) { |
| int schemaReplicationFactor = Integer.parseInt(attribute.INTEGER_LITERAL().getText()); |
| databaseSchemaStatement.setSchemaReplicationFactor(schemaReplicationFactor); |
| } else if (attributeKey.DATA_REPLICATION_FACTOR() != null) { |
| int dataReplicationFactor = Integer.parseInt(attribute.INTEGER_LITERAL().getText()); |
| databaseSchemaStatement.setDataReplicationFactor(dataReplicationFactor); |
| } else if (attributeKey.TIME_PARTITION_INTERVAL() != null) { |
| long timePartitionInterval = Long.parseLong(attribute.INTEGER_LITERAL().getText()); |
| databaseSchemaStatement.setTimePartitionInterval(timePartitionInterval); |
| } else if (attributeKey.SCHEMA_REGION_GROUP_NUM() != null) { |
| int schemaRegionGroupNum = Integer.parseInt(attribute.INTEGER_LITERAL().getText()); |
| databaseSchemaStatement.setSchemaRegionGroupNum(schemaRegionGroupNum); |
| } else if (attributeKey.DATA_REGION_GROUP_NUM() != null) { |
| int dataRegionGroupNum = Integer.parseInt(attribute.INTEGER_LITERAL().getText()); |
| databaseSchemaStatement.setDataRegionGroupNum(dataRegionGroupNum); |
| } |
| } |
| } |
| |
| @Override |
| public Statement visitSetTTL(IoTDBSqlParser.SetTTLContext ctx) { |
| SetTTLStatement setTTLStatement = new SetTTLStatement(); |
| PartialPath path = parsePrefixPath(ctx.prefixPath()); |
| long ttl = Long.parseLong(ctx.INTEGER_LITERAL().getText()); |
| setTTLStatement.setDatabasePath(path); |
| setTTLStatement.setTTL(ttl); |
| return setTTLStatement; |
| } |
| |
| @Override |
| public Statement visitUnsetTTL(IoTDBSqlParser.UnsetTTLContext ctx) { |
| UnSetTTLStatement unSetTTLStatement = new UnSetTTLStatement(); |
| PartialPath partialPath = parsePrefixPath(ctx.prefixPath()); |
| unSetTTLStatement.setDatabasePath(partialPath); |
| return unSetTTLStatement; |
| } |
| |
| @Override |
| public Statement visitShowTTL(IoTDBSqlParser.ShowTTLContext ctx) { |
| ShowTTLStatement showTTLStatement = new ShowTTLStatement(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| PartialPath partialPath = parsePrefixPath(prefixPathContext); |
| showTTLStatement.addPathPatterns(partialPath); |
| } |
| return showTTLStatement; |
| } |
| |
| @Override |
| public Statement visitShowAllTTL(IoTDBSqlParser.ShowAllTTLContext ctx) { |
| ShowTTLStatement showTTLStatement = new ShowTTLStatement(); |
| showTTLStatement.setAll(true); |
| return showTTLStatement; |
| } |
| |
| @Override |
| public Statement visitShowVariables(IoTDBSqlParser.ShowVariablesContext ctx) { |
| return new ShowVariablesStatement(); |
| } |
| |
| @Override |
| public Statement visitShowCluster(IoTDBSqlParser.ShowClusterContext ctx) { |
| ShowClusterStatement showClusterStatement = new ShowClusterStatement(); |
| if (ctx.DETAILS() != null) { |
| showClusterStatement.setDetails(true); |
| } |
| return showClusterStatement; |
| } |
| |
| @Override |
| public Statement visitShowClusterId(IoTDBSqlParser.ShowClusterIdContext ctx) { |
| return new ShowClusterIdStatement(); |
| } |
| |
| @Override |
| public Statement visitDropDatabase(IoTDBSqlParser.DropDatabaseContext ctx) { |
| DeleteDatabaseStatement dropDatabaseStatement = new DeleteDatabaseStatement(); |
| List<IoTDBSqlParser.PrefixPathContext> prefixPathContexts = ctx.prefixPath(); |
| List<String> paths = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : prefixPathContexts) { |
| paths.add(parsePrefixPath(prefixPathContext).getFullPath()); |
| } |
| dropDatabaseStatement.setPrefixPath(paths); |
| return dropDatabaseStatement; |
| } |
| |
| // Explain ======================================================================== |
| @Override |
| public Statement visitExplain(IoTDBSqlParser.ExplainContext ctx) { |
| QueryStatement queryStatement = (QueryStatement) visitSelectStatement(ctx.selectStatement()); |
| if (ctx.ANALYZE() == null) { |
| return new ExplainStatement(queryStatement); |
| } |
| ExplainAnalyzeStatement explainAnalyzeStatement = new ExplainAnalyzeStatement(queryStatement); |
| if (ctx.VERBOSE() != null) { |
| explainAnalyzeStatement.setVerbose(true); |
| } |
| return explainAnalyzeStatement; |
| } |
| |
| @Override |
| public Statement visitDeleteStatement(IoTDBSqlParser.DeleteStatementContext ctx) { |
| DeleteDataStatement statement = new DeleteDataStatement(); |
| List<IoTDBSqlParser.PrefixPathContext> prefixPaths = ctx.prefixPath(); |
| List<PartialPath> pathList = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPath : prefixPaths) { |
| pathList.add(parsePrefixPath(prefixPath)); |
| } |
| statement.setPathList(pathList); |
| if (ctx.whereClause() != null) { |
| WhereCondition whereCondition = parseWhereClause(ctx.whereClause()); |
| TimeRange timeRange = parseDeleteTimeRange(whereCondition.getPredicate()); |
| statement.setTimeRange(timeRange); |
| } else { |
| statement.setTimeRange(new TimeRange(Long.MIN_VALUE, Long.MAX_VALUE)); |
| } |
| return statement; |
| } |
| |
| private TimeRange parseDeleteTimeRange(Expression predicate) { |
| if (predicate instanceof LogicAndExpression) { |
| TimeRange leftTimeRange = |
| parseDeleteTimeRange(((LogicAndExpression) predicate).getLeftExpression()); |
| TimeRange rightTimeRange = |
| parseDeleteTimeRange(((LogicAndExpression) predicate).getRightExpression()); |
| return new TimeRange( |
| Math.max(leftTimeRange.getMin(), rightTimeRange.getMin()), |
| Math.min(leftTimeRange.getMax(), rightTimeRange.getMax())); |
| } else if (predicate instanceof CompareBinaryExpression) { |
| if (((CompareBinaryExpression) predicate).getLeftExpression() instanceof TimestampOperand) { |
| return parseTimeRangeForDeleteTimeRange( |
| predicate.getExpressionType(), |
| ((CompareBinaryExpression) predicate).getLeftExpression(), |
| ((CompareBinaryExpression) predicate).getRightExpression()); |
| } else { |
| return parseTimeRangeForDeleteTimeRange( |
| predicate.getExpressionType(), |
| ((CompareBinaryExpression) predicate).getRightExpression(), |
| ((CompareBinaryExpression) predicate).getLeftExpression()); |
| } |
| } else { |
| throw new SemanticException(DELETE_RANGE_ERROR_MSG); |
| } |
| } |
| |
| private TimeRange parseTimeRangeForDeleteTimeRange( |
| ExpressionType expressionType, Expression timeExpression, Expression valueExpression) { |
| if (!(timeExpression instanceof TimestampOperand) |
| || !(valueExpression instanceof ConstantOperand)) { |
| throw new SemanticException(DELETE_ONLY_SUPPORT_TIME_EXP_ERROR_MSG); |
| } |
| |
| if (((ConstantOperand) valueExpression).getDataType() != TSDataType.INT64) { |
| throw new SemanticException("The datatype of timestamp should be LONG."); |
| } |
| |
| long time = Long.parseLong(((ConstantOperand) valueExpression).getValueString()); |
| switch (expressionType) { |
| case LESS_THAN: |
| return new TimeRange(Long.MIN_VALUE, time - 1); |
| case LESS_EQUAL: |
| return new TimeRange(Long.MIN_VALUE, time); |
| case GREATER_THAN: |
| return new TimeRange(time + 1, Long.MAX_VALUE); |
| case GREATER_EQUAL: |
| return new TimeRange(time, Long.MAX_VALUE); |
| case EQUAL_TO: |
| return new TimeRange(time, time); |
| default: |
| throw new SemanticException(DELETE_RANGE_ERROR_MSG); |
| } |
| } |
| |
| /** function for parsing file path used by LOAD statement. */ |
| public String parseFilePath(String src) { |
| return src.substring(1, src.length() - 1); |
| } |
| |
| // Expression & Predicate ======================================================================== |
| |
| private Expression parseExpression( |
| IoTDBSqlParser.ExpressionContext context, boolean canUseFullPath) { |
| if (context.unaryInBracket != null) { |
| return parseExpression(context.unaryInBracket, canUseFullPath); |
| } |
| |
| if (context.expressionAfterUnaryOperator != null) { |
| if (context.MINUS() != null) { |
| return new NegationExpression( |
| parseExpression(context.expressionAfterUnaryOperator, canUseFullPath)); |
| } |
| if (context.operator_not() != null) { |
| return new LogicNotExpression( |
| parseExpression(context.expressionAfterUnaryOperator, canUseFullPath)); |
| } |
| return parseExpression(context.expressionAfterUnaryOperator, canUseFullPath); |
| } |
| |
| if (context.leftExpression != null && context.rightExpression != null) { |
| Expression leftExpression = parseExpression(context.leftExpression, canUseFullPath); |
| Expression rightExpression = parseExpression(context.rightExpression, canUseFullPath); |
| 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); |
| } |
| if (context.OPERATOR_GT() != null) { |
| return new GreaterThanExpression(leftExpression, rightExpression); |
| } |
| if (context.OPERATOR_GTE() != null) { |
| return new GreaterEqualExpression(leftExpression, rightExpression); |
| } |
| if (context.OPERATOR_LT() != null) { |
| return new LessThanExpression(leftExpression, rightExpression); |
| } |
| if (context.OPERATOR_LTE() != null) { |
| return new LessEqualExpression(leftExpression, rightExpression); |
| } |
| if (context.OPERATOR_DEQ() != null || context.OPERATOR_SEQ() != null) { |
| return new EqualToExpression(leftExpression, rightExpression); |
| } |
| if (context.OPERATOR_NEQ() != null) { |
| return new NonEqualExpression(leftExpression, rightExpression); |
| } |
| if (context.operator_and() != null) { |
| return new LogicAndExpression(leftExpression, rightExpression); |
| } |
| if (context.operator_or() != null) { |
| return new LogicOrExpression(leftExpression, rightExpression); |
| } |
| throw new UnsupportedOperationException(); |
| } |
| |
| if (context.unaryBeforeRegularOrLikeExpression != null) { |
| if (context.REGEXP() != null) { |
| return parseRegularExpression(context, canUseFullPath); |
| } |
| if (context.LIKE() != null) { |
| return parseLikeExpression(context, canUseFullPath); |
| } |
| throw new UnsupportedOperationException(); |
| } |
| |
| if (context.unaryBeforeIsNullExpression != null) { |
| return parseIsNullExpression(context, canUseFullPath); |
| } |
| |
| if (context.firstExpression != null |
| && context.secondExpression != null |
| && context.thirdExpression != null) { |
| Expression firstExpression = parseExpression(context.firstExpression, canUseFullPath); |
| Expression secondExpression = parseExpression(context.secondExpression, canUseFullPath); |
| Expression thirdExpression = parseExpression(context.thirdExpression, canUseFullPath); |
| |
| if (context.operator_between() != null) { |
| return new BetweenExpression( |
| firstExpression, secondExpression, thirdExpression, context.operator_not() != null); |
| } |
| throw new UnsupportedOperationException(); |
| } |
| |
| if (context.unaryBeforeInExpression != null) { |
| return parseInExpression(context, canUseFullPath); |
| } |
| |
| if (context.scalarFunctionExpression() != null) { |
| return parseScalarFunctionExpression(context.scalarFunctionExpression(), canUseFullPath); |
| } |
| |
| if (context.functionName() != null) { |
| return parseFunctionExpression(context, canUseFullPath); |
| } |
| |
| if (context.fullPathInExpression() != null) { |
| return new TimeSeriesOperand( |
| parseFullPathInExpression(context.fullPathInExpression(), canUseFullPath)); |
| } |
| |
| if (context.time != null) { |
| return new TimestampOperand(); |
| } |
| |
| if (context.constant() != null && !context.constant().isEmpty()) { |
| return parseConstantOperand(context.constant(0)); |
| } |
| |
| if (context.caseWhenThenExpression() != null) { |
| return parseCaseWhenThenExpression(context.caseWhenThenExpression(), canUseFullPath); |
| } |
| |
| throw new UnsupportedOperationException(); |
| } |
| |
| private Expression parseScalarFunctionExpression( |
| IoTDBSqlParser.ScalarFunctionExpressionContext context, boolean canUseFullPath) { |
| if (context.CAST() != null) { |
| return parseCastFunction(context, canUseFullPath); |
| } else if (context.REPLACE() != null) { |
| return parseReplaceFunction(context, canUseFullPath); |
| } else if (context.ROUND() != null) { |
| return parseRoundFunction(context, canUseFullPath); |
| } else if (context.SUBSTRING() != null) { |
| return parseSubStrFunction(context, canUseFullPath); |
| } |
| throw new UnsupportedOperationException(); |
| } |
| |
| private Expression parseCastFunction( |
| IoTDBSqlParser.ScalarFunctionExpressionContext castClause, boolean canUseFullPath) { |
| FunctionExpression functionExpression = new FunctionExpression(CAST_FUNCTION); |
| functionExpression.addExpression(parseExpression(castClause.castInput, canUseFullPath)); |
| functionExpression.addAttribute(CAST_TYPE, parseAttributeValue(castClause.attributeValue())); |
| return functionExpression; |
| } |
| |
| private Expression parseReplaceFunction( |
| IoTDBSqlParser.ScalarFunctionExpressionContext replaceClause, boolean canUseFullPath) { |
| FunctionExpression functionExpression = new FunctionExpression(REPLACE_FUNCTION); |
| functionExpression.addExpression(parseExpression(replaceClause.text, canUseFullPath)); |
| functionExpression.addAttribute(REPLACE_FROM, parseStringLiteral(replaceClause.from.getText())); |
| functionExpression.addAttribute(REPLACE_TO, parseStringLiteral(replaceClause.to.getText())); |
| return functionExpression; |
| } |
| |
| private Expression parseSubStrFunction( |
| IoTDBSqlParser.ScalarFunctionExpressionContext subStrClause, boolean canUseFullPath) { |
| FunctionExpression functionExpression = new FunctionExpression(SUBSTRING_FUNCTION); |
| IoTDBSqlParser.SubStringExpressionContext subStringExpression = |
| subStrClause.subStringExpression(); |
| functionExpression.addExpression(parseExpression(subStringExpression.input, canUseFullPath)); |
| if (subStringExpression.startPosition != null) { |
| functionExpression.addAttribute(SUBSTRING_START, subStringExpression.startPosition.getText()); |
| if (subStringExpression.length != null) { |
| functionExpression.addAttribute(SUBSTRING_LENGTH, subStringExpression.length.getText()); |
| } |
| } |
| if (subStringExpression.from != null) { |
| functionExpression.addAttribute(SUBSTRING_IS_STANDARD, "0"); |
| functionExpression.addAttribute( |
| SUBSTRING_START, parseStringLiteral(subStringExpression.from.getText())); |
| if (subStringExpression.forLength != null) { |
| functionExpression.addAttribute(SUBSTRING_LENGTH, subStringExpression.forLength.getText()); |
| } |
| } |
| return functionExpression; |
| } |
| |
| private Expression parseRoundFunction( |
| IoTDBSqlParser.ScalarFunctionExpressionContext roundClause, boolean canUseFullPath) { |
| FunctionExpression functionExpression = new FunctionExpression(ROUND_FUNCTION); |
| functionExpression.addExpression(parseExpression(roundClause.input, canUseFullPath)); |
| if (roundClause.places != null) { |
| functionExpression.addAttribute(ROUND_PLACES, parseConstant(roundClause.constant())); |
| } |
| return functionExpression; |
| } |
| |
| private CaseWhenThenExpression parseCaseWhenThenExpression( |
| IoTDBSqlParser.CaseWhenThenExpressionContext context, boolean canUseFullPath) { |
| // handle CASE |
| Expression caseExpression = null; |
| boolean simpleCase = false; |
| if (context.caseExpression != null) { |
| caseExpression = parseExpression(context.caseExpression, canUseFullPath); |
| simpleCase = true; |
| } |
| // handle WHEN-THEN |
| List<WhenThenExpression> whenThenList = new ArrayList<>(); |
| if (simpleCase) { |
| for (IoTDBSqlParser.WhenThenExpressionContext whenThenExpressionContext : |
| context.whenThenExpression()) { |
| Expression when = parseExpression(whenThenExpressionContext.whenExpression, canUseFullPath); |
| Expression then = parseExpression(whenThenExpressionContext.thenExpression, canUseFullPath); |
| Expression comparison = new EqualToExpression(caseExpression, when); |
| whenThenList.add(new WhenThenExpression(comparison, then)); |
| } |
| } else { |
| for (IoTDBSqlParser.WhenThenExpressionContext whenThenExpressionContext : |
| context.whenThenExpression()) { |
| whenThenList.add( |
| new WhenThenExpression( |
| parseExpression(whenThenExpressionContext.whenExpression, canUseFullPath), |
| parseExpression(whenThenExpressionContext.thenExpression, canUseFullPath))); |
| } |
| } |
| // handle ELSE |
| Expression elseExpression = new NullOperand(); |
| if (context.elseExpression != null) { |
| elseExpression = parseExpression(context.elseExpression, canUseFullPath); |
| } |
| return new CaseWhenThenExpression(whenThenList, elseExpression); |
| } |
| |
| private Expression parseFunctionExpression( |
| IoTDBSqlParser.ExpressionContext functionClause, boolean canUseFullPath) { |
| FunctionExpression functionExpression = |
| new FunctionExpression(parseIdentifier(functionClause.functionName().getText())); |
| |
| // expressions |
| boolean hasNonPureConstantSubExpression = false; |
| for (IoTDBSqlParser.ExpressionContext expression : functionClause.expression()) { |
| Expression subexpression = parseExpression(expression, canUseFullPath); |
| if (!subexpression.isConstantOperand()) { |
| hasNonPureConstantSubExpression = true; |
| } |
| if (subexpression instanceof EqualToExpression) { |
| Expression subLeftExpression = ((EqualToExpression) subexpression).getLeftExpression(); |
| Expression subRightExpression = ((EqualToExpression) subexpression).getRightExpression(); |
| if (subLeftExpression.isConstantOperand() |
| && (!(subRightExpression.isConstantOperand() |
| && ((ConstantOperand) subRightExpression).getDataType().equals(TSDataType.TEXT)))) { |
| throw new SemanticException("Attributes of functions should be quoted with '' or \"\""); |
| } |
| if (subLeftExpression.isConstantOperand() && subRightExpression.isConstantOperand()) { |
| // parse attribute |
| functionExpression.addAttribute( |
| ((ConstantOperand) subLeftExpression).getValueString(), |
| ((ConstantOperand) subRightExpression).getValueString()); |
| } else { |
| functionExpression.addExpression(subexpression); |
| } |
| } else { |
| functionExpression.addExpression(subexpression); |
| } |
| } |
| |
| // It is not allowed to have function expressions like F(1, 1.0). There should be at least one |
| // non-pure-constant sub-expression, otherwise the timestamp of the row cannot be inferred. |
| if (!hasNonPureConstantSubExpression) { |
| throw new SemanticException( |
| "Invalid function expression, all the arguments are constant operands: " |
| + functionClause.getText()); |
| } |
| |
| // check size of input expressions |
| // type check of input expressions is put in ExpressionTypeAnalyzer |
| if (functionExpression.isBuiltInAggregationFunctionExpression()) { |
| checkAggregationFunctionInput(functionExpression); |
| } else if (functionExpression.isBuiltInScalarFunctionExpression()) { |
| checkBuiltInScalarFunctionInput(functionExpression); |
| } |
| return functionExpression; |
| } |
| |
| private void checkAggregationFunctionInput(FunctionExpression functionExpression) { |
| final String functionName = functionExpression.getFunctionName().toLowerCase(); |
| switch (functionName) { |
| case SqlConstant.MIN_TIME: |
| case SqlConstant.MAX_TIME: |
| case SqlConstant.COUNT: |
| case SqlConstant.COUNT_TIME: |
| case SqlConstant.MIN_VALUE: |
| case SqlConstant.LAST_VALUE: |
| case SqlConstant.FIRST_VALUE: |
| case SqlConstant.MAX_VALUE: |
| case SqlConstant.EXTREME: |
| case SqlConstant.AVG: |
| case SqlConstant.SUM: |
| case SqlConstant.TIME_DURATION: |
| case SqlConstant.MODE: |
| case SqlConstant.STDDEV: |
| case SqlConstant.STDDEV_POP: |
| case SqlConstant.STDDEV_SAMP: |
| case SqlConstant.VARIANCE: |
| case SqlConstant.VAR_POP: |
| case SqlConstant.VAR_SAMP: |
| checkFunctionExpressionInputSize( |
| functionExpression.getExpressionString(), |
| functionExpression.getExpressions().size(), |
| 1); |
| return; |
| case SqlConstant.COUNT_IF: |
| case SqlConstant.MAX_BY: |
| case SqlConstant.MIN_BY: |
| checkFunctionExpressionInputSize( |
| functionExpression.getExpressionString(), |
| functionExpression.getExpressions().size(), |
| 2); |
| return; |
| default: |
| throw new IllegalArgumentException( |
| "Invalid Aggregation function: " + functionExpression.getFunctionName()); |
| } |
| } |
| |
| private void checkBuiltInScalarFunctionInput(FunctionExpression functionExpression) { |
| BuiltInScalarFunctionHelperFactory.createHelper(functionExpression.getFunctionName()) |
| .checkBuiltInScalarFunctionInputSize(functionExpression); |
| } |
| |
| public static void checkFunctionExpressionInputSize( |
| String expressionString, int actual, int... expected) { |
| for (int expect : expected) { |
| if (expect == actual) { |
| return; |
| } |
| } |
| throw new SemanticException( |
| String.format( |
| "Error size of input expressions. expression: %s, actual size: %s, expected size: %s.", |
| expressionString, actual, Arrays.toString(expected))); |
| } |
| |
| private Expression parseRegularExpression(ExpressionContext context, boolean canUseFullPath) { |
| return new RegularExpression( |
| parseExpression(context.unaryBeforeRegularOrLikeExpression, canUseFullPath), |
| parseStringLiteral(context.STRING_LITERAL().getText()), |
| false); |
| } |
| |
| private Expression parseLikeExpression(ExpressionContext context, boolean canUseFullPath) { |
| return new LikeExpression( |
| parseExpression(context.unaryBeforeRegularOrLikeExpression, canUseFullPath), |
| parseStringLiteral(context.STRING_LITERAL().getText()), |
| false); |
| } |
| |
| private Expression parseIsNullExpression(ExpressionContext context, boolean canUseFullPath) { |
| return new IsNullExpression( |
| parseExpression(context.unaryBeforeIsNullExpression, canUseFullPath), |
| context.operator_not() != null); |
| } |
| |
| private Expression parseInExpression(ExpressionContext context, boolean canUseFullPath) { |
| Expression childExpression = parseExpression(context.unaryBeforeInExpression, canUseFullPath); |
| LinkedHashSet<String> values = new LinkedHashSet<>(); |
| for (ConstantContext constantContext : context.constant()) { |
| values.add(parseConstant(constantContext)); |
| } |
| return new InExpression(childExpression, context.operator_not() != null, values); |
| } |
| |
| private String parseConstant(ConstantContext constantContext) { |
| String text = constantContext.getText(); |
| if (constantContext.boolean_literal() != null |
| || constantContext.INTEGER_LITERAL() != null |
| || constantContext.realLiteral() != null) { |
| return text; |
| } else if (constantContext.STRING_LITERAL() != null) { |
| return parseStringLiteral(text); |
| } else if (constantContext.dateExpression() != null) { |
| return String.valueOf(parseDateExpression(constantContext.dateExpression())); |
| } else { |
| throw new IllegalArgumentException("Unsupported constant value: " + text); |
| } |
| } |
| |
| private Expression parseConstantOperand(ConstantContext constantContext) { |
| String text = constantContext.getText(); |
| if (constantContext.boolean_literal() != null) { |
| return new ConstantOperand(TSDataType.BOOLEAN, text); |
| } else if (constantContext.STRING_LITERAL() != null) { |
| return new ConstantOperand(TSDataType.TEXT, parseStringLiteral(text)); |
| } else if (constantContext.INTEGER_LITERAL() != null) { |
| return new ConstantOperand(TSDataType.INT64, text); |
| } else if (constantContext.realLiteral() != null) { |
| return parseRealLiteral(text); |
| } else if (constantContext.dateExpression() != null) { |
| return new ConstantOperand( |
| TSDataType.INT64, String.valueOf(parseDateExpression(constantContext.dateExpression()))); |
| } else { |
| throw new SemanticException("Unsupported constant operand: " + text); |
| } |
| } |
| |
| private Expression parseRealLiteral(String value) { |
| // 3.33 is float by default |
| return new ConstantOperand( |
| CONFIG.getFloatingStringInferType().equals(TSDataType.DOUBLE) |
| ? TSDataType.DOUBLE |
| : TSDataType.FLOAT, |
| value); |
| } |
| |
| /** |
| * parse time expression, which is addition and subtraction expression of duration time, now() or |
| * DataTimeFormat time. |
| * |
| * <p>eg. now() + 1d - 2h |
| */ |
| private Long parseDateExpression(IoTDBSqlParser.DateExpressionContext ctx) { |
| long time; |
| time = parseDateFormat(ctx.getChild(0).getText()); |
| for (int i = 1; i < ctx.getChildCount(); i = i + 2) { |
| if ("+".equals(ctx.getChild(i).getText())) { |
| time += DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText(), false); |
| } else { |
| time -= DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText(), false); |
| } |
| } |
| return time; |
| } |
| |
| private Long parseDateExpression(IoTDBSqlParser.DateExpressionContext ctx, long currentTime) { |
| long time; |
| time = parseDateFormat(ctx.getChild(0).getText(), currentTime); |
| for (int i = 1; i < ctx.getChildCount(); i = i + 2) { |
| if ("+".equals(ctx.getChild(i).getText())) { |
| time += DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText(), false); |
| } else { |
| time -= DateTimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText(), false); |
| } |
| } |
| return time; |
| } |
| |
| private long parseTimeValue(IoTDBSqlParser.TimeValueContext ctx, long currentTime) { |
| if (ctx.INTEGER_LITERAL() != null) { |
| try { |
| if (ctx.MINUS() != null) { |
| return -Long.parseLong(ctx.INTEGER_LITERAL().getText()); |
| } |
| return Long.parseLong(ctx.INTEGER_LITERAL().getText()); |
| } catch (NumberFormatException e) { |
| throw new SemanticException( |
| String.format("Can not parse %s to long value", ctx.INTEGER_LITERAL().getText())); |
| } |
| } else if (ctx.dateExpression() != null) { |
| return parseDateExpression(ctx.dateExpression(), currentTime); |
| } else { |
| return parseDateFormat(ctx.datetimeLiteral().getText(), currentTime); |
| } |
| } |
| |
| /** Utils. */ |
| private void setMap(IoTDBSqlParser.AlterClauseContext ctx, Map<String, String> alterMap) { |
| List<IoTDBSqlParser.AttributePairContext> tagsList = ctx.attributePair(); |
| String key; |
| if (ctx.attributePair(0) != null) { |
| for (IoTDBSqlParser.AttributePairContext attributePair : tagsList) { |
| key = parseAttributeKey(attributePair.attributeKey()); |
| alterMap.computeIfPresent( |
| key, |
| (k, v) -> { |
| throw new SemanticException( |
| String.format("There's duplicate [%s] in tag or attribute clause.", k)); |
| }); |
| alterMap.put(key, parseAttributeValue(attributePair.attributeValue())); |
| } |
| } |
| } |
| |
| private Map<String, String> extractMap( |
| List<IoTDBSqlParser.AttributePairContext> attributePair2, |
| IoTDBSqlParser.AttributePairContext attributePair3) { |
| Map<String, String> tags = new HashMap<>(attributePair2.size()); |
| if (attributePair3 != null) { |
| String key; |
| for (IoTDBSqlParser.AttributePairContext attributePair : attributePair2) { |
| key = parseAttributeKey(attributePair.attributeKey()); |
| tags.computeIfPresent( |
| key, |
| (k, v) -> { |
| throw new SemanticException( |
| String.format("There's duplicate [%s] in tag or attribute clause.", k)); |
| }); |
| tags.put(key, parseAttributeValue(attributePair.attributeValue())); |
| } |
| } |
| return tags; |
| } |
| |
| private String parseAttributeKey(IoTDBSqlParser.AttributeKeyContext ctx) { |
| if (ctx.constant() != null) { |
| return parseStringLiteral(ctx.getText()); |
| } |
| return parseIdentifier(ctx.getText()); |
| } |
| |
| private String parseAttributeValue(IoTDBSqlParser.AttributeValueContext ctx) { |
| if (ctx.constant() != null) { |
| return parseStringLiteral(ctx.getText()); |
| } |
| return parseIdentifier(ctx.getText()); |
| } |
| |
| // Flush |
| |
| @Override |
| public Statement visitFlush(IoTDBSqlParser.FlushContext ctx) { |
| FlushStatement flushStatement = new FlushStatement(StatementType.FLUSH); |
| List<PartialPath> storageGroups = null; |
| if (ctx.boolean_literal() != null) { |
| flushStatement.setSeq(Boolean.parseBoolean(ctx.boolean_literal().getText())); |
| } |
| flushStatement.setOnCluster(ctx.LOCAL() == null); |
| if (ctx.prefixPath(0) != null) { |
| storageGroups = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| storageGroups.add(parsePrefixPath(prefixPathContext)); |
| } |
| } |
| flushStatement.setStorageGroups(storageGroups); |
| return flushStatement; |
| } |
| |
| // Clear Cache |
| |
| @Override |
| public Statement visitClearCache(IoTDBSqlParser.ClearCacheContext ctx) { |
| ClearCacheStatement clearCacheStatement = new ClearCacheStatement(StatementType.CLEAR_CACHE); |
| clearCacheStatement.setOnCluster(ctx.LOCAL() == null); |
| return clearCacheStatement; |
| } |
| |
| // Start Repair Data |
| |
| @Override |
| public Statement visitStartRepairData(IoTDBSqlParser.StartRepairDataContext ctx) { |
| StartRepairDataStatement startRepairDataStatement = |
| new StartRepairDataStatement(StatementType.START_REPAIR_DATA); |
| startRepairDataStatement.setOnCluster(ctx.LOCAL() == null); |
| return startRepairDataStatement; |
| } |
| |
| // Stop Repair Data |
| |
| @Override |
| public Statement visitStopRepairData(IoTDBSqlParser.StopRepairDataContext ctx) { |
| StopRepairDataStatement stopRepairDataStatement = |
| new StopRepairDataStatement(StatementType.STOP_REPAIR_DATA); |
| stopRepairDataStatement.setOnCluster(ctx.LOCAL() == null); |
| return stopRepairDataStatement; |
| } |
| |
| // Load Configuration |
| |
| @Override |
| public Statement visitLoadConfiguration(IoTDBSqlParser.LoadConfigurationContext ctx) { |
| LoadConfigurationStatement loadConfigurationStatement = |
| new LoadConfigurationStatement(StatementType.LOAD_CONFIGURATION); |
| loadConfigurationStatement.setOnCluster(ctx.LOCAL() == null); |
| return loadConfigurationStatement; |
| } |
| |
| // Set System Status |
| |
| @Override |
| public Statement visitSetSystemStatus(IoTDBSqlParser.SetSystemStatusContext ctx) { |
| SetSystemStatusStatement setSystemStatusStatement = new SetSystemStatusStatement(); |
| setSystemStatusStatement.setOnCluster(ctx.LOCAL() == null); |
| if (ctx.RUNNING() != null) { |
| setSystemStatusStatement.setStatus(NodeStatus.Running); |
| } else if (ctx.READONLY() != null) { |
| setSystemStatusStatement.setStatus(NodeStatus.ReadOnly); |
| } else { |
| throw new SemanticException("Unknown system status in set system command."); |
| } |
| return setSystemStatusStatement; |
| } |
| |
| // Kill Query |
| @Override |
| public Statement visitKillQuery(IoTDBSqlParser.KillQueryContext ctx) { |
| if (ctx.queryId != null) { |
| return new KillQueryStatement(parseStringLiteral(ctx.queryId.getText())); |
| } |
| return new KillQueryStatement(); |
| } |
| |
| // show query processlist |
| |
| @Override |
| public Statement visitShowQueries(IoTDBSqlParser.ShowQueriesContext ctx) { |
| ShowQueriesStatement showQueriesStatement = new ShowQueriesStatement(); |
| // parse WHERE |
| if (ctx.whereClause() != null) { |
| showQueriesStatement.setWhereCondition(parseWhereClause(ctx.whereClause())); |
| } |
| |
| // parse ORDER BY |
| if (ctx.orderByClause() != null) { |
| showQueriesStatement.setOrderByComponent( |
| parseOrderByClause( |
| ctx.orderByClause(), |
| ImmutableSet.of( |
| OrderByKey.TIME, |
| OrderByKey.QUERYID, |
| OrderByKey.DATANODEID, |
| OrderByKey.ELAPSEDTIME, |
| OrderByKey.STATEMENT))); |
| } |
| |
| // parse LIMIT & OFFSET |
| if (ctx.rowPaginationClause() != null) { |
| if (ctx.rowPaginationClause().limitClause() != null) { |
| showQueriesStatement.setRowLimit(parseLimitClause(ctx.rowPaginationClause().limitClause())); |
| } |
| if (ctx.rowPaginationClause().offsetClause() != null) { |
| showQueriesStatement.setRowOffset( |
| parseOffsetClause(ctx.rowPaginationClause().offsetClause())); |
| } |
| } |
| |
| return showQueriesStatement; |
| } |
| |
| // show region |
| |
| @Override |
| public Statement visitShowRegions(IoTDBSqlParser.ShowRegionsContext ctx) { |
| ShowRegionStatement showRegionStatement = new ShowRegionStatement(); |
| // TODO: Maybe add a show ConfigNode region in the future |
| if (ctx.DATA() != null) { |
| showRegionStatement.setRegionType(TConsensusGroupType.DataRegion); |
| } else if (ctx.SCHEMA() != null) { |
| showRegionStatement.setRegionType(TConsensusGroupType.SchemaRegion); |
| } else { |
| showRegionStatement.setRegionType(null); |
| } |
| |
| if (ctx.OF() != null) { |
| List<PartialPath> storageGroups = null; |
| if (ctx.prefixPath(0) != null) { |
| storageGroups = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| storageGroups.add(parsePrefixPath(prefixPathContext)); |
| } |
| } |
| showRegionStatement.setStorageGroups(storageGroups); |
| } else { |
| showRegionStatement.setStorageGroups(null); |
| } |
| |
| if (ctx.ON() != null) { |
| List<Integer> nodeIds = new ArrayList<>(); |
| for (TerminalNode nodeid : ctx.INTEGER_LITERAL()) { |
| nodeIds.add(Integer.parseInt(nodeid.getText())); |
| } |
| showRegionStatement.setNodeIds(nodeIds); |
| } else { |
| showRegionStatement.setNodeIds(null); |
| } |
| return showRegionStatement; |
| } |
| |
| // show datanodes |
| |
| @Override |
| public Statement visitShowDataNodes(IoTDBSqlParser.ShowDataNodesContext ctx) { |
| return new ShowDataNodesStatement(); |
| } |
| |
| // show confignodes |
| |
| @Override |
| public Statement visitShowConfigNodes(IoTDBSqlParser.ShowConfigNodesContext ctx) { |
| return new ShowConfigNodesStatement(); |
| } |
| |
| // device template |
| |
| @Override |
| public Statement visitCreateSchemaTemplate(IoTDBSqlParser.CreateSchemaTemplateContext ctx) { |
| String name = parseIdentifier(ctx.templateName.getText()); |
| List<List<String>> measurementsList = new ArrayList<>(); |
| List<List<TSDataType>> dataTypesList = new ArrayList<>(); |
| List<List<TSEncoding>> encodingsList = new ArrayList<>(); |
| List<List<CompressionType>> compressorsList = new ArrayList<>(); |
| |
| if (ctx.ALIGNED() != null) { |
| // aligned |
| List<String> measurements = new ArrayList<>(); |
| List<TSDataType> dataTypes = new ArrayList<>(); |
| List<TSEncoding> encodings = new ArrayList<>(); |
| List<CompressionType> compressors = new ArrayList<>(); |
| for (IoTDBSqlParser.TemplateMeasurementClauseContext templateClauseContext : |
| ctx.templateMeasurementClause()) { |
| measurements.add( |
| parseNodeNameWithoutWildCard(templateClauseContext.nodeNameWithoutWildcard())); |
| parseAttributeClauseForSchemaTemplate( |
| templateClauseContext.attributeClauses(), dataTypes, encodings, compressors); |
| } |
| measurementsList.add(measurements); |
| dataTypesList.add(dataTypes); |
| encodingsList.add(encodings); |
| compressorsList.add(compressors); |
| } else { |
| // non-aligned |
| for (IoTDBSqlParser.TemplateMeasurementClauseContext templateClauseContext : |
| ctx.templateMeasurementClause()) { |
| List<String> measurements = new ArrayList<>(); |
| List<TSDataType> dataTypes = new ArrayList<>(); |
| List<TSEncoding> encodings = new ArrayList<>(); |
| List<CompressionType> compressors = new ArrayList<>(); |
| measurements.add( |
| parseNodeNameWithoutWildCard(templateClauseContext.nodeNameWithoutWildcard())); |
| parseAttributeClauseForSchemaTemplate( |
| templateClauseContext.attributeClauses(), dataTypes, encodings, compressors); |
| measurementsList.add(measurements); |
| dataTypesList.add(dataTypes); |
| encodingsList.add(encodings); |
| compressorsList.add(compressors); |
| } |
| } |
| |
| return new CreateSchemaTemplateStatement( |
| name, |
| measurementsList, |
| dataTypesList, |
| encodingsList, |
| compressorsList, |
| ctx.ALIGNED() != null); |
| } |
| |
| @Override |
| public Statement visitAlterSchemaTemplate(IoTDBSqlParser.AlterSchemaTemplateContext ctx) { |
| String name = parseIdentifier(ctx.templateName.getText()); |
| List<String> measurements = new ArrayList<>(); |
| List<TSDataType> dataTypes = new ArrayList<>(); |
| List<TSEncoding> encodings = new ArrayList<>(); |
| List<CompressionType> compressors = new ArrayList<>(); |
| |
| for (IoTDBSqlParser.TemplateMeasurementClauseContext templateClauseContext : |
| ctx.templateMeasurementClause()) { |
| measurements.add( |
| parseNodeNameWithoutWildCard(templateClauseContext.nodeNameWithoutWildcard())); |
| parseAttributeClauseForSchemaTemplate( |
| templateClauseContext.attributeClauses(), dataTypes, encodings, compressors); |
| } |
| |
| return new AlterSchemaTemplateStatement( |
| name, |
| measurements, |
| dataTypes, |
| encodings, |
| compressors, |
| TemplateAlterOperationType.EXTEND_TEMPLATE); |
| } |
| |
| void parseAttributeClauseForSchemaTemplate( |
| IoTDBSqlParser.AttributeClausesContext ctx, |
| List<TSDataType> dataTypes, |
| List<TSEncoding> encodings, |
| List<CompressionType> compressors) { |
| if (ctx.aliasNodeName() != null) { |
| throw new SemanticException("Device Template: alias is not supported yet."); |
| } |
| |
| TSDataType dataType = parseDataTypeAttribute(ctx); |
| dataTypes.add(dataType); |
| |
| Map<String, String> props = new HashMap<>(); |
| if (ctx.attributePair() != null) { |
| for (int i = 0; i < ctx.attributePair().size(); i++) { |
| props.put( |
| parseAttributeKey(ctx.attributePair(i).attributeKey()).toLowerCase(), |
| parseAttributeValue(ctx.attributePair(i).attributeValue())); |
| } |
| } |
| |
| TSEncoding encoding = IoTDBDescriptor.getInstance().getDefaultEncodingByType(dataType); |
| if (props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase())) { |
| String encodingString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase()).toUpperCase(); |
| try { |
| encoding = TSEncoding.valueOf(encodingString); |
| encodings.add(encoding); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_ENCODING.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("Unsupported encoding: %s", encodingString)); |
| } |
| } else { |
| encodings.add(encoding); |
| } |
| |
| CompressionType compressor = TSFileDescriptor.getInstance().getConfig().getCompressor(); |
| if (props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase())) { |
| String compressorString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase()).toUpperCase(); |
| try { |
| compressor = CompressionType.valueOf(compressorString); |
| compressors.add(compressor); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSOR.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("Unsupported compressor: %s", compressorString)); |
| } |
| } else if (props.containsKey(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase())) { |
| String compressionString = |
| props.get(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase()).toUpperCase(); |
| try { |
| compressor = CompressionType.valueOf(compressionString); |
| compressors.add(compressor); |
| props.remove(IoTDBConstant.COLUMN_TIMESERIES_COMPRESSION.toLowerCase()); |
| } catch (Exception e) { |
| throw new SemanticException( |
| String.format("Unsupported compression: %s", compressionString)); |
| } |
| } else { |
| compressors.add(compressor); |
| } |
| |
| if (props.size() > 0) { |
| throw new SemanticException("Device Template: property is not supported yet."); |
| } |
| |
| if (ctx.tagClause() != null) { |
| throw new SemanticException("Device Template: tag is not supported yet."); |
| } |
| |
| if (ctx.attributeClause() != null) { |
| throw new SemanticException("Device Template: attribute is not supported yet."); |
| } |
| } |
| |
| private TSDataType parseDataTypeAttribute(IoTDBSqlParser.AttributeClausesContext ctx) { |
| TSDataType dataType = null; |
| if (ctx.dataType != null) { |
| if (ctx.attributeKey() != null |
| && !parseAttributeKey(ctx.attributeKey()) |
| .equalsIgnoreCase(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE)) { |
| throw new SemanticException("Expecting datatype"); |
| } |
| String dataTypeString = ctx.dataType.getText().toUpperCase(); |
| try { |
| dataType = TSDataType.valueOf(dataTypeString); |
| } catch (Exception e) { |
| throw new SemanticException(String.format("Unsupported datatype: %s", dataTypeString)); |
| } |
| } |
| return dataType; |
| } |
| |
| @Override |
| public Statement visitShowSchemaTemplates(IoTDBSqlParser.ShowSchemaTemplatesContext ctx) { |
| return new ShowSchemaTemplateStatement(); |
| } |
| |
| @Override |
| public Statement visitShowNodesInSchemaTemplate( |
| IoTDBSqlParser.ShowNodesInSchemaTemplateContext ctx) { |
| String templateName = parseIdentifier(ctx.templateName.getText()); |
| return new ShowNodesInSchemaTemplateStatement(templateName); |
| } |
| |
| @Override |
| public Statement visitSetSchemaTemplate(IoTDBSqlParser.SetSchemaTemplateContext ctx) { |
| String templateName = parseIdentifier(ctx.templateName.getText()); |
| return new SetSchemaTemplateStatement(templateName, parsePrefixPath(ctx.prefixPath())); |
| } |
| |
| @Override |
| public Statement visitShowPathsSetSchemaTemplate( |
| IoTDBSqlParser.ShowPathsSetSchemaTemplateContext ctx) { |
| String templateName = parseIdentifier(ctx.templateName.getText()); |
| return new ShowPathSetTemplateStatement(templateName); |
| } |
| |
| @Override |
| public Statement visitCreateTimeseriesUsingSchemaTemplate( |
| IoTDBSqlParser.CreateTimeseriesUsingSchemaTemplateContext ctx) { |
| ActivateTemplateStatement statement = new ActivateTemplateStatement(); |
| statement.setPath(parsePrefixPath(ctx.prefixPath())); |
| return statement; |
| } |
| |
| @Override |
| public Statement visitShowPathsUsingSchemaTemplate( |
| IoTDBSqlParser.ShowPathsUsingSchemaTemplateContext ctx) { |
| PartialPath pathPattern; |
| if (ctx.prefixPath() == null) { |
| pathPattern = new PartialPath(SqlConstant.getSingleRootArray()); |
| } else { |
| pathPattern = parsePrefixPath(ctx.prefixPath()); |
| } |
| return new ShowPathsUsingTemplateStatement( |
| pathPattern, parseIdentifier(ctx.templateName.getText())); |
| } |
| |
| @Override |
| public Statement visitDropTimeseriesOfSchemaTemplate( |
| IoTDBSqlParser.DropTimeseriesOfSchemaTemplateContext ctx) { |
| DeactivateTemplateStatement statement = new DeactivateTemplateStatement(); |
| if (ctx.templateName != null) { |
| statement.setTemplateName(parseIdentifier(ctx.templateName.getText())); |
| } |
| List<PartialPath> pathPatternList = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| pathPatternList.add(parsePrefixPath(prefixPathContext)); |
| } |
| statement.setPathPatternList(pathPatternList); |
| return statement; |
| } |
| |
| @Override |
| public Statement visitUnsetSchemaTemplate(IoTDBSqlParser.UnsetSchemaTemplateContext ctx) { |
| String templateName = parseIdentifier(ctx.templateName.getText()); |
| PartialPath path = parsePrefixPath(ctx.prefixPath()); |
| return new UnsetSchemaTemplateStatement(templateName, path); |
| } |
| |
| @Override |
| public Statement visitDropSchemaTemplate(IoTDBSqlParser.DropSchemaTemplateContext ctx) { |
| return new DropSchemaTemplateStatement(parseIdentifier(ctx.templateName.getText())); |
| } |
| |
| public Map<String, String> parseSyncAttributeClauses( |
| IoTDBSqlParser.SyncAttributeClausesContext ctx) { |
| |
| Map<String, String> attributes = new HashMap<>(); |
| |
| List<IoTDBSqlParser.AttributePairContext> attributePairs = ctx.attributePair(); |
| if (ctx.attributePair(0) != null) { |
| for (IoTDBSqlParser.AttributePairContext attributePair : attributePairs) { |
| attributes.put( |
| parseAttributeKey(attributePair.attributeKey()).toLowerCase(), |
| parseAttributeValue(attributePair.attributeValue()).toLowerCase()); |
| } |
| } |
| |
| return attributes; |
| } |
| |
| // PIPE |
| |
| @Override |
| public Statement visitCreatePipe(IoTDBSqlParser.CreatePipeContext ctx) { |
| final CreatePipeStatement createPipeStatement = |
| new CreatePipeStatement(StatementType.CREATE_PIPE); |
| |
| if (ctx.pipeName != null) { |
| createPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText())); |
| } else { |
| throw new SemanticException( |
| "Not support for this sql in CREATE PIPE, please enter pipe name."); |
| } |
| if (ctx.extractorAttributesClause() != null) { |
| createPipeStatement.setExtractorAttributes( |
| parseExtractorAttributesClause( |
| ctx.extractorAttributesClause().extractorAttributeClause())); |
| } else { |
| createPipeStatement.setExtractorAttributes(new HashMap<>()); |
| } |
| if (ctx.processorAttributesClause() != null) { |
| createPipeStatement.setProcessorAttributes( |
| parseProcessorAttributesClause( |
| ctx.processorAttributesClause().processorAttributeClause())); |
| } else { |
| createPipeStatement.setProcessorAttributes(new HashMap<>()); |
| } |
| createPipeStatement.setConnectorAttributes( |
| parseConnectorAttributesClause(ctx.connectorAttributesClause().connectorAttributeClause())); |
| return createPipeStatement; |
| } |
| |
| @Override |
| public Statement visitAlterPipe(IoTDBSqlParser.AlterPipeContext ctx) { |
| final AlterPipeStatement alterPipeStatement = new AlterPipeStatement(StatementType.ALTER_PIPE); |
| |
| if (ctx.pipeName != null) { |
| alterPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText())); |
| } else { |
| throw new SemanticException( |
| "Not support for this sql in ALTER PIPE, please enter pipe name."); |
| } |
| if (ctx.alterProcessorAttributesClause() != null) { |
| alterPipeStatement.setProcessorAttributes( |
| parseProcessorAttributesClause( |
| ctx.alterProcessorAttributesClause().processorAttributeClause())); |
| alterPipeStatement.setReplaceAllProcessorAttributes( |
| Objects.nonNull(ctx.alterProcessorAttributesClause().REPLACE())); |
| } else { |
| alterPipeStatement.setProcessorAttributes(new HashMap<>()); |
| alterPipeStatement.setReplaceAllProcessorAttributes(false); |
| } |
| if (ctx.alterConnectorAttributesClause() != null) { |
| alterPipeStatement.setConnectorAttributes( |
| parseConnectorAttributesClause( |
| ctx.alterConnectorAttributesClause().connectorAttributeClause())); |
| alterPipeStatement.setReplaceAllConnectorAttributes( |
| Objects.nonNull(ctx.alterConnectorAttributesClause().REPLACE())); |
| } else { |
| alterPipeStatement.setConnectorAttributes(new HashMap<>()); |
| alterPipeStatement.setReplaceAllConnectorAttributes(false); |
| } |
| return alterPipeStatement; |
| } |
| |
| private Map<String, String> parseExtractorAttributesClause( |
| List<ExtractorAttributeClauseContext> contexts) { |
| final Map<String, String> collectorMap = new HashMap<>(); |
| for (IoTDBSqlParser.ExtractorAttributeClauseContext context : contexts) { |
| collectorMap.put( |
| parseStringLiteral(context.extractorKey.getText()), |
| parseStringLiteral(context.extractorValue.getText())); |
| } |
| return collectorMap; |
| } |
| |
| private Map<String, String> parseProcessorAttributesClause( |
| List<ProcessorAttributeClauseContext> contexts) { |
| final Map<String, String> processorMap = new HashMap<>(); |
| for (IoTDBSqlParser.ProcessorAttributeClauseContext context : contexts) { |
| processorMap.put( |
| parseStringLiteral(context.processorKey.getText()), |
| parseStringLiteral(context.processorValue.getText())); |
| } |
| return processorMap; |
| } |
| |
| private Map<String, String> parseConnectorAttributesClause( |
| List<ConnectorAttributeClauseContext> contexts) { |
| final Map<String, String> connectorMap = new HashMap<>(); |
| for (IoTDBSqlParser.ConnectorAttributeClauseContext context : contexts) { |
| connectorMap.put( |
| parseStringLiteral(context.connectorKey.getText()), |
| parseStringLiteral(context.connectorValue.getText())); |
| } |
| return connectorMap; |
| } |
| |
| @Override |
| public Statement visitDropPipe(IoTDBSqlParser.DropPipeContext ctx) { |
| final DropPipeStatement dropPipeStatement = new DropPipeStatement(StatementType.DROP_PIPE); |
| |
| if (ctx.pipeName != null) { |
| dropPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText())); |
| } else { |
| throw new SemanticException("Not support for this sql in DROP PIPE, please enter pipename."); |
| } |
| |
| return dropPipeStatement; |
| } |
| |
| @Override |
| public Statement visitStartPipe(IoTDBSqlParser.StartPipeContext ctx) { |
| final StartPipeStatement startPipeStatement = new StartPipeStatement(StatementType.START_PIPE); |
| |
| if (ctx.pipeName != null) { |
| startPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText())); |
| } else { |
| throw new SemanticException("Not support for this sql in START PIPE, please enter pipename."); |
| } |
| |
| return startPipeStatement; |
| } |
| |
| @Override |
| public Statement visitStopPipe(IoTDBSqlParser.StopPipeContext ctx) { |
| final StopPipeStatement stopPipeStatement = new StopPipeStatement(StatementType.STOP_PIPE); |
| |
| if (ctx.pipeName != null) { |
| stopPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText())); |
| } else { |
| throw new SemanticException("Not support for this sql in STOP PIPE, please enter pipename."); |
| } |
| |
| return stopPipeStatement; |
| } |
| |
| @Override |
| public Statement visitShowPipes(IoTDBSqlParser.ShowPipesContext ctx) { |
| final ShowPipesStatement showPipesStatement = new ShowPipesStatement(); |
| |
| if (ctx.pipeName != null) { |
| showPipesStatement.setPipeName(parseIdentifier(ctx.pipeName.getText())); |
| } |
| showPipesStatement.setWhereClause(ctx.CONNECTOR() != null); |
| |
| return showPipesStatement; |
| } |
| |
| @Override |
| public Statement visitCreateTopic(IoTDBSqlParser.CreateTopicContext ctx) { |
| final CreateTopicStatement createTopicStatement = new CreateTopicStatement(); |
| |
| if (ctx.topicName != null) { |
| createTopicStatement.setTopicName(parseIdentifier(ctx.topicName.getText())); |
| } else { |
| throw new SemanticException( |
| "Not support for this sql in CREATE TOPIC, please enter topicName."); |
| } |
| |
| if (ctx.topicAttributesClause() != null) { |
| createTopicStatement.setTopicAttributes( |
| parseTopicAttributesClause(ctx.topicAttributesClause().topicAttributeClause())); |
| } else { |
| createTopicStatement.setTopicAttributes(new HashMap<>()); |
| } |
| |
| return createTopicStatement; |
| } |
| |
| private Map<String, String> parseTopicAttributesClause( |
| List<IoTDBSqlParser.TopicAttributeClauseContext> contexts) { |
| final Map<String, String> collectorMap = new HashMap<>(); |
| for (IoTDBSqlParser.TopicAttributeClauseContext context : contexts) { |
| collectorMap.put( |
| parseStringLiteral(context.topicKey.getText()), |
| parseStringLiteral(context.topicValue.getText())); |
| } |
| return collectorMap; |
| } |
| |
| @Override |
| public Statement visitDropTopic(IoTDBSqlParser.DropTopicContext ctx) { |
| final DropTopicStatement dropTopicStatement = new DropTopicStatement(); |
| |
| if (ctx.topicName != null) { |
| dropTopicStatement.setTopicName(parseIdentifier(ctx.topicName.getText())); |
| } else { |
| throw new SemanticException( |
| "Not support for this sql in DROP TOPIC, please enter topicName."); |
| } |
| |
| return dropTopicStatement; |
| } |
| |
| @Override |
| public Statement visitShowTopics(IoTDBSqlParser.ShowTopicsContext ctx) { |
| final ShowTopicsStatement showTopicsStatement = new ShowTopicsStatement(); |
| |
| if (ctx.topicName != null) { |
| showTopicsStatement.setTopicName(parseIdentifier(ctx.topicName.getText())); |
| } |
| |
| return showTopicsStatement; |
| } |
| |
| @Override |
| public Statement visitShowSubscriptions(IoTDBSqlParser.ShowSubscriptionsContext ctx) { |
| final ShowSubscriptionsStatement showSubscriptionsStatement = new ShowSubscriptionsStatement(); |
| |
| if (ctx.topicName != null) { |
| showSubscriptionsStatement.setTopicName(parseIdentifier(ctx.topicName.getText())); |
| } |
| |
| return showSubscriptionsStatement; |
| } |
| |
| @Override |
| public Statement visitGetRegionId(IoTDBSqlParser.GetRegionIdContext ctx) { |
| TConsensusGroupType type = |
| ctx.DATA() == null ? TConsensusGroupType.SchemaRegion : TConsensusGroupType.DataRegion; |
| GetRegionIdStatement getRegionIdStatement = new GetRegionIdStatement(type); |
| if (ctx.database != null) { |
| getRegionIdStatement.setDatabase(ctx.database.getText()); |
| } else { |
| getRegionIdStatement.setDevice(ctx.device.getText()); |
| } |
| getRegionIdStatement.setStartTimeStamp(-1L); |
| getRegionIdStatement.setEndTimeStamp(Long.MAX_VALUE); |
| |
| if (ctx.timeRangeExpression != null) { |
| Expression timeRangeExpression = parseExpression(ctx.timeRangeExpression, true); |
| getRegionIdStatement = parseTimeRangeExpression(timeRangeExpression, getRegionIdStatement); |
| } |
| |
| return getRegionIdStatement; |
| } |
| |
| public GetRegionIdStatement parseTimeRangeExpression( |
| Expression timeRangeExpression, GetRegionIdStatement getRegionIdStatement) { |
| List<Expression> result = timeRangeExpression.getExpressions(); |
| if (timeRangeExpression.getExpressionType() == ExpressionType.LOGIC_AND) { |
| getRegionIdStatement = parseTimeRangeExpression(result.get(0), getRegionIdStatement); |
| getRegionIdStatement = parseTimeRangeExpression(result.get(1), getRegionIdStatement); |
| } else if (result.get(0).getExpressionType() == ExpressionType.TIMESTAMP |
| && result.get(1) instanceof ConstantOperand |
| && ((ConstantOperand) result.get(1)).getDataType() == TSDataType.INT64) { |
| ExpressionType tmpType = timeRangeExpression.getExpressionType(); |
| long timestamp = Long.parseLong(((ConstantOperand) result.get(1)).getValueString()); |
| switch (tmpType) { |
| case EQUAL_TO: |
| getRegionIdStatement.setStartTimeStamp( |
| Math.max(getRegionIdStatement.getStartTimeStamp(), timestamp)); |
| getRegionIdStatement.setEndTimeStamp( |
| Math.min(getRegionIdStatement.getEndTimeStamp(), timestamp)); |
| break; |
| case GREATER_EQUAL: |
| getRegionIdStatement.setStartTimeStamp( |
| Math.max(getRegionIdStatement.getStartTimeStamp(), timestamp)); |
| break; |
| case GREATER_THAN: |
| getRegionIdStatement.setStartTimeStamp( |
| Math.max(getRegionIdStatement.getStartTimeStamp(), timestamp + 1)); |
| break; |
| case LESS_EQUAL: |
| getRegionIdStatement.setEndTimeStamp( |
| Math.min(getRegionIdStatement.getEndTimeStamp(), timestamp)); |
| break; |
| case LESS_THAN: |
| getRegionIdStatement.setEndTimeStamp( |
| Math.min(getRegionIdStatement.getEndTimeStamp(), timestamp - 1)); |
| break; |
| default: |
| throw new UnsupportedOperationException(); |
| } |
| } else { |
| throw new SemanticException("Get region id statement‘ expression must be a time expression"); |
| } |
| return getRegionIdStatement; |
| } |
| |
| @Override |
| public Statement visitGetSeriesSlotList(IoTDBSqlParser.GetSeriesSlotListContext ctx) { |
| TConsensusGroupType type = |
| ctx.DATA() == null ? TConsensusGroupType.SchemaRegion : TConsensusGroupType.DataRegion; |
| return new GetSeriesSlotListStatement(ctx.database.getText(), type); |
| } |
| |
| @Override |
| public Statement visitGetTimeSlotList(IoTDBSqlParser.GetTimeSlotListContext ctx) { |
| GetTimeSlotListStatement getTimeSlotListStatement = new GetTimeSlotListStatement(); |
| if (ctx.database != null) { |
| getTimeSlotListStatement.setDatabase(ctx.database.getText()); |
| } else if (ctx.device != null) { |
| getTimeSlotListStatement.setDevice(ctx.device.getText()); |
| } else if (ctx.regionId != null) { |
| getTimeSlotListStatement.setRegionId(Integer.parseInt(ctx.regionId.getText())); |
| } |
| if (ctx.startTime != null) { |
| long timestamp = parseTimeValue(ctx.startTime, CommonDateTimeUtils.currentTime()); |
| getTimeSlotListStatement.setStartTime(timestamp); |
| } |
| if (ctx.endTime != null) { |
| long timestamp = parseTimeValue(ctx.endTime, CommonDateTimeUtils.currentTime()); |
| getTimeSlotListStatement.setEndTime(timestamp); |
| } |
| return getTimeSlotListStatement; |
| } |
| |
| @Override |
| public Statement visitCountTimeSlotList(IoTDBSqlParser.CountTimeSlotListContext ctx) { |
| CountTimeSlotListStatement countTimeSlotListStatement = new CountTimeSlotListStatement(); |
| if (ctx.database != null) { |
| countTimeSlotListStatement.setDatabase(ctx.database.getText()); |
| } else if (ctx.device != null) { |
| countTimeSlotListStatement.setDevice(ctx.device.getText()); |
| } else if (ctx.regionId != null) { |
| countTimeSlotListStatement.setRegionId(Integer.parseInt(ctx.regionId.getText())); |
| } |
| if (ctx.startTime != null) { |
| countTimeSlotListStatement.setStartTime(Long.parseLong(ctx.startTime.getText())); |
| } |
| if (ctx.endTime != null) { |
| countTimeSlotListStatement.setEndTime(Long.parseLong(ctx.endTime.getText())); |
| } |
| return countTimeSlotListStatement; |
| } |
| |
| @Override |
| public Statement visitMigrateRegion(IoTDBSqlParser.MigrateRegionContext ctx) { |
| return new MigrateRegionStatement( |
| Integer.parseInt(ctx.regionId.getText()), |
| Integer.parseInt(ctx.fromId.getText()), |
| Integer.parseInt(ctx.toId.getText())); |
| } |
| |
| // Quota |
| @Override |
| public Statement visitSetSpaceQuota(IoTDBSqlParser.SetSpaceQuotaContext ctx) { |
| if (!IoTDBDescriptor.getInstance().getConfig().isQuotaEnable()) { |
| throw new SemanticException(LIMIT_CONFIGURATION_ENABLED_ERROR_MSG); |
| } |
| SetSpaceQuotaStatement setSpaceQuotaStatement = new SetSpaceQuotaStatement(); |
| List<IoTDBSqlParser.PrefixPathContext> prefixPathContexts = ctx.prefixPath(); |
| List<String> paths = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : prefixPathContexts) { |
| paths.add(parsePrefixPath(prefixPathContext).getFullPath()); |
| } |
| setSpaceQuotaStatement.setPrefixPathList(paths); |
| |
| Map<String, String> quotas = new HashMap<>(); |
| for (IoTDBSqlParser.AttributePairContext attributePair : ctx.attributePair()) { |
| quotas.put( |
| parseAttributeKey(attributePair.attributeKey()), |
| parseAttributeValue(attributePair.attributeValue())); |
| } |
| |
| quotas |
| .keySet() |
| .forEach( |
| quotaType -> { |
| switch (quotaType) { |
| case IoTDBConstant.COLUMN_DEVICES: |
| break; |
| case IoTDBConstant.COLUMN_TIMESERIES: |
| break; |
| case IoTDBConstant.SPACE_QUOTA_DISK: |
| break; |
| default: |
| throw new SemanticException("Wrong space quota type: " + quotaType); |
| } |
| }); |
| |
| if (quotas.containsKey(IoTDBConstant.COLUMN_DEVICES)) { |
| if (quotas.get(IoTDBConstant.COLUMN_DEVICES).equals(IoTDBConstant.QUOTA_UNLIMITED)) { |
| setSpaceQuotaStatement.setDeviceNum(IoTDBConstant.UNLIMITED_VALUE); |
| } else if (Long.parseLong(quotas.get(IoTDBConstant.COLUMN_DEVICES)) <= 0) { |
| throw new SemanticException("Please set the number of devices greater than 0"); |
| } else { |
| setSpaceQuotaStatement.setDeviceNum( |
| Long.parseLong(quotas.get(IoTDBConstant.COLUMN_DEVICES))); |
| } |
| } |
| if (quotas.containsKey(IoTDBConstant.COLUMN_TIMESERIES)) { |
| if (quotas.get(IoTDBConstant.COLUMN_TIMESERIES).equals(IoTDBConstant.QUOTA_UNLIMITED)) { |
| setSpaceQuotaStatement.setTimeSeriesNum(IoTDBConstant.UNLIMITED_VALUE); |
| } else if (Long.parseLong(quotas.get(IoTDBConstant.COLUMN_TIMESERIES)) <= 0) { |
| throw new SemanticException("Please set the number of timeseries greater than 0"); |
| } else { |
| setSpaceQuotaStatement.setTimeSeriesNum( |
| Long.parseLong(quotas.get(IoTDBConstant.COLUMN_TIMESERIES))); |
| } |
| } |
| if (quotas.containsKey(IoTDBConstant.SPACE_QUOTA_DISK)) { |
| if (quotas.get(IoTDBConstant.SPACE_QUOTA_DISK).equals(IoTDBConstant.QUOTA_UNLIMITED)) { |
| setSpaceQuotaStatement.setDiskSize(IoTDBConstant.UNLIMITED_VALUE); |
| } else { |
| setSpaceQuotaStatement.setDiskSize( |
| parseSpaceQuotaSizeUnit(quotas.get(IoTDBConstant.SPACE_QUOTA_DISK))); |
| } |
| } |
| return setSpaceQuotaStatement; |
| } |
| |
| @Override |
| public Statement visitSetThrottleQuota(IoTDBSqlParser.SetThrottleQuotaContext ctx) { |
| if (!IoTDBDescriptor.getInstance().getConfig().isQuotaEnable()) { |
| throw new SemanticException(LIMIT_CONFIGURATION_ENABLED_ERROR_MSG); |
| } |
| if (parseIdentifier(ctx.userName.getText()).equals(IoTDBConstant.PATH_ROOT)) { |
| throw new SemanticException("Cannot set throttle quota for user root."); |
| } |
| SetThrottleQuotaStatement setThrottleQuotaStatement = new SetThrottleQuotaStatement(); |
| setThrottleQuotaStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| Map<String, String> quotas = new HashMap<>(); |
| Map<ThrottleType, TTimedQuota> throttleLimit = new HashMap<>(); |
| for (IoTDBSqlParser.AttributePairContext attributePair : ctx.attributePair()) { |
| quotas.put( |
| parseAttributeKey(attributePair.attributeKey()), |
| parseAttributeValue(attributePair.attributeValue())); |
| } |
| if (quotas.containsKey(IoTDBConstant.REQUEST_NUM_PER_UNIT_TIME)) { |
| TTimedQuota timedQuota; |
| String request = quotas.get(IoTDBConstant.REQUEST_NUM_PER_UNIT_TIME); |
| if (request.equals(IoTDBConstant.QUOTA_UNLIMITED)) { |
| timedQuota = new TTimedQuota(IoTDBConstant.SEC, Long.MAX_VALUE); |
| } else { |
| String[] split = request.toLowerCase().split(IoTDBConstant.REQ_SPLIT_UNIT); |
| if (Long.parseLong(split[0]) < 0) { |
| throw new SemanticException("Please set the number of requests greater than 0"); |
| } |
| timedQuota = |
| new TTimedQuota(parseThrottleQuotaTimeUnit(split[1]), Long.parseLong(split[0])); |
| } |
| if (quotas.get(IoTDBConstant.REQUEST_TYPE) == null) { |
| throttleLimit.put(ThrottleType.REQUEST_NUMBER, timedQuota); |
| } else { |
| switch (quotas.get(IoTDBConstant.REQUEST_TYPE)) { |
| case IoTDBConstant.REQUEST_TYPE_READ: |
| throttleLimit.put(ThrottleType.READ_NUMBER, timedQuota); |
| break; |
| case IoTDBConstant.REQUEST_TYPE_WRITE: |
| throttleLimit.put(ThrottleType.WRITE_NUMBER, timedQuota); |
| break; |
| default: |
| throw new SemanticException( |
| "Please set the correct request type: " + quotas.get(IoTDBConstant.REQUEST_TYPE)); |
| } |
| } |
| } |
| |
| if (quotas.containsKey(IoTDBConstant.REQUEST_SIZE_PER_UNIT_TIME)) { |
| TTimedQuota timedQuota; |
| String size = quotas.get(IoTDBConstant.REQUEST_SIZE_PER_UNIT_TIME); |
| if (size.equals(IoTDBConstant.QUOTA_UNLIMITED)) { |
| timedQuota = new TTimedQuota(IoTDBConstant.SEC, Long.MAX_VALUE); |
| } else { |
| String[] split = size.toLowerCase().split("/"); |
| timedQuota = |
| new TTimedQuota( |
| parseThrottleQuotaTimeUnit(split[1]), parseThrottleQuotaSizeUnit(split[0])); |
| } |
| if (quotas.get(IoTDBConstant.REQUEST_TYPE) == null) { |
| throttleLimit.put(ThrottleType.REQUEST_SIZE, timedQuota); |
| } else { |
| switch (quotas.get(IoTDBConstant.REQUEST_TYPE)) { |
| case IoTDBConstant.REQUEST_TYPE_READ: |
| throttleLimit.put(ThrottleType.READ_SIZE, timedQuota); |
| break; |
| case IoTDBConstant.REQUEST_TYPE_WRITE: |
| throttleLimit.put(ThrottleType.WRITE_SIZE, timedQuota); |
| break; |
| default: |
| throw new SemanticException( |
| "Please set the correct request type: " + quotas.get(IoTDBConstant.REQUEST_TYPE)); |
| } |
| } |
| } |
| |
| if (quotas.containsKey(IoTDBConstant.MEMORY_SIZE_PER_READ)) { |
| String mem = quotas.get(IoTDBConstant.MEMORY_SIZE_PER_READ); |
| if (mem.equals(IoTDBConstant.QUOTA_UNLIMITED)) { |
| setThrottleQuotaStatement.setMemLimit(IoTDBConstant.UNLIMITED_VALUE); |
| } else { |
| setThrottleQuotaStatement.setMemLimit(parseThrottleQuotaSizeUnit(mem)); |
| } |
| } |
| |
| if (quotas.containsKey(IoTDBConstant.CPU_NUMBER_PER_READ)) { |
| String cpuLimit = quotas.get(IoTDBConstant.CPU_NUMBER_PER_READ); |
| if (cpuLimit.contains(IoTDBConstant.QUOTA_UNLIMITED)) { |
| setThrottleQuotaStatement.setCpuLimit(IoTDBConstant.UNLIMITED_VALUE); |
| } else { |
| int cpuNum = Integer.parseInt(cpuLimit); |
| if (cpuNum <= 0) { |
| throw new SemanticException("Please set the number of cpu greater than 0"); |
| } |
| setThrottleQuotaStatement.setCpuLimit(cpuNum); |
| } |
| } |
| setThrottleQuotaStatement.setThrottleLimit(throttleLimit); |
| return setThrottleQuotaStatement; |
| } |
| |
| @Override |
| public Statement visitShowThrottleQuota(IoTDBSqlParser.ShowThrottleQuotaContext ctx) { |
| if (!IoTDBDescriptor.getInstance().getConfig().isQuotaEnable()) { |
| throw new SemanticException(LIMIT_CONFIGURATION_ENABLED_ERROR_MSG); |
| } |
| ShowThrottleQuotaStatement showThrottleQuotaStatement = new ShowThrottleQuotaStatement(); |
| if (ctx.userName != null) { |
| showThrottleQuotaStatement.setUserName(parseIdentifier(ctx.userName.getText())); |
| } |
| return showThrottleQuotaStatement; |
| } |
| |
| private long parseThrottleQuotaTimeUnit(String timeUnit) { |
| switch (timeUnit.toLowerCase()) { |
| case IoTDBConstant.SEC_UNIT: |
| return IoTDBConstant.SEC; |
| case IoTDBConstant.MIN_UNIT: |
| return IoTDBConstant.MIN; |
| case IoTDBConstant.HOUR_UNIT: |
| return IoTDBConstant.HOUR; |
| case IoTDBConstant.DAY_UNIT: |
| return IoTDBConstant.DAY; |
| default: |
| throw new SemanticException( |
| "When setting the request, the unit is incorrect. Please use 'sec', 'min', 'hour', 'day' as the unit"); |
| } |
| } |
| |
| private long parseThrottleQuotaSizeUnit(String data) { |
| String unit = data.substring(data.length() - 1); |
| long size = Long.parseLong(data.substring(0, data.length() - 1)); |
| if (size <= 0) { |
| throw new SemanticException("Please set the size greater than 0"); |
| } |
| switch (unit.toUpperCase()) { |
| case IoTDBConstant.B_UNIT: |
| return size; |
| case IoTDBConstant.KB_UNIT: |
| return size * IoTDBConstant.KB; |
| case IoTDBConstant.MB_UNIT: |
| return size * IoTDBConstant.MB; |
| case IoTDBConstant.GB_UNIT: |
| return size * IoTDBConstant.GB; |
| case IoTDBConstant.TB_UNIT: |
| return size * IoTDBConstant.TB; |
| case IoTDBConstant.PB_UNIT: |
| return size * IoTDBConstant.PB; |
| default: |
| throw new SemanticException( |
| "When setting the size/time, the unit is incorrect. Please use 'B', 'K', 'M', 'G', 'P', 'T' as the unit"); |
| } |
| } |
| |
| private long parseSpaceQuotaSizeUnit(String data) { |
| String unit = data.substring(data.length() - 1); |
| long disk = Long.parseLong(data.substring(0, data.length() - 1)); |
| if (disk <= 0) { |
| throw new SemanticException("Please set the disk size greater than 0"); |
| } |
| switch (unit.toUpperCase()) { |
| case IoTDBConstant.MB_UNIT: |
| return disk; |
| case IoTDBConstant.GB_UNIT: |
| return disk * IoTDBConstant.KB; |
| case IoTDBConstant.TB_UNIT: |
| return disk * IoTDBConstant.MB; |
| case IoTDBConstant.PB_UNIT: |
| return disk * IoTDBConstant.GB; |
| default: |
| throw new SemanticException( |
| "When setting the disk size, the unit is incorrect. Please use 'M', 'G', 'P', 'T' as the unit"); |
| } |
| } |
| |
| @Override |
| public Statement visitShowSpaceQuota(IoTDBSqlParser.ShowSpaceQuotaContext ctx) { |
| if (!IoTDBDescriptor.getInstance().getConfig().isQuotaEnable()) { |
| throw new SemanticException(LIMIT_CONFIGURATION_ENABLED_ERROR_MSG); |
| } |
| ShowSpaceQuotaStatement showSpaceQuotaStatement = new ShowSpaceQuotaStatement(); |
| if (ctx.prefixPath() != null) { |
| List<PartialPath> databases = new ArrayList<>(); |
| for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { |
| databases.add(parsePrefixPath(prefixPathContext)); |
| } |
| showSpaceQuotaStatement.setDatabases(databases); |
| } else { |
| showSpaceQuotaStatement.setDatabases(null); |
| } |
| return showSpaceQuotaStatement; |
| } |
| |
| @Override |
| public Statement visitShowCurrentTimestamp(IoTDBSqlParser.ShowCurrentTimestampContext ctx) { |
| return new ShowCurrentTimestampStatement(); |
| } |
| } |