blob: 307bee5829cd5dc05dca064583f11edf3b4a9725 [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.queryengine.plan.statement;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.db.exception.sql.SemanticException;
import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement;
import org.apache.tsfile.utils.Pair;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import static org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement.RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class QueryStatementTest {
private static final Logger logger = LoggerFactory.getLogger(QueryStatementTest.class);
private static final String ALIGN_BY_DEVICE_ONE_LEVEL_ERROR =
"ALIGN BY DEVICE: the suffix paths can only be measurement or one-level wildcard";
@Test
public void semanticCheckTest() {
List<Pair<String, String>> errorSqlWithMessages =
Arrays.asList(
new Pair<>(
"SELECT s1 FROM root.sg.d1 "
+ "GROUP BY ([2017-11-01T00:00:00, 2017-11-07T23:00:00),1d)",
"Common queries and aggregated queries are not allowed to appear at the same time"),
new Pair<>(
"SELECT count(s1),s2 FROM root.sg.d1", RAW_AGGREGATION_HYBRID_QUERY_ERROR_MSG),
// test for where clause
new Pair<>(
"SELECT s1 FROM root.sg.d1 WHERE count(s1) > 0",
"aggregate functions are not supported in WHERE clause"),
// test for having clause
new Pair<>(
"SELECT s1 FROM root.sg.d1 HAVING(s1 > 0)",
"Expression of HAVING clause must to be an Aggregation"),
new Pair<>(
"SELECT s1 FROM root.sg.d1 HAVING(count(s1) > 0)",
"Expression of HAVING clause can not be used in NonAggregationQuery"),
new Pair<>(
"SELECT count(d1.s1) FROM root.sg.d1 GROUP BY level=1 HAVING (count(s1) > 0)",
"When Having used with GroupByLevel: "
+ "the suffix paths can only be measurement or one-level wildcard"),
new Pair<>(
"SELECT count(s1) FROM root.sg.d1 GROUP BY level=1 HAVING (count(sg.d1.s1) > 0)",
"When Having used with GroupByLevel: "
+ "the suffix paths can only be measurement or one-level wildcard"),
// test for align by device clause
new Pair<>(
"SELECT d1.s1 FROM root.sg.d1 align by device", ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
new Pair<>(
"SELECT count(s1) FROM root.sg.d1 group by variation(sg.s1) align by device",
ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
new Pair<>(
"SELECT s1 FROM root.sg.d1 order by root.sg.d1.s1 align by device",
ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
new Pair<>(
"SELECT s1 FROM root.sg.d1 where root.sg.d1.s1 > 0 align by device",
ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
new Pair<>(
"SELECT count(s1) FROM root.sg.d1 having(count(root.sg.d1.s1) > 0) align by device",
ALIGN_BY_DEVICE_ONE_LEVEL_ERROR),
new Pair<>(
"SELECT s1 FROM root.sg.d1 order by timeseries align by device",
"Sorting by timeseries is only supported in last queries."),
// test for last query
new Pair<>(
"SELECT last s1 FROM root.sg.d1 align by device",
"Last query doesn't support align by device."),
new Pair<>(
"SELECT last s1+s2 FROM root.sg.d1",
"Last queries can only be applied on raw time series."),
new Pair<>(
"SELECT last s1 FROM root.sg.d1 order by device",
"Sorting by device is only supported in ALIGN BY DEVICE queries."),
new Pair<>(
"SELECT last s1 FROM root.sg.d1 SLIMIT 1 SOFFSET 2",
"SLIMIT and SOFFSET can not be used in LastQuery."),
// test for select into clause
new Pair<>(
"SELECT s1 INTO root.sg.d2(t1) FROM root.sg.d1 SLIMIT 5",
"select into: slimit clauses are not supported."),
new Pair<>(
"SELECT s1 INTO root.sg.d2(t1) FROM root.sg.d1 SOFFSET 6",
"select into: soffset clauses are not supported."),
new Pair<>(
"SELECT last s1 INTO root.sg.d2(t1) FROM root.sg.d1",
"select into: last clauses are not supported."),
new Pair<>(
"SELECT count(s1) INTO root.sg.d2(t1) FROM root.sg.d1 GROUP BY TAGS(a)",
"select into: GROUP BY TAGS clause are not supported."),
new Pair<>(
"SELECT s1 FROM root.sg.d1 order by timeseries",
"Sorting by timeseries is only supported in last queries."),
new Pair<>(
"SELECT s1 FROM root.sg.d1 order by device",
"Sorting by device is only supported in ALIGN BY DEVICE queries."));
for (Pair<String, String> pair : errorSqlWithMessages) {
String errorSql = pair.left;
String errorMsg = pair.right;
try {
checkErrorQuerySql(errorSql);
} catch (SemanticException e) {
assertEquals(errorMsg, e.getMessage());
continue;
} catch (Exception ex) {
fail(String.format("Meets exception %s in test sql: `%s`", errorMsg, errorSql));
}
fail(String.format("Sql: `%s` must throw exception: %s", errorSql, errorMsg));
}
}
@Test
public void getPathsTest() {
String sql = "SELECT count(s1 + s3) FROM root.sg.d1 WHERE s2 > 0 and time < 1000";
QueryStatement statement =
(QueryStatement) StatementGenerator.createStatement(sql, ZonedDateTime.now().getOffset());
List<PartialPath> fullPaths = statement.getPaths();
assertEquals(2, fullPaths.size());
assertEquals("root.sg.d1.s1", fullPaths.get(0).getFullPath());
assertEquals("root.sg.d1.s3", fullPaths.get(1).getFullPath());
}
private void checkErrorQuerySql(String sql) {
QueryStatement statement =
(QueryStatement) StatementGenerator.createStatement(sql, ZonedDateTime.now().getOffset());
statement.semanticCheck();
}
}