Skip to content

Commit d6b0680

Browse files
authored
[To dev/1.3] Enhance the last query permission && Fixed the rollback version of alter view / table plans && Deleted the unnecessary mods in Tree view deletion (#17465) (#17494)
* [To dev/1.3] Enhance the last query permission && Fixed the rollback version of alter view / table plans && Deleted the unnecessary mods in Tree view deletion (#17465) * dele * shop * f
1 parent b8f33a6 commit d6b0680

File tree

11 files changed

+369
-64
lines changed

11 files changed

+369
-64
lines changed

integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.apache.iotdb.db.it;
2020

21+
import org.apache.iotdb.db.it.utils.TestUtils;
2122
import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant;
2223
import org.apache.iotdb.it.env.EnvFactory;
2324
import org.apache.iotdb.it.env.cluster.env.SimpleEnv;
@@ -57,6 +58,7 @@
5758
import java.sql.Statement;
5859
import java.util.ArrayList;
5960
import java.util.Base64;
61+
import java.util.Collections;
6062
import java.util.List;
6163
import java.util.Map;
6264
import java.util.concurrent.TimeUnit;
@@ -513,6 +515,7 @@ public void insertAndQuery() {
513515
selectLast(httpClient);
514516

515517
queryV2(httpClient);
518+
selectFastLast(httpClient);
516519
queryGroupByLevelV2(httpClient);
517520
queryRowLimitV2(httpClient);
518521
queryShowChildPathsV2(httpClient);
@@ -923,6 +926,71 @@ public void queryWithWrongAuthorization() {
923926
}
924927
}
925928

929+
@Test
930+
public void queryFastLastWithWrongAuthorization() {
931+
CloseableHttpResponse response = null;
932+
933+
TestUtils.executeNonQuery("create user abcd 'strongPassword@1234'");
934+
try {
935+
final CloseableHttpClient httpClient = HttpClientBuilder.create().build();
936+
final HttpPost httpPost = new HttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery");
937+
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
938+
httpPost.setHeader("Accept", "application/json");
939+
final String authorization = getAuthorization("abcd", "strongPassword@1234");
940+
httpPost.setHeader("Authorization", authorization);
941+
final String sql = "{\"prefix_paths\":[\"root\",\"sg25\"]}";
942+
httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
943+
for (int i = 0; i < 30; i++) {
944+
try {
945+
response = httpClient.execute(httpPost);
946+
break;
947+
} catch (Exception e) {
948+
if (i == 29) {
949+
throw e;
950+
}
951+
try {
952+
Thread.sleep(1000);
953+
} catch (InterruptedException ex) {
954+
throw new RuntimeException(ex);
955+
}
956+
}
957+
}
958+
959+
Assert.assertEquals(200, response.getStatusLine().getStatusCode());
960+
String message = EntityUtils.toString(response.getEntity(), "utf-8");
961+
ObjectMapper mapper = new ObjectMapper();
962+
Map map = mapper.readValue(message, Map.class);
963+
List<Long> timestampsResult = (List<Long>) map.get("timestamps");
964+
List<Long> expressionsResult = (List<Long>) map.get("expressions");
965+
List<List<Object>> valuesResult = (List<List<Object>>) map.get("values");
966+
Assert.assertTrue(map.size() > 0);
967+
List<Object> expressions =
968+
new ArrayList<Object>() {
969+
{
970+
add("Timeseries");
971+
add("Value");
972+
add("DataType");
973+
}
974+
};
975+
976+
Assert.assertEquals(expressions, expressionsResult);
977+
Assert.assertEquals(Collections.emptyList(), timestampsResult);
978+
Assert.assertEquals(Collections.emptyList(), valuesResult);
979+
} catch (IOException e) {
980+
e.printStackTrace();
981+
fail(e.getMessage());
982+
} finally {
983+
try {
984+
if (response != null) {
985+
response.close();
986+
}
987+
} catch (IOException e) {
988+
e.printStackTrace();
989+
fail(e.getMessage());
990+
}
991+
}
992+
}
993+
926994
public void query(CloseableHttpClient httpClient) {
927995
CloseableHttpResponse response = null;
928996
try {
@@ -1677,6 +1745,98 @@ public void queryV2(CloseableHttpClient httpClient) {
16771745
}
16781746
}
16791747

1748+
public void selectFastLast(CloseableHttpClient httpClient) {
1749+
// Only used in 1D scenarios
1750+
if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) {
1751+
return;
1752+
}
1753+
CloseableHttpResponse response = null;
1754+
try {
1755+
HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery");
1756+
String sql = "{\"prefix_paths\":[\"root\",\"sg25\"]}";
1757+
httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
1758+
response = httpClient.execute(httpPost);
1759+
HttpEntity responseEntity = response.getEntity();
1760+
String message = EntityUtils.toString(responseEntity, "utf-8");
1761+
ObjectMapper mapper = new ObjectMapper();
1762+
Map map = mapper.readValue(message, Map.class);
1763+
List<Long> timestampsResult = (List<Long>) map.get("timestamps");
1764+
List<Long> expressionsResult = (List<Long>) map.get("expressions");
1765+
List<List<Object>> valuesResult = (List<List<Object>>) map.get("values");
1766+
Assert.assertTrue(map.size() > 0);
1767+
List<Object> expressions =
1768+
new ArrayList<Object>() {
1769+
{
1770+
add("Timeseries");
1771+
add("Value");
1772+
add("DataType");
1773+
}
1774+
};
1775+
List<Object> timestamps =
1776+
new ArrayList<Object>() {
1777+
{
1778+
add(1635232153960l);
1779+
add(1635232153960l);
1780+
add(1635232153960l);
1781+
add(1635232143960l);
1782+
add(1635232153960l);
1783+
add(1635232153960l);
1784+
}
1785+
};
1786+
List<Object> values1 =
1787+
new ArrayList<Object>() {
1788+
{
1789+
add("root.sg25.s3");
1790+
add("root.sg25.s4");
1791+
add("root.sg25.s5");
1792+
add("root.sg25.s6");
1793+
add("root.sg25.s7");
1794+
add("root.sg25.s8");
1795+
}
1796+
};
1797+
List<Object> values2 =
1798+
new ArrayList<Object>() {
1799+
{
1800+
add("");
1801+
add("2");
1802+
add("1635000012345556");
1803+
add("1.41");
1804+
add("false");
1805+
add("3.5555");
1806+
}
1807+
};
1808+
List<Object> values3 =
1809+
new ArrayList<Object>() {
1810+
{
1811+
add("TEXT");
1812+
add("INT32");
1813+
add("INT64");
1814+
add("FLOAT");
1815+
add("BOOLEAN");
1816+
add("DOUBLE");
1817+
}
1818+
};
1819+
1820+
Assert.assertEquals(expressions, expressionsResult);
1821+
Assert.assertEquals(timestamps, timestampsResult);
1822+
Assert.assertEquals(values1, valuesResult.get(0));
1823+
Assert.assertEquals(values2, valuesResult.get(1));
1824+
Assert.assertEquals(values3, valuesResult.get(2));
1825+
} catch (IOException e) {
1826+
e.printStackTrace();
1827+
fail(e.getMessage());
1828+
} finally {
1829+
try {
1830+
if (response != null) {
1831+
response.close();
1832+
}
1833+
} catch (IOException e) {
1834+
e.printStackTrace();
1835+
fail(e.getMessage());
1836+
}
1837+
}
1838+
}
1839+
16801840
public void queryGroupByLevelV2(CloseableHttpClient httpClient) {
16811841
CloseableHttpResponse response = null;
16821842
try {

integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,32 @@ public static void assertResultSetEqual(
684684
}
685685
}
686686

687+
public static void assertResultSetEqual(
688+
SessionDataSet actualResultSet,
689+
List<String> expectedColumnNames,
690+
Set<String> expectedRetSet,
691+
boolean ignoreTimeStamp) {
692+
final Set<String> copiedSet = new HashSet<>(expectedRetSet);
693+
try {
694+
List<String> actualColumnNames = actualResultSet.getColumnNames();
695+
if (ignoreTimeStamp) {
696+
assertEquals(expectedColumnNames, actualColumnNames);
697+
} else {
698+
assertEquals(TIMESTAMP_STR, actualColumnNames.get(0));
699+
assertEquals(expectedColumnNames, actualColumnNames.subList(1, actualColumnNames.size()));
700+
}
701+
702+
while (actualResultSet.hasNext()) {
703+
RowRecord rowRecord = actualResultSet.next();
704+
assertTrue(copiedSet.remove(rowRecord.toString().replace('\t', ',')));
705+
}
706+
assertEquals(0, copiedSet.size());
707+
} catch (IoTDBConnectionException | StatementExecutionException e) {
708+
e.printStackTrace();
709+
fail(e.getMessage());
710+
}
711+
}
712+
687713
public static void createUser(String userName, String password) {
688714
createUser(EnvFactory.getEnv(), userName, password);
689715
}

integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@
2222
import org.apache.iotdb.common.rpc.thrift.TAggregationType;
2323
import org.apache.iotdb.commons.conf.IoTDBConstant;
2424
import org.apache.iotdb.db.it.utils.AlignedWriteUtil;
25+
import org.apache.iotdb.db.it.utils.TestUtils;
2526
import org.apache.iotdb.isession.ISession;
2627
import org.apache.iotdb.isession.SessionDataSet;
2728
import org.apache.iotdb.it.env.EnvFactory;
2829
import org.apache.iotdb.it.framework.IoTDBTestRunner;
2930
import org.apache.iotdb.itbase.category.ClusterIT;
3031
import org.apache.iotdb.itbase.category.LocalStandaloneIT;
3132
import org.apache.iotdb.rpc.IoTDBConnectionException;
33+
import org.apache.iotdb.rpc.RedirectException;
3234
import org.apache.iotdb.rpc.StatementExecutionException;
3335

3436
import org.junit.AfterClass;
@@ -40,7 +42,9 @@
4042
import java.util.ArrayList;
4143
import java.util.Arrays;
4244
import java.util.Collections;
45+
import java.util.HashSet;
4346
import java.util.List;
47+
import java.util.Set;
4448

4549
import static org.apache.iotdb.db.it.utils.TestUtils.assertResultSetEqual;
4650
import static org.junit.Assert.fail;
@@ -244,6 +248,81 @@ public void lastQueryForOneDeviceNoSchema() throws IoTDBConnectionException {
244248
}
245249
}
246250

251+
@Test
252+
public void lastQueryWithPrefixTest() throws IoTDBConnectionException {
253+
// Only used in 1D scenarios
254+
if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) {
255+
return;
256+
}
257+
final Set<String> retArray =
258+
new HashSet<>(
259+
Arrays.asList(
260+
"30,root.sg1.d1.s3,30,INT64",
261+
"30,root.sg1.d1.s4,false,BOOLEAN",
262+
"40,root.sg1.d1.s5,aligned_test40,TEXT",
263+
"23,root.sg1.d1.s1,230000.0,FLOAT",
264+
"40,root.sg1.d1.s2,40,INT32"));
265+
266+
try (final ISession session = EnvFactory.getEnv().getSessionConnection()) {
267+
// Push last cache first
268+
try (final SessionDataSet resultSet =
269+
session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) {
270+
assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true);
271+
}
272+
273+
try (final SessionDataSet resultSet =
274+
session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) {
275+
assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true);
276+
}
277+
} catch (StatementExecutionException | RedirectException e) {
278+
e.printStackTrace();
279+
fail(e.getMessage());
280+
}
281+
}
282+
283+
@Test
284+
public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException {
285+
// Only used in 1D scenarios
286+
if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) {
287+
return;
288+
}
289+
final String[] retArray = new String[] {};
290+
final Set<String> retArray2 =
291+
new HashSet<>(
292+
Arrays.asList(
293+
"30,root.sg1.d1.s3,30,INT64",
294+
"30,root.sg1.d1.s4,false,BOOLEAN",
295+
"40,root.sg1.d1.s5,aligned_test40,TEXT",
296+
"23,root.sg1.d1.s1,230000.0,FLOAT",
297+
"40,root.sg1.d1.s2,40,INT32"));
298+
TestUtils.executeNonQuery("create user abcd 'veryComplexPassword@123'");
299+
300+
try (final ISession session =
301+
EnvFactory.getEnv().getSessionConnection("abcd", "veryComplexPassword@123");
302+
final ISession rootSession = EnvFactory.getEnv().getSessionConnection()) {
303+
// Push last cache first
304+
try (final SessionDataSet resultSet =
305+
rootSession.executeFastLastDataQueryForOnePrefixPath(
306+
Arrays.asList("root", "sg1", "d1"))) {
307+
assertResultSetEqual(resultSet, lastQueryColumnNames, retArray2, true);
308+
}
309+
310+
try (final SessionDataSet resultSet =
311+
session.executeLastDataQueryForOneDevice(
312+
"root.sg1", "root.sg1.d1", Arrays.asList("notExist", "s1"), true)) {
313+
assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true);
314+
}
315+
316+
try (final SessionDataSet resultSet =
317+
session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) {
318+
assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true);
319+
}
320+
} catch (StatementExecutionException | RedirectException e) {
321+
e.printStackTrace();
322+
fail(e.getMessage());
323+
}
324+
}
325+
247326
// ------------------------------ Aggregation Query ------------------------------
248327
@Test
249328
public void aggregationQueryTest() {

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
5656
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
5757
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
58+
import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement;
5859
import org.apache.iotdb.db.schemaengine.SchemaEngine;
5960
import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion;
6061
import org.apache.iotdb.db.utils.CommonUtils;
@@ -102,7 +103,7 @@ public RestApiServiceImpl() {
102103
public Response executeFastLastQueryStatement(
103104
PrefixPathList prefixPathList, SecurityContext securityContext) {
104105
Long queryId = null;
105-
Statement statement = null;
106+
QueryStatement statement = null;
106107
boolean finish = false;
107108
long startTime = System.nanoTime();
108109

@@ -113,28 +114,31 @@ public Response executeFastLastQueryStatement(
113114
new PartialPath(prefixPathList.getPrefixPaths().toArray(new String[0]));
114115
final Map<PartialPath, Map<String, TimeValuePair>> resultMap = new HashMap<>();
115116

117+
// Check permission, the cost is rather low because the req only contains one prefix path
118+
final IClientSession clientSession = SESSION_MANAGER.getCurrSession();
119+
final TSLastDataQueryReq tsLastDataQueryReq =
120+
FastLastHandler.createTSLastDataQueryReq(clientSession, prefixPathList);
121+
statement = StatementGenerator.createStatement(tsLastDataQueryReq);
122+
123+
final Response response = authorizationHandler.checkAuthority(securityContext, statement);
124+
if (response != null) {
125+
return response;
126+
}
127+
116128
final String prefixString = prefixPath.toString();
117129
for (ISchemaRegion region : SchemaEngine.getInstance().getAllSchemaRegions()) {
118130
if (!prefixString.startsWith(region.getDatabaseFullPath())
119131
&& !region.getDatabaseFullPath().startsWith(prefixString)) {
120132
continue;
121133
}
122-
region.fillLastQueryMap(prefixPath, resultMap);
134+
region.fillLastQueryMap(prefixPath, resultMap, statement.getAuthorityScope());
123135
}
124136
// Check cache first
125137
if (!DataNodeSchemaCache.getInstance().getDeviceSchemaCache().getLastCache(resultMap)) {
126-
IClientSession clientSession = SESSION_MANAGER.getCurrSessionAndUpdateIdleTime();
127-
TSLastDataQueryReq tsLastDataQueryReq =
128-
FastLastHandler.createTSLastDataQueryReq(clientSession, prefixPathList);
129-
statement = StatementGenerator.createStatement(tsLastDataQueryReq);
130-
131138
if (ExecuteStatementHandler.validateStatement(statement)) {
132139
return FastLastHandler.buildErrorResponse(TSStatusCode.EXECUTE_STATEMENT_ERROR);
133140
}
134141

135-
Optional.ofNullable(authorizationHandler.checkAuthority(securityContext, statement))
136-
.ifPresent(Response.class::cast);
137-
138142
queryId = SESSION_MANAGER.requestQueryId();
139143
SessionInfo sessionInfo = SESSION_MANAGER.getSessionInfo(clientSession);
140144

0 commit comments

Comments
 (0)