blob: 7428a4050064ee28f5447a4a476a576d65c05e5a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.iotdb.db.mpp.plan.parser;
import org.apache.iotdb.common.rpc.thrift.TConsensusGroupType;
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.exception.IllegalPathException;
import org.apache.iotdb.commons.path.PartialPath;
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.SQLParserException;
import org.apache.iotdb.db.exception.sql.SemanticException;
import org.apache.iotdb.db.mpp.common.filter.BasicFunctionFilter;
import org.apache.iotdb.db.mpp.common.filter.QueryFilter;
import org.apache.iotdb.db.mpp.plan.analyze.ExpressionAnalyzer;
import org.apache.iotdb.db.mpp.plan.constant.StatementType;
import org.apache.iotdb.db.mpp.plan.expression.Expression;
import org.apache.iotdb.db.mpp.plan.expression.ExpressionType;
import org.apache.iotdb.db.mpp.plan.expression.binary.AdditionExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.BinaryExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.CompareBinaryExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.DivisionExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.EqualToExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.GreaterEqualExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.GreaterThanExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.LessEqualExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.LessThanExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.LogicAndExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.LogicOrExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.ModuloExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.MultiplicationExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.NonEqualExpression;
import org.apache.iotdb.db.mpp.plan.expression.binary.SubtractionExpression;
import org.apache.iotdb.db.mpp.plan.expression.leaf.ConstantOperand;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimestampOperand;
import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
import org.apache.iotdb.db.mpp.plan.expression.ternary.BetweenExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.InExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.IsNullExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.LikeExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.LogicNotExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.NegationExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.RegularExpression;
import org.apache.iotdb.db.mpp.plan.statement.Statement;
import org.apache.iotdb.db.mpp.plan.statement.component.FillComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.FillPolicy;
import org.apache.iotdb.db.mpp.plan.statement.component.FromComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.GroupByLevelComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.HavingCondition;
import org.apache.iotdb.db.mpp.plan.statement.component.OrderByComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.Ordering;
import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn;
import org.apache.iotdb.db.mpp.plan.statement.component.ResultSetFormat;
import org.apache.iotdb.db.mpp.plan.statement.component.SelectComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.SortItem;
import org.apache.iotdb.db.mpp.plan.statement.component.SortKey;
import org.apache.iotdb.db.mpp.plan.statement.component.WhereCondition;
import org.apache.iotdb.db.mpp.plan.statement.crud.DeleteDataStatement;
import org.apache.iotdb.db.mpp.plan.statement.crud.InsertStatement;
import org.apache.iotdb.db.mpp.plan.statement.crud.LoadTsFileStatement;
import org.apache.iotdb.db.mpp.plan.statement.crud.QueryStatement;
import org.apache.iotdb.db.mpp.plan.statement.literal.BooleanLiteral;
import org.apache.iotdb.db.mpp.plan.statement.literal.DoubleLiteral;
import org.apache.iotdb.db.mpp.plan.statement.literal.Literal;
import org.apache.iotdb.db.mpp.plan.statement.literal.LongLiteral;
import org.apache.iotdb.db.mpp.plan.statement.literal.StringLiteral;
import org.apache.iotdb.db.mpp.plan.statement.metadata.AlterTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CountDevicesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CountLevelTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CountNodesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CountStorageGroupStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CountTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateAlignedTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateFunctionStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.CreateTriggerStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteStorageGroupStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.DeleteTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.DropFunctionStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.DropTriggerStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.SetStorageGroupStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.SetTTLStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildNodesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowChildPathsStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowClusterStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowConfigNodesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDataNodesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowDevicesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowFunctionsStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowRegionStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowStorageGroupStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTTLStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTimeSeriesStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.ShowTriggersStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.UnSetTTLStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.ActivateTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.CreateSchemaTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.SetSchemaTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowNodesInSchemaTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowPathSetTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowPathsUsingTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowSchemaTemplateStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.AuthorStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.ClearCacheStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.ExplainStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.FlushStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.LoadConfigurationStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.MergeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.SetSystemStatusStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.ShowVersionStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.CreatePipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.DropPipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.ShowPipeSinkStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.ShowPipeSinkTypeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.ShowPipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.StartPipeStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.StopPipeStatement;
import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.db.qp.logical.sys.AuthorOperator;
import org.apache.iotdb.db.qp.sql.IoTDBSqlParser;
import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.ConstantContext;
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.CountStorageGroupContext;
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.ShowFunctionsContext;
import org.apache.iotdb.db.qp.sql.IoTDBSqlParser.UriContext;
import org.apache.iotdb.db.qp.sql.IoTDBSqlParserBaseVisitor;
import org.apache.iotdb.db.qp.utils.DatetimeUtils;
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.Pair;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.apache.iotdb.db.metadata.MetadataConstant.ALL_RESULT_NODES;
/** 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.";
/** For create-cq clause and select-into clause, used to match "{x}", where x is an integer. */
private static final Pattern leveledPathNodePattern = Pattern.compile("\\$\\{\\w+}");
// TODO: add comment
private ZoneId zoneId;
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) {
parseAttributeClauses(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)));
parseAttributeClauses(ctx.attributeClauses(i), createAlignedTimeSeriesStatement);
}
}
public void parseAttributeClauses(
IoTDBSqlParser.AttributeClausesContext ctx,
CreateTimeSeriesStatement createTimeSeriesStatement) {
if (ctx.aliasNodeName() != null) {
createTimeSeriesStatement.setAlias(parseNodeName(ctx.aliasNodeName().nodeName()));
}
Map<String, String> props = new HashMap<>();
if (ctx.dataType != null) {
if (ctx.attributeKey() != null) {
if (!parseAttributeKey(ctx.attributeKey())
.equalsIgnoreCase(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE)) {
throw new SQLParserException("expecting datatype");
}
}
props.put(
IoTDBConstant.COLUMN_TIMESERIES_DATATYPE.toLowerCase(),
parseAttributeValue(ctx.dataType).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) {
parseAttributeClause(ctx.attributeClause(), createTimeSeriesStatement);
}
}
/** check and set datatype, encoding, compressor */
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 parseAttributeClauses(
IoTDBSqlParser.AttributeClausesContext ctx,
CreateAlignedTimeSeriesStatement createAlignedTimeSeriesStatement) {
if (ctx.aliasNodeName() != null) {
createAlignedTimeSeriesStatement.addAliasList(parseNodeName(ctx.aliasNodeName().nodeName()));
} else {
createAlignedTimeSeriesStatement.addAliasList(null);
}
TSDataType dataType = null;
if (ctx.dataType != null) {
if (ctx.attributeKey() != null) {
if (!parseAttributeKey(ctx.attributeKey())
.equalsIgnoreCase(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE)) {
throw new SQLParserException("expecting datatype");
}
}
String dataTypeString = ctx.dataType.getText().toUpperCase();
try {
dataType = TSDataType.valueOf(dataTypeString);
createAlignedTimeSeriesStatement.addDataType(dataType);
} catch (Exception e) {
throw new SemanticException(String.format("unsupported datatype: %s", dataTypeString));
}
}
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 SQLParserException("create aligned timeseries: property is not supported yet.");
}
if (ctx.tagClause() != null) {
parseTagClause(ctx.tagClause(), createAlignedTimeSeriesStatement);
} else {
createAlignedTimeSeriesStatement.addTagsList(null);
}
if (ctx.attributeClause() != null) {
parseAttributeClause(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 parseAttributeClause(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) {
parseAttributeClause(ctx.attributeClause(), alterTimeSeriesStatement);
}
}
alterTimeSeriesStatement.setAlterMap(alterMap);
}
public void parseAliasClause(
IoTDBSqlParser.AliasClauseContext ctx, AlterTimeSeriesStatement alterTimeSeriesStatement) {
if (alterTimeSeriesStatement != null && ctx.ALIAS() != null) {
alterTimeSeriesStatement.setAlias(parseAlias(ctx.alias()));
}
}
// Delete Timeseries ======================================================================
@Override
public Statement visitDeleteTimeseries(IoTDBSqlParser.DeleteTimeseriesContext 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.tagWhereClause() != null) {
parseTagWhereClause(ctx.tagWhereClause(), showTimeSeriesStatement);
}
if (ctx.limitClause() != null) {
parseLimitClause(ctx.limitClause(), showTimeSeriesStatement);
}
return showTimeSeriesStatement;
}
private void parseTagWhereClause(IoTDBSqlParser.TagWhereClauseContext ctx, Statement statement) {
IoTDBSqlParser.AttributeValueContext attributeValueContext;
String key;
String value;
boolean isContains;
if (ctx.containsExpression() != null) {
isContains = true;
attributeValueContext = ctx.containsExpression().attributeValue();
key = parseAttributeKey(ctx.containsExpression().attributeKey());
} else {
isContains = false;
attributeValueContext = ctx.attributePair().attributeValue();
key = parseAttributeKey(ctx.attributePair().attributeKey());
}
value = parseAttributeValue(attributeValueContext);
if (statement instanceof ShowTimeSeriesStatement) {
((ShowTimeSeriesStatement) statement).setContains(isContains);
((ShowTimeSeriesStatement) statement).setKey(key);
((ShowTimeSeriesStatement) statement).setValue(value);
} else if (statement instanceof CountTimeSeriesStatement) {
((CountTimeSeriesStatement) statement).setContains(isContains);
((CountTimeSeriesStatement) statement).setKey(key);
((CountTimeSeriesStatement) statement).setValue(value);
} else if (statement instanceof CountLevelTimeSeriesStatement) {
((CountLevelTimeSeriesStatement) statement).setContains(isContains);
((CountLevelTimeSeriesStatement) statement).setKey(key);
((CountLevelTimeSeriesStatement) statement).setValue(value);
}
}
// Show Storage Group
@Override
public Statement visitShowStorageGroup(IoTDBSqlParser.ShowStorageGroupContext ctx) {
if (ctx.prefixPath() != null) {
return new ShowStorageGroupStatement(parsePrefixPath(ctx.prefixPath()));
} else {
return new ShowStorageGroupStatement(new PartialPath(SQLConstant.getSingleRootArray()));
}
}
// 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.limitClause() != null) {
parseLimitClause(ctx.limitClause(), showDevicesStatement);
}
// show devices wtih storage group
if (ctx.WITH() != null) {
showDevicesStatement.setSgCol(true);
}
return showDevicesStatement;
}
// 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.tagWhereClause() != null) {
parseTagWhereClause(ctx.tagWhereClause(), statement);
}
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 visitCountStorageGroup(CountStorageGroupContext ctx) {
PartialPath path;
if (ctx.prefixPath() != null) {
path = parsePrefixPath(ctx.prefixPath());
} else {
path = new PartialPath(SQLConstant.getSingleRootArray());
}
return new CountStorageGroupStatement(path);
}
// Show version
@Override
public Statement visitShowVersion(IoTDBSqlParser.ShowVersionContext ctx) {
return new ShowVersionStatement();
}
// Create Function
@Override
public Statement visitCreateFunction(CreateFunctionContext ctx) {
return new CreateFunctionStatement(
parseIdentifier(ctx.udfName.getText()),
parseStringLiteral(ctx.className.getText()),
parseUris(ctx.uri()));
}
private List<URI> parseUris(List<UriContext> uriContexts) {
List<URI> uris = new ArrayList<>();
if (uriContexts != null) {
for (UriContext uriContext : uriContexts) {
final String uriString = uriContext.getText();
try {
uris.add(new URI(parseStringLiteral(uriString)));
} catch (URISyntaxException e) {
throw new SemanticException(String.format("'%s' is not a legal URI.", uriString));
}
}
}
return uris;
}
// 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.");
}
if (ctx.jarLocation() == null) {
throw new SemanticException("Please specify the location of jar.");
}
// parse jarPath
String jarPath;
boolean usingURI;
if (ctx.jarLocation().FILE() != null) {
usingURI = false;
jarPath = parseFilePath(ctx.jarLocation().fileName.getText());
} else {
usingURI = true;
jarPath = parseFilePath(ctx.jarLocation().uri().getText());
}
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));
}
}
return new CreateTriggerStatement(
parseIdentifier(ctx.triggerName.getText()),
parseStringLiteral(ctx.className.getText()),
jarPath,
usingURI,
ctx.triggerEventClause().BEFORE() != null
? TriggerEvent.BEFORE_INSERT
: TriggerEvent.AFTER_INSERT,
ctx.triggerType().STATELESS() != null ? TriggerType.STATELESS : TriggerType.STATEFUL,
parsePrefixPath(ctx.prefixPath()),
attributes);
}
@Override
public Statement visitDropTrigger(IoTDBSqlParser.DropTriggerContext ctx) {
return new DropTriggerStatement(parseIdentifier(ctx.triggerName.getText()));
}
@Override
public Statement visitShowTriggers(IoTDBSqlParser.ShowTriggersContext ctx) {
return new ShowTriggersStatement();
}
// 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()));
}
}
/** Data Manipulation Language (DML) */
// Select Statement ========================================================================
private QueryStatement queryStatement;
@Override
public Statement visitSelectStatement(IoTDBSqlParser.SelectStatementContext ctx) {
if (ctx.intoClause() != null) {
throw new SemanticException(
"The SELECT-INTO statement is not supported in the current version.");
}
// initialize query statement
queryStatement = new QueryStatement();
// parser select, from
parseSelectClause(ctx.selectClause());
parseFromClause(ctx.fromClause());
// parse where clause
if (ctx.whereClause() != null) {
WhereCondition whereCondition = parseWhereClause(ctx.whereClause());
queryStatement.setWhereCondition(whereCondition);
}
// parser special clause
if (ctx.specialClause() != null) {
queryStatement = (QueryStatement) visit(ctx.specialClause());
}
return queryStatement;
}
// Select Clause
public void parseSelectClause(IoTDBSqlParser.SelectClauseContext ctx) {
SelectComponent selectComponent = new SelectComponent(zoneId);
// 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);
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);
// set selectComponent
queryStatement.setSelectComponent(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
public void 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);
}
queryStatement.setFromComponent(fromComponent);
}
// Where Clause
public WhereCondition parseWhereClause(IoTDBSqlParser.WhereClauseContext ctx) {
Expression predicate =
parseExpression(ctx.expression(), ctx.expression().OPERATOR_NOT() == null);
return new WhereCondition(predicate);
}
// Group By Time Clause
@Override
public Statement visitGroupByTimeStatement(IoTDBSqlParser.GroupByTimeStatementContext ctx) {
// parse group by time clause
parseGroupByTimeClause(ctx.groupByTimeClause());
// parse order by time
if (ctx.orderByClause() != null) {
parseOrderByClause(ctx.orderByClause());
}
// parse Having
if (ctx.havingClause() != null) {
parseHavingClause(ctx.havingClause());
}
// parse limit & offset
if (ctx.specialLimit() != null) {
return visit(ctx.specialLimit());
}
return queryStatement;
}
@Override
public Statement visitGroupByFillStatement(IoTDBSqlParser.GroupByFillStatementContext ctx) {
// parse group by time clause & fill clause
parseGroupByTimeClause(ctx.groupByFillClause());
// parse order by time
if (ctx.orderByClause() != null) {
parseOrderByClause(ctx.orderByClause());
}
// parse Having
if (ctx.havingClause() != null) {
parseHavingClause(ctx.havingClause());
}
// parse limit & offset
if (ctx.specialLimit() != null) {
return visit(ctx.specialLimit());
}
return queryStatement;
}
private void parseGroupByTimeClause(IoTDBSqlParser.GroupByTimeClauseContext ctx) {
GroupByTimeComponent groupByTimeComponent = new GroupByTimeComponent();
// parse time range
parseTimeRange(ctx.timeRange(), groupByTimeComponent);
groupByTimeComponent.setLeftCRightO(ctx.timeRange().LS_BRACKET() != null);
// parse time interval
groupByTimeComponent.setInterval(
parseTimeIntervalOrSlidingStep(
ctx.DURATION_LITERAL(0).getText(), true, groupByTimeComponent));
if (groupByTimeComponent.getInterval() <= 0) {
throw new SemanticException(
"The second parameter time interval should be a positive integer.");
}
// parse sliding step
if (ctx.DURATION_LITERAL().size() == 2) {
groupByTimeComponent.setSlidingStep(
parseTimeIntervalOrSlidingStep(
ctx.DURATION_LITERAL(1).getText(), false, groupByTimeComponent));
} else {
groupByTimeComponent.setSlidingStep(groupByTimeComponent.getInterval());
groupByTimeComponent.setSlidingStepByMonth(groupByTimeComponent.isIntervalByMonth());
}
// parse GroupByLevel clause
if (ctx.LEVEL() != null && ctx.INTEGER_LITERAL() != null) {
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);
queryStatement.setGroupByLevelComponent(groupByLevelComponent);
}
// parse fill clause
if (ctx.fillClause() != null) {
parseFillClause(ctx.fillClause());
}
// set groupByTimeComponent
queryStatement.setGroupByTimeComponent(groupByTimeComponent);
}
private void parseGroupByTimeClause(IoTDBSqlParser.GroupByFillClauseContext ctx) {
GroupByTimeComponent groupByTimeComponent = new GroupByTimeComponent();
// parse time range
parseTimeRange(ctx.timeRange(), groupByTimeComponent);
groupByTimeComponent.setLeftCRightO(ctx.timeRange().LS_BRACKET() != null);
// parse time interval
groupByTimeComponent.setInterval(
parseTimeIntervalOrSlidingStep(
ctx.DURATION_LITERAL(0).getText(), true, groupByTimeComponent));
if (groupByTimeComponent.getInterval() <= 0) {
throw new SemanticException(
"The second parameter time interval should be a positive integer.");
}
// parse sliding step
if (ctx.DURATION_LITERAL().size() == 2) {
groupByTimeComponent.setSlidingStep(
parseTimeIntervalOrSlidingStep(
ctx.DURATION_LITERAL(1).getText(), false, groupByTimeComponent));
} else {
groupByTimeComponent.setSlidingStep(groupByTimeComponent.getInterval());
groupByTimeComponent.setSlidingStepByMonth(groupByTimeComponent.isIntervalByMonth());
}
// parse fill clause
if (ctx.fillClause() != null) {
parseFillClause(ctx.fillClause());
}
// set groupByTimeComponent
queryStatement.setGroupByTimeComponent(groupByTimeComponent);
}
/** parse time range (startTime and endTime) in group by query. */
private void parseTimeRange(
IoTDBSqlParser.TimeRangeContext timeRange, GroupByTimeComponent groupByClauseComponent) {
long currentTime = DatetimeUtils.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");
}
}
/**
* parse time interval or sliding step in group by query.
*
* @param duration represent duration string like: 12d8m9ns, 1y1d, etc.
* @return time in milliseconds, microseconds, or nanoseconds depending on the profile
*/
private long parseTimeIntervalOrSlidingStep(
String duration, boolean isParsingTimeInterval, GroupByTimeComponent groupByTimeComponent) {
if (duration.toLowerCase().contains("mo")) {
if (isParsingTimeInterval) {
groupByTimeComponent.setIntervalByMonth(true);
} else {
groupByTimeComponent.setSlidingStepByMonth(true);
}
}
return DatetimeUtils.convertDurationStrToLong(duration);
}
// Group By Level Clause
@Override
public Statement visitGroupByLevelStatement(IoTDBSqlParser.GroupByLevelStatementContext ctx) {
// parse GroupByLevel clause
parseGroupByLevelClause(ctx.groupByLevelClause());
// parse order by time
if (ctx.orderByClause() != null) {
parseOrderByClause(ctx.orderByClause());
}
// parse Having
if (ctx.havingClause() != null) {
parseHavingClause(ctx.havingClause());
}
// parse limit & offset
if (ctx.specialLimit() != null) {
return visit(ctx.specialLimit());
}
return queryStatement;
}
public void parseGroupByLevelClause(IoTDBSqlParser.GroupByLevelClauseContext 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);
// parse fill clause
if (ctx.fillClause() != null) {
parseFillClause(ctx.fillClause());
}
queryStatement.setGroupByLevelComponent(groupByLevelComponent);
}
// HAVING Clause
public void parseHavingClause(IoTDBSqlParser.HavingClauseContext ctx) {
Expression predicate =
parseExpression(ctx.expression(), ctx.expression().OPERATOR_NOT() == null);
queryStatement.setHavingCondition(new HavingCondition(predicate));
}
// Fill Clause
@Override
public Statement visitFillStatement(IoTDBSqlParser.FillStatementContext ctx) {
// parse fill
parseFillClause(ctx.fillClause());
// parse order by time
if (ctx.orderByClause() != null) {
parseOrderByClause(ctx.orderByClause());
}
// parse limit & offset
if (ctx.specialLimit() != null) {
return visit(ctx.specialLimit());
}
return queryStatement;
}
public void parseFillClause(IoTDBSqlParser.FillClauseContext ctx) {
FillComponent fillComponent = new FillComponent();
if (ctx.linearClause() != null) {
if (ctx.linearClause().DURATION_LITERAL().size() > 0) {
throw new SemanticException("The specified fill time range is not supported.");
}
fillComponent.setFillPolicy(FillPolicy.LINEAR);
} else if (ctx.previousClause() != null) {
if (ctx.previousClause().DURATION_LITERAL() != null) {
throw new SemanticException("The specified fill time range is not supported.");
}
fillComponent.setFillPolicy(FillPolicy.PREVIOUS);
} else if (ctx.specificValueClause() != null) {
fillComponent.setFillPolicy(FillPolicy.VALUE);
if (ctx.specificValueClause().constant() != null) {
Literal fillValue = parseLiteral(ctx.specificValueClause().constant());
fillComponent.setFillValue(fillValue);
} else {
throw new SemanticException("fill value cannot be null");
}
} else if (ctx.previousUntilLastClause() != null) {
throw new SemanticException("PREVIOUSUNTILLAST fill is not supported yet.");
} else if (ctx.oldTypeClause() != null) {
throw new SemanticException("The specified fill datatype is not supported.");
}
queryStatement.setFillComponent(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 SQLParserException("Unsupported constant operand: " + text);
}
}
// Other Clauses
@Override
public Statement visitSpecialLimitStatement(IoTDBSqlParser.SpecialLimitStatementContext ctx) {
return visit(ctx.specialLimit());
}
@Override
public Statement visitLimitStatement(IoTDBSqlParser.LimitStatementContext ctx) {
// parse LIMIT
parseLimitClause(ctx.limitClause(), queryStatement);
// parse SLIMIT
if (ctx.slimitClause() != null) {
parseSlimitClause(ctx.slimitClause());
}
// parse ALIGN BY DEVICE or DISABLE ALIGN
if (ctx.alignByDeviceClauseOrDisableAlign() != null) {
parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
}
return queryStatement;
}
// parse LIMIT & OFFSET
private void parseLimitClause(IoTDBSqlParser.LimitClauseContext ctx, Statement statement) {
int limit;
try {
limit = Integer.parseInt(ctx.INTEGER_LITERAL().getText());
} catch (NumberFormatException e) {
throw new SemanticException("Out of range. LIMIT <N>: N should be Int32.");
}
if (limit <= 0) {
throw new SemanticException("LIMIT <N>: N should be greater than 0.");
}
if (statement instanceof ShowTimeSeriesStatement) {
((ShowTimeSeriesStatement) statement).setLimit(limit);
} else if (statement instanceof ShowDevicesStatement) {
((ShowDevicesStatement) statement).setLimit(limit);
} else {
queryStatement.setRowLimit(limit);
}
// parse OFFSET
if (ctx.offsetClause() != null) {
parseOffsetClause(ctx.offsetClause(), statement);
}
}
// parse OFFSET
private void parseOffsetClause(IoTDBSqlParser.OffsetClauseContext ctx, Statement statement) {
int offset;
try {
offset = Integer.parseInt(ctx.INTEGER_LITERAL().getText());
} catch (NumberFormatException e) {
throw new SemanticException(
"Out of range. OFFSET <OFFSETValue>: OFFSETValue should be Int32.");
}
if (offset < 0) {
throw new SemanticException("OFFSET <OFFSETValue>: OFFSETValue should >= 0.");
}
if (statement instanceof ShowTimeSeriesStatement) {
((ShowTimeSeriesStatement) statement).setOffset(offset);
} else if (statement instanceof ShowDevicesStatement) {
((ShowDevicesStatement) statement).setOffset(offset);
} else {
queryStatement.setRowOffset(offset);
}
}
@Override
public Statement visitSlimitStatement(IoTDBSqlParser.SlimitStatementContext ctx) {
// parse SLIMIT
parseSlimitClause(ctx.slimitClause());
// parse LIMIT
if (ctx.limitClause() != null) {
parseLimitClause(ctx.limitClause(), queryStatement);
}
// parse ALIGN BY DEVICE or DISABLE ALIGN
if (ctx.alignByDeviceClauseOrDisableAlign() != null) {
parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
}
return queryStatement;
}
// parse SLIMIT & SOFFSET
private void 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.");
}
queryStatement.setSeriesLimit(slimit);
// parse SOFFSET
if (ctx.soffsetClause() != null) {
parseSoffsetClause(ctx.soffsetClause());
}
}
// parse SOFFSET
public void 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.");
}
queryStatement.setSeriesOffset(soffset);
}
// WITHOUT NULL Clause
@Override
public Statement visitWithoutNullStatement(IoTDBSqlParser.WithoutNullStatementContext ctx) {
// parse WITHOUT NULL
parseWithoutNullClause(ctx.withoutNullClause());
// parse LIMIT & OFFSET
if (ctx.limitClause() != null) {
parseLimitClause(ctx.limitClause(), queryStatement);
}
// parse SLIMIT & SOFFSET
if (ctx.slimitClause() != null) {
parseSlimitClause(ctx.slimitClause());
}
// parse ALIGN BY DEVICE or DISABLE ALIGN
if (ctx.alignByDeviceClauseOrDisableAlign() != null) {
parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
}
return queryStatement;
}
// parse WITHOUT NULL
private void parseWithoutNullClause(IoTDBSqlParser.WithoutNullClauseContext ctx) {
throw new SemanticException("WITHOUT NULL clause is not supported yet.");
}
// ORDER BY TIME Clause
@Override
public Statement visitOrderByTimeStatement(IoTDBSqlParser.OrderByTimeStatementContext ctx) {
// parse ORDER BY TIME
parseOrderByClause(ctx.orderByClause());
// parse others
if (ctx.specialLimit() != null) {
return visit(ctx.specialLimit());
}
return queryStatement;
}
// parse ORDER BY TIME
private void parseOrderByClause(IoTDBSqlParser.OrderByClauseContext ctx) {
OrderByComponent orderByComponent = new OrderByComponent();
Set<SortKey> sortKeySet = new HashSet<>();
for (IoTDBSqlParser.OrderByAttributeClauseContext orderByAttributeClauseContext :
ctx.orderByAttributeClause()) {
SortItem sortItem = parseOrderByAttributeClause(orderByAttributeClauseContext);
SortKey sortKey = sortItem.getSortKey();
if (sortKeySet.contains(sortKey)) {
throw new SemanticException(String.format("ORDER BY: duplicate sort key '%s'", sortKey));
} else {
sortKeySet.add(sortKey);
orderByComponent.addSortItem(sortItem);
}
}
queryStatement.setOrderByComponent(orderByComponent);
}
private SortItem parseOrderByAttributeClause(IoTDBSqlParser.OrderByAttributeClauseContext ctx) {
return new SortItem(
SortKey.valueOf(ctx.sortKey().getText().toUpperCase()),
ctx.DESC() != null ? Ordering.DESC : Ordering.ASC);
}
// ResultSetFormat Clause
@Override
public Statement visitAlignByDeviceClauseOrDisableAlignStatement(
IoTDBSqlParser.AlignByDeviceClauseOrDisableAlignStatementContext ctx) {
parseAlignByDeviceClauseOrDisableAlign(ctx.alignByDeviceClauseOrDisableAlign());
return queryStatement;
}
private void parseAlignByDeviceClauseOrDisableAlign(
IoTDBSqlParser.AlignByDeviceClauseOrDisableAlignContext ctx) {
if (ctx.alignByDeviceClause() != null) {
queryStatement.setResultSetFormat(ResultSetFormat.ALIGN_BY_DEVICE);
} else {
queryStatement.setResultSetFormat(ResultSetFormat.DISABLE_ALIGN);
}
}
// Insert Statement ========================================================================
@Override
public Statement visitInsertStatement(IoTDBSqlParser.InsertStatementContext ctx) {
InsertStatement insertStatement = new InsertStatement();
insertStatement.setDevice(parsePrefixPath(ctx.prefixPath()));
boolean isTimeDefault = parseInsertColumnSpec(ctx.insertColumnsSpec(), insertStatement);
parseInsertValuesSpec(ctx.insertValuesSpec(), insertStatement, isTimeDefault);
insertStatement.setAligned(ctx.ALIGNED() != null);
return insertStatement;
}
private boolean parseInsertColumnSpec(
IoTDBSqlParser.InsertColumnsSpecContext ctx, InsertStatement insertStatement) {
List<String> measurementList = new ArrayList<>();
for (IoTDBSqlParser.NodeNameWithoutWildcardContext measurementName :
ctx.nodeNameWithoutWildcard()) {
measurementList.add(parseNodeNameWithoutWildCard(measurementName));
}
insertStatement.setMeasurementList(measurementList.toArray(new String[0]));
return (ctx.TIME() == null && ctx.TIMESTAMP() == null);
}
private void parseInsertValuesSpec(
IoTDBSqlParser.InsertValuesSpecContext ctx,
InsertStatement insertStatement,
boolean isTimeDefault) {
List<IoTDBSqlParser.InsertMultiValueContext> insertMultiValues = ctx.insertMultiValue();
List<String[]> valuesList = new ArrayList<>();
long[] timeArray = new long[insertMultiValues.size()];
for (int i = 0; i < insertMultiValues.size(); i++) {
// parse timestamp
long timestamp;
List<String> valueList = new ArrayList<>();
if (insertMultiValues.get(i).timeValue() != null) {
if (isTimeDefault) {
if (insertMultiValues.size() != 1) {
throw new SemanticException("need timestamps when insert multi rows");
}
valueList.add(insertMultiValues.get(i).timeValue().getText());
timestamp = DatetimeUtils.currentTime();
} else {
timestamp =
parseTimeValue(insertMultiValues.get(i).timeValue(), DatetimeUtils.currentTime());
}
} else {
if (!isTimeDefault) {
throw new SemanticException(
"the measurementList's size is not consistent with the valueList's size");
}
if (insertMultiValues.size() != 1) {
throw new SemanticException("need timestamps when insert multi rows");
}
timestamp = parseDateFormat(SQLConstant.NOW_FUNC);
}
timeArray[i] = timestamp;
// parse values
List<IoTDBSqlParser.MeasurementValueContext> values =
insertMultiValues.get(i).measurementValue();
for (IoTDBSqlParser.MeasurementValueContext value : values) {
for (IoTDBSqlParser.ConstantContext constant : value.constant()) {
if (constant.STRING_LITERAL() != null) {
valueList.add(parseStringLiteralInInsertValue(constant.getText()));
} else {
valueList.add(constant.getText());
}
}
}
valuesList.add(valueList.toArray(new String[0]));
}
insertStatement.setTimes(timeArray);
insertStatement.setValuesList(valuesList);
}
// Load File
@Override
public Statement visitLoadFile(IoTDBSqlParser.LoadFileContext ctx) {
LoadTsFileStatement loadTsFileStatement =
new LoadTsFileStatement(parseStringLiteral(ctx.fileName.getText()));
if (ctx.loadFilesClause() != null) {
parseLoadFiles(loadTsFileStatement, ctx.loadFilesClause());
}
return loadTsFileStatement;
}
/**
* 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
*/
private void parseLoadFiles(
LoadTsFileStatement loadTsFileStatement, IoTDBSqlParser.LoadFilesClauseContext ctx) {
if (ctx.AUTOREGISTER() != null) {
loadTsFileStatement.setAutoCreateSchema(
Boolean.parseBoolean(ctx.BOOLEAN_LITERAL().getText()));
} else if (ctx.SGLEVEL() != null) {
loadTsFileStatement.setSgLevel(Integer.parseInt(ctx.INTEGER_LITERAL().getText()));
} else if (ctx.VERIFY() != null) {
loadTsFileStatement.setVerifySchema(Boolean.parseBoolean(ctx.BOOLEAN_LITERAL().getText()));
} else {
throw new SQLParserException(
String.format(
"load tsfile format %s error, please input AUTOREGISTER | SGLEVEL | VERIFY.",
ctx.getText()));
}
if (ctx.loadFilesClause() != null) {
parseLoadFiles(loadTsFileStatement, ctx.loadFilesClause());
}
}
/** 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);
}
/** path of expression in withoutNull clause can start with root. */
private PartialPath parseFullPathInExpression(
IoTDBSqlParser.FullPathInExpressionContext ctx, boolean inWithoutNull)
throws SQLParserException {
List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName();
int size = nodeNames.size();
if (ctx.ROOT() != null) {
if (!inWithoutNull) {
throw new SQLParserException("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));
}
}
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 PartialPath parseSuffixPath(IoTDBSqlParser.SuffixPathContext ctx) {
List<IoTDBSqlParser.NodeNameContext> nodeNames = ctx.nodeName();
String[] path = new String[nodeNames.size()];
for (int i = 0; i < nodeNames.size(); i++) {
path[i] = parseNodeName(nodeNames.get(i));
}
return new PartialPath(path);
}
private PartialPath convertConstantToPath(String src) throws IllegalPathException {
return new PartialPath(src);
}
private String parseNodeName(IoTDBSqlParser.NodeNameContext ctx) {
return parseNodeString(ctx.getText());
}
private String parseNodeNameWithoutWildCard(IoTDBSqlParser.NodeNameWithoutWildcardContext ctx) {
return parseNodeString(ctx.getText());
}
private 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)) {
String unWrapped = nodeName.substring(1, nodeName.length() - 1);
if (PathUtils.isRealNumber(unWrapped)
|| !TsFileConstant.IDENTIFIER_PATTERN.matcher(unWrapped).matches()) {
return nodeName;
}
return unWrapped;
}
checkNodeName(nodeName);
return nodeName;
}
private void checkNodeName(String src) {
// node name could start with * and end with *
if (!TsFileConstant.NODE_NAME_PATTERN.matcher(src).matches()) {
throw new SQLParserException(
String.format(
"%s is illegal, unquoted node name can only consist of digits, characters and underscore, or start or end with wildcard",
src));
}
}
private void checkIdentifier(String src) {
if (!TsFileConstant.IDENTIFIER_PATTERN.matcher(src).matches()) {
throw new SQLParserException(
String.format(
"%s is illegal, unquoted identifier can only consist of digits, characters and underscore",
src));
}
}
// Literals ========================================================================
public long parseDateFormat(String timestampStr) throws SQLParserException {
if (timestampStr == null || "".equals(timestampStr.trim())) {
throw new SemanticException("input timestamp cannot be empty");
}
if (timestampStr.equalsIgnoreCase(SQLConstant.NOW_FUNC)) {
return DatetimeUtils.currentTime();
}
try {
return DatetimeUtils.convertDatetimeStrToLong(timestampStr, zoneId);
} catch (Exception e) {
throw new SQLParserException(
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) throws SQLParserException {
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 SQLParserException(
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()) {
if ((src.charAt(0) == '\"' && src.charAt(src.length() - 1) == '\"')
|| (src.charAt(0) == '\'' && src.charAt(src.length() - 1) == '\'')) {
return "'" + parseStringLiteral(src) + "'";
}
}
return src;
}
private 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;
}
/** function for parsing Alias. */
private String parseAlias(IoTDBSqlParser.AliasContext ctx) {
String alias;
if (ctx.constant() != null) {
alias = parseStringLiteral(ctx.constant().getText());
} else {
alias = parseIdentifier(ctx.identifier().getText());
}
return alias;
}
/** Data Control Language (DCL) */
// Create User
@Override
public Statement visitCreateUser(IoTDBSqlParser.CreateUserContext ctx) {
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.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(AuthorOperator.AuthorType.CREATE_ROLE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
return authorStatement;
}
// Alter Password
@Override
public Statement visitAlterUser(IoTDBSqlParser.AlterUserContext ctx) {
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.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);
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.AuthorType.GRANT_USER);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
authorStatement.setPrivilegeList(privileges);
authorStatement.setNodeNameList(nodeNameList);
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);
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.AuthorType.GRANT_ROLE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
authorStatement.setPrivilegeList(privileges);
authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
// Grant User Role
@Override
public Statement visitGrantRoleToUser(IoTDBSqlParser.GrantRoleToUserContext ctx) {
AuthorStatement authorStatement =
new AuthorStatement(AuthorOperator.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);
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.AuthorType.REVOKE_USER);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
authorStatement.setPrivilegeList(privileges);
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);
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.AuthorType.REVOKE_ROLE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
authorStatement.setPrivilegeList(privileges);
authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
private void checkGrantRevokePrivileges(String[] privileges, List<PartialPath> nodeNameList) {
if (nodeNameList.isEmpty()) {
nodeNameList.addAll(Collections.singletonList(new PartialPath(ALL_RESULT_NODES)));
return;
}
boolean pathRelevant = true;
String errorPrivilegeName = "";
for (String privilege : privileges) {
if (!PrivilegeType.valueOf(privilege.toUpperCase()).isPathRelevant()) {
pathRelevant = false;
errorPrivilegeName = privilege.toUpperCase();
break;
}
}
if (!(pathRelevant
|| (nodeNameList.size() == 1
&& nodeNameList.contains(new PartialPath(ALL_RESULT_NODES))))) {
throw new SQLParserException(
String.format(
"path independent privilege: [%s] can only be set on path: root.**",
errorPrivilegeName));
}
}
// Revoke Role From User
@Override
public Statement visitRevokeRoleFromUser(IoTDBSqlParser.RevokeRoleFromUserContext ctx) {
AuthorStatement authorStatement =
new AuthorStatement(AuthorOperator.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(AuthorOperator.AuthorType.DROP_USER);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
return authorStatement;
}
// Drop Role
@Override
public Statement visitDropRole(IoTDBSqlParser.DropRoleContext ctx) {
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.AuthorType.DROP_ROLE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
return authorStatement;
}
// List Users
@Override
public Statement visitListUser(IoTDBSqlParser.ListUserContext ctx) {
AuthorStatement authorStatement = new AuthorStatement(AuthorOperator.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(AuthorOperator.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(AuthorOperator.AuthorType.LIST_USER_PRIVILEGE);
authorStatement.setUserName(parseIdentifier(ctx.userName.getText()));
List<PartialPath> nodeNameList =
ctx.prefixPath().stream().map(this::parsePrefixPath).collect(Collectors.toList());
authorStatement.setNodeNameList(nodeNameList);
return authorStatement;
}
// List Privileges of Roles On Specific Path
@Override
public Statement visitListPrivilegesRole(IoTDBSqlParser.ListPrivilegesRoleContext ctx) {
AuthorStatement authorStatement =
new AuthorStatement(AuthorOperator.AuthorType.LIST_ROLE_PRIVILEGE);
authorStatement.setRoleName(parseIdentifier(ctx.roleName.getText()));
List<PartialPath> nodeNameList =
ctx.prefixPath().stream().map(this::parsePrefixPath).collect(Collectors.toList());
authorStatement.setNodeNameList(nodeNameList);
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 Storage Group
@Override
public Statement visitSetStorageGroup(IoTDBSqlParser.SetStorageGroupContext ctx) {
SetStorageGroupStatement setStorageGroupStatement = new SetStorageGroupStatement();
PartialPath path = parsePrefixPath(ctx.prefixPath());
setStorageGroupStatement.setStorageGroupPath(path);
if (ctx.storageGroupAttributesClause() != null) {
parseStorageGroupAttributesClause(
setStorageGroupStatement, ctx.storageGroupAttributesClause());
}
return setStorageGroupStatement;
}
@Override
public Statement visitCreateStorageGroup(IoTDBSqlParser.CreateStorageGroupContext ctx) {
SetStorageGroupStatement setStorageGroupStatement = new SetStorageGroupStatement();
PartialPath path = parsePrefixPath(ctx.prefixPath());
setStorageGroupStatement.setStorageGroupPath(path);
if (ctx.storageGroupAttributesClause() != null) {
parseStorageGroupAttributesClause(
setStorageGroupStatement, ctx.storageGroupAttributesClause());
}
return setStorageGroupStatement;
}
private void parseStorageGroupAttributesClause(
SetStorageGroupStatement setStorageGroupStatement,
IoTDBSqlParser.StorageGroupAttributesClauseContext ctx) {
if (ctx.storageGroupAttributeClause().size() != 0) {
throw new RuntimeException(
"Currently not support set ttl, schemaReplication factor, dataReplication factor, time partition interval to specific storage group.");
}
for (IoTDBSqlParser.StorageGroupAttributeClauseContext attribute :
ctx.storageGroupAttributeClause()) {
if (attribute.TTL() != null) {
long ttl = Long.parseLong(attribute.INTEGER_LITERAL().getText());
setStorageGroupStatement.setTtl(ttl);
} else if (attribute.SCHEMA_REPLICATION_FACTOR() != null) {
int schemaReplicationFactor = Integer.parseInt(attribute.INTEGER_LITERAL().getText());
setStorageGroupStatement.setSchemaReplicationFactor(schemaReplicationFactor);
} else if (attribute.DATA_REPLICATION_FACTOR() != null) {
int dataReplicationFactor = Integer.parseInt(attribute.INTEGER_LITERAL().getText());
setStorageGroupStatement.setDataReplicationFactor(dataReplicationFactor);
} else if (attribute.TIME_PARTITION_INTERVAL() != null) {
long timePartitionInterval = Long.parseLong(attribute.INTEGER_LITERAL().getText());
setStorageGroupStatement.setTimePartitionInterval(timePartitionInterval);
}
}
}
@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.setStorageGroupPath(path);
setTTLStatement.setTTL(ttl);
return setTTLStatement;
}
@Override
public Statement visitUnsetTTL(IoTDBSqlParser.UnsetTTLContext ctx) {
UnSetTTLStatement unSetTTLStatement = new UnSetTTLStatement();
PartialPath partialPath = parsePrefixPath(ctx.prefixPath());
unSetTTLStatement.setStorageGroupPath(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 visitShowCluster(IoTDBSqlParser.ShowClusterContext ctx) {
ShowClusterStatement showClusterStatement = new ShowClusterStatement();
return showClusterStatement;
}
@Override
public Statement visitDeleteStorageGroup(IoTDBSqlParser.DeleteStorageGroupContext ctx) {
DeleteStorageGroupStatement deleteStorageGroupStatement = new DeleteStorageGroupStatement();
List<IoTDBSqlParser.PrefixPathContext> prefixPathContexts = ctx.prefixPath();
List<String> paths = new ArrayList<>();
for (IoTDBSqlParser.PrefixPathContext prefixPathContext : prefixPathContexts) {
paths.add(parsePrefixPath(prefixPathContext).getFullPath());
}
deleteStorageGroupStatement.setPrefixPath(paths);
return deleteStorageGroupStatement;
}
// Explain ========================================================================
@Override
public Statement visitExplain(IoTDBSqlParser.ExplainContext ctx) {
QueryStatement queryStatement = (QueryStatement) visitSelectStatement(ctx.selectStatement());
return new ExplainStatement(queryStatement);
}
@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 parseTimeRange(
predicate.getExpressionType(),
((CompareBinaryExpression) predicate).getLeftExpression(),
((CompareBinaryExpression) predicate).getRightExpression());
} else {
return parseTimeRange(
predicate.getExpressionType(),
((CompareBinaryExpression) predicate).getRightExpression(),
((CompareBinaryExpression) predicate).getLeftExpression());
}
} else {
throw new SemanticException(DELETE_RANGE_ERROR_MSG);
}
}
private TimeRange parseTimeRange(
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 inWithoutNull) {
if (context.unaryInBracket != null) {
return parseExpression(context.unaryInBracket, inWithoutNull);
}
if (context.expressionAfterUnaryOperator != null) {
if (context.MINUS() != null) {
return new NegationExpression(
parseExpression(context.expressionAfterUnaryOperator, inWithoutNull));
}
if (context.OPERATOR_NOT() != null) {
return new LogicNotExpression(
parseExpression(context.expressionAfterUnaryOperator, inWithoutNull));
}
return parseExpression(context.expressionAfterUnaryOperator, inWithoutNull);
}
if (context.leftExpression != null && context.rightExpression != null) {
Expression leftExpression = parseExpression(context.leftExpression, inWithoutNull);
Expression rightExpression = parseExpression(context.rightExpression, inWithoutNull);
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, inWithoutNull);
}
if (context.LIKE() != null) {
return parseLikeExpression(context, inWithoutNull);
}
throw new UnsupportedOperationException();
}
if (context.unaryBeforeIsNullExpression != null) {
return parseIsNullExpression(context, inWithoutNull);
}
if (context.firstExpression != null
&& context.secondExpression != null
&& context.thirdExpression != null) {
Expression firstExpression = parseExpression(context.firstExpression, inWithoutNull);
Expression secondExpression = parseExpression(context.secondExpression, inWithoutNull);
Expression thirdExpression = parseExpression(context.thirdExpression, inWithoutNull);
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, inWithoutNull);
}
if (context.functionName() != null) {
return parseFunctionExpression(context, inWithoutNull);
}
if (context.fullPathInExpression() != null) {
return new TimeSeriesOperand(
parseFullPathInExpression(context.fullPathInExpression(), inWithoutNull));
}
if (context.time != null) {
return new TimestampOperand();
}
if (context.constant() != null && !context.constant().isEmpty()) {
return parseConstantOperand(context.constant(0));
}
throw new UnsupportedOperationException();
}
private Expression parseFunctionExpression(
IoTDBSqlParser.ExpressionContext functionClause, boolean inWithoutNull) {
FunctionExpression functionExpression =
new FunctionExpression(parseIdentifier(functionClause.functionName().getText()));
// expressions
boolean hasNonPureConstantSubExpression = false;
for (IoTDBSqlParser.ExpressionContext expression : functionClause.expression()) {
Expression subexpression = parseExpression(expression, inWithoutNull);
if (!subexpression.isConstantOperand()) {
hasNonPureConstantSubExpression = true;
}
if (subexpression instanceof EqualToExpression
&& ((EqualToExpression) subexpression).getLeftExpression().isConstantOperand()
&& ((EqualToExpression) subexpression).getRightExpression().isConstantOperand()) {
// parse attribute
functionExpression.addAttribute(
((ConstantOperand) ((EqualToExpression) subexpression).getLeftExpression())
.getValueString(),
((ConstantOperand) ((EqualToExpression) subexpression).getRightExpression())
.getValueString());
} 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());
}
return functionExpression;
}
private Expression parseRegularExpression(ExpressionContext context, boolean inWithoutNull) {
return new RegularExpression(
parseExpression(context.unaryBeforeRegularOrLikeExpression, inWithoutNull),
parseStringLiteral(context.STRING_LITERAL().getText()));
}
private Expression parseLikeExpression(ExpressionContext context, boolean inWithoutNull) {
return new LikeExpression(
parseExpression(context.unaryBeforeRegularOrLikeExpression, inWithoutNull),
parseStringLiteral(context.STRING_LITERAL().getText()));
}
private Expression parseIsNullExpression(ExpressionContext context, boolean inWithoutNull) {
return new IsNullExpression(
parseExpression(context.unaryBeforeIsNullExpression, inWithoutNull),
context.OPERATOR_NOT() != null);
}
private Expression parseInExpression(ExpressionContext context, boolean inWithoutNull) {
Expression childExpression = parseExpression(context.unaryBeforeInExpression, inWithoutNull);
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 operand: " + 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 SQLParserException("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());
} else {
time -= DatetimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText());
}
}
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());
} else {
time -= DatetimeUtils.convertDurationStrToLong(time, ctx.getChild(i + 1).getText());
}
}
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 SQLParserException(
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();
if (ctx.attributePair(0) != null) {
for (IoTDBSqlParser.AttributePairContext attributePair : tagsList) {
String value;
value = parseAttributeValue(attributePair.attributeValue());
alterMap.put(parseAttributeKey(attributePair.attributeKey()), value);
}
}
}
private Map<String, String> extractMap(
List<IoTDBSqlParser.AttributePairContext> attributePair2,
IoTDBSqlParser.AttributePairContext attributePair3) {
Map<String, String> tags = new HashMap<>(attributePair2.size());
if (attributePair3 != null) {
for (IoTDBSqlParser.AttributePairContext attributePair : attributePair2) {
tags.put(
parseAttributeKey(attributePair.attributeKey()),
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());
}
private Pair<Long, Long> calcOperatorInterval(QueryFilter queryFilter) {
if (queryFilter.getSinglePath() != null
&& !IoTDBConstant.TIME.equals(queryFilter.getSinglePath().getMeasurement())) {
throw new SemanticException(DELETE_ONLY_SUPPORT_TIME_EXP_ERROR_MSG);
}
long time = Long.parseLong(((BasicFunctionFilter) queryFilter).getValue());
switch (queryFilter.getFilterType()) {
case LESSTHAN:
return new Pair<>(Long.MIN_VALUE, time - 1);
case LESSTHANOREQUALTO:
return new Pair<>(Long.MIN_VALUE, time);
case GREATERTHAN:
return new Pair<>(time + 1, Long.MAX_VALUE);
case GREATERTHANOREQUALTO:
return new Pair<>(time, Long.MAX_VALUE);
case EQUAL:
return new Pair<>(time, time);
default:
throw new SemanticException(DELETE_RANGE_ERROR_MSG);
}
}
// Merge
@Override
public Statement visitMerge(IoTDBSqlParser.MergeContext ctx) {
MergeStatement mergeStatement = new MergeStatement(StatementType.MERGE);
if (ctx.CLUSTER() != null && !IoTDBDescriptor.getInstance().getConfig().isClusterMode()) {
throw new SemanticException("MERGE ON CLUSTER is not supported in standalone mode");
}
mergeStatement.setOnCluster(ctx.LOCAL() == null);
return mergeStatement;
}
@Override
public Statement visitFullMerge(IoTDBSqlParser.FullMergeContext ctx) {
MergeStatement mergeStatement = new MergeStatement(StatementType.FULL_MERGE);
if (ctx.CLUSTER() != null && !IoTDBDescriptor.getInstance().getConfig().isClusterMode()) {
throw new SemanticException("FULL MERGE ON CLUSTER is not supported in standalone mode");
}
mergeStatement.setOnCluster(ctx.LOCAL() == null);
return mergeStatement;
}
// 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()));
}
if (ctx.CLUSTER() != null && !IoTDBDescriptor.getInstance().getConfig().isClusterMode()) {
throw new SemanticException("FLUSH ON CLUSTER is not supported in standalone mode");
}
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);
if (ctx.CLUSTER() != null && !IoTDBDescriptor.getInstance().getConfig().isClusterMode()) {
throw new SemanticException("CLEAR CACHE ON CLUSTER is not supported in standalone mode");
}
clearCacheStatement.setOnCluster(ctx.LOCAL() == null);
return clearCacheStatement;
}
// Load Configuration
@Override
public Statement visitLoadConfiguration(IoTDBSqlParser.LoadConfigurationContext ctx) {
LoadConfigurationStatement loadConfigurationStatement =
new LoadConfigurationStatement(StatementType.LOAD_CONFIGURATION);
if (ctx.CLUSTER() != null && !IoTDBDescriptor.getInstance().getConfig().isClusterMode()) {
throw new SemanticException(
"LOAD CONFIGURATION ON CLUSTER is not supported in standalone mode");
}
loadConfigurationStatement.setOnCluster(ctx.LOCAL() == null);
return loadConfigurationStatement;
}
// Set System Status
@Override
public Statement visitSetSystemStatus(IoTDBSqlParser.SetSystemStatusContext ctx) {
SetSystemStatusStatement setSystemStatusStatement = new SetSystemStatusStatement();
if (ctx.CLUSTER() != null && !IoTDBDescriptor.getInstance().getConfig().isClusterMode()) {
throw new SemanticException(
"SET SYSTEM STATUS ON CLUSTER is not supported in standalone mode");
}
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 RuntimeException("Unknown system status in set system command.");
}
return setSystemStatusStatement;
}
// show region
@Override
public Statement visitShowRegion(IoTDBSqlParser.ShowRegionContext ctx) {
ShowRegionStatement showRegionStatement = new ShowRegionStatement();
// TODO: Maybe add a show partition 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);
}
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();
}
// schema template
@Override
public Statement visitCreateSchemaTemplate(IoTDBSqlParser.CreateSchemaTemplateContext ctx) {
String name = parseIdentifier(parseIdentifier(ctx.templateName.getText()));
List<List<String>> measurementsList = new ArrayList<List<String>>();
List<List<TSDataType>> dataTypesList = new ArrayList<List<TSDataType>>();
List<List<TSEncoding>> encodingsList = new ArrayList<List<TSEncoding>>();
List<List<CompressionType>> compressorsList = new ArrayList<List<CompressionType>>();
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()));
parseAttributeClause(
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()));
parseAttributeClause(
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);
}
void parseAttributeClause(
IoTDBSqlParser.AttributeClausesContext ctx,
List<TSDataType> dataTypes,
List<TSEncoding> encodings,
List<CompressionType> compressors) {
if (ctx.aliasNodeName() != null) {
throw new SQLParserException("schema template: alias is not supported yet.");
}
TSDataType dataType = null;
if (ctx.dataType != null) {
if (ctx.attributeKey() != null) {
if (!parseAttributeKey(ctx.attributeKey())
.equalsIgnoreCase(IoTDBConstant.COLUMN_TIMESERIES_DATATYPE)) {
throw new SQLParserException("expecting datatype");
}
}
String dataTypeString = ctx.dataType.getText().toUpperCase();
try {
dataType = TSDataType.valueOf(dataTypeString);
dataTypes.add(dataType);
} catch (Exception e) {
throw new SemanticException(String.format("unsupported datatype: %s", dataTypeString));
}
}
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 SQLParserException("schema template: property is not supported yet.");
}
if (ctx.tagClause() != null) {
throw new SQLParserException("schema template: tag is not supported yet.");
}
if (ctx.attributeClause() != null) {
throw new SQLParserException("schema template: attribute is not supported yet.");
}
}
@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 visitCreateTimeseriesOfSchemaTemplate(
IoTDBSqlParser.CreateTimeseriesOfSchemaTemplateContext ctx) {
ActivateTemplateStatement statement = new ActivateTemplateStatement();
statement.setPath(parsePrefixPath(ctx.prefixPath()));
return statement;
}
@Override
public Statement visitShowPathsUsingSchemaTemplate(
IoTDBSqlParser.ShowPathsUsingSchemaTemplateContext ctx) {
return new ShowPathsUsingTemplateStatement(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;
}
private PartialPath parsePathFromExpression(Expression expression) {
if (expression instanceof TimeSeriesOperand) {
return ((TimeSeriesOperand) expression).getPath();
} else if (expression instanceof TimestampOperand) {
return SQLConstant.TIME_PATH;
} else {
throw new IllegalArgumentException(
"Unsupported expression type: " + expression.getExpressionType());
}
}
private void parseSelectStatementForPipe(
IoTDBSqlParser.SelectStatementContext ctx, CreatePipeStatement statement)
throws SQLParserException {
if (ctx.TRACING() != null || ctx.intoClause() != null || ctx.specialClause() != null) {
throw new SQLParserException("Not support for this sql in pipe.");
}
// parse select
IoTDBSqlParser.SelectClauseContext selectCtx = ctx.selectClause();
if (selectCtx.LAST() != null || selectCtx.resultColumn().size() != 1) {
throw new SQLParserException("Not support for this sql in pipe.");
}
IoTDBSqlParser.ResultColumnContext resultColumnCtx = selectCtx.resultColumn(0);
if (resultColumnCtx.AS() != null
|| !IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD.equals(
resultColumnCtx.expression().getText())) {
throw new SQLParserException("Not support for this sql in pipe.");
}
// parse from
IoTDBSqlParser.FromClauseContext fromCtx = ctx.fromClause();
if (fromCtx.prefixPath().size() != 1
|| !IoTDBConstant.PATH_ROOT.equals(fromCtx.prefixPath(0).getText())) {
throw new SQLParserException("Not support for this sql in pipe.");
}
// parse where
IoTDBSqlParser.WhereClauseContext whereCtx = ctx.whereClause();
if (whereCtx != null) {
Expression predicate =
parseExpression(whereCtx.expression(), whereCtx.expression().OPERATOR_NOT() == null);
if (!((predicate instanceof GreaterThanExpression)
|| (predicate instanceof GreaterEqualExpression))) {
throw new SQLParserException("Not support for this sql in pipe.");
}
Expression left = ((BinaryExpression) predicate).getLeftExpression();
Expression right = ((BinaryExpression) predicate).getRightExpression();
if (!SQLConstant.isReservedPath(parsePathFromExpression(left))) {
throw new SQLParserException("Not support for this sql in pipe.");
}
if (!(right instanceof ConstantOperand)) {
throw new SQLParserException("Not support for this sql in pipe.");
}
if (((ConstantOperand) right).getDataType() != TSDataType.INT64) {
throw new SQLParserException("Not support for this sql in pipe.");
}
long startTime = Long.parseLong(((ConstantOperand) right).getValueString());
statement.setStartTime(startTime);
}
}
// PIPE
@Override
public Statement visitShowPipe(IoTDBSqlParser.ShowPipeContext ctx) {
ShowPipeStatement showPipeStatement = new ShowPipeStatement();
if (ctx.pipeName != null) {
showPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText()));
}
return showPipeStatement;
}
@Override
public Statement visitCreatePipe(IoTDBSqlParser.CreatePipeContext ctx) throws SQLParserException {
CreatePipeStatement createPipeStatement = new CreatePipeStatement(StatementType.CREATE_PIPE);
if (ctx.pipeName != null && ctx.pipeSinkName != null) {
createPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText()));
createPipeStatement.setPipeSinkName(parseIdentifier(ctx.pipeSinkName.getText()));
} else {
throw new SQLParserException(
"Not support for this sql in CREATEPIPE, please enter pipename or pipesinkname.");
}
if (ctx.selectStatement() != null) {
parseSelectStatementForPipe(ctx.selectStatement(), createPipeStatement);
}
if (ctx.syncAttributeClauses() != null) {
createPipeStatement.setPipeAttributes(parseSyncAttributeClauses(ctx.syncAttributeClauses()));
} else {
createPipeStatement.setPipeAttributes(new HashMap<>());
}
return createPipeStatement;
}
@Override
public Statement visitStartPipe(IoTDBSqlParser.StartPipeContext ctx) {
StartPipeStatement startPipeStatement = new StartPipeStatement(StatementType.START_PIPE);
if (ctx.pipeName != null) {
startPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText()));
} else {
throw new SQLParserException("Not support for this sql in STARTPIPE, please enter pipename.");
}
return startPipeStatement;
}
@Override
public Statement visitStopPipe(IoTDBSqlParser.StopPipeContext ctx) {
StopPipeStatement stopPipeStatement = new StopPipeStatement(StatementType.STOP_PIPE);
if (ctx.pipeName != null) {
stopPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText()));
} else {
throw new SQLParserException("Not support for this sql in STOPPIPE, please enter pipename.");
}
return stopPipeStatement;
}
@Override
public Statement visitDropPipe(IoTDBSqlParser.DropPipeContext ctx) {
DropPipeStatement dropPipeStatement = new DropPipeStatement(StatementType.DROP_PIPE);
if (ctx.pipeName != null) {
dropPipeStatement.setPipeName(parseIdentifier(ctx.pipeName.getText()));
} else {
throw new SQLParserException("Not support for this sql in DROPPIPE, please enter pipename.");
}
return dropPipeStatement;
}
// pipeSink
@Override
public Statement visitShowPipeSink(IoTDBSqlParser.ShowPipeSinkContext ctx) {
ShowPipeSinkStatement showPipeSinkStatement = new ShowPipeSinkStatement();
if (ctx.pipeSinkName != null) {
showPipeSinkStatement.setPipeSinkName(parseIdentifier(ctx.pipeSinkName.getText()));
}
return showPipeSinkStatement;
}
@Override
public Statement visitShowPipeSinkType(IoTDBSqlParser.ShowPipeSinkTypeContext ctx) {
ShowPipeSinkTypeStatement showPipeSinkTypeStatement = new ShowPipeSinkTypeStatement();
return showPipeSinkTypeStatement;
}
@Override
public Statement visitCreatePipeSink(IoTDBSqlParser.CreatePipeSinkContext ctx) {
CreatePipeSinkStatement createPipeSinkStatement =
new CreatePipeSinkStatement(StatementType.CREATE_PIPESINK);
if (ctx.pipeSinkName != null) {
createPipeSinkStatement.setPipeSinkName(parseIdentifier(ctx.pipeSinkName.getText()));
} else {
throw new SQLParserException(
"Not support for this sql in CREATEPIPESINK, please enter pipesinkname.");
}
if (ctx.pipeSinkType != null) {
createPipeSinkStatement.setPipeSinkType(parseIdentifier(ctx.pipeSinkType.getText()));
} else {
throw new SQLParserException(
"Not support for this sql in CREATEPIPESINK, please enter pipesinktype.");
}
if (ctx.syncAttributeClauses() != null) {
createPipeSinkStatement.setAttributes(parseSyncAttributeClauses(ctx.syncAttributeClauses()));
} else {
createPipeSinkStatement.setAttributes(new HashMap<>());
}
return createPipeSinkStatement;
}
@Override
public Statement visitDropPipeSink(IoTDBSqlParser.DropPipeSinkContext ctx) {
DropPipeSinkStatement dropPipeSinkStatement =
new DropPipeSinkStatement(StatementType.DROP_PIPESINK);
if (ctx.pipeSinkName != null) {
dropPipeSinkStatement.setPipeSinkName(parseIdentifier(ctx.pipeSinkName.getText()));
} else {
throw new SQLParserException(
"Not support for this sql in DROPPIPESINK, please enter pipesinkname.");
}
return dropPipeSinkStatement;
}
}