You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by er...@apache.org on 2022/10/24 04:11:14 UTC

[iotdb] branch feature/iotdb-4639 updated (70e268f105 -> 04d71fc7f2)

This is an automated email from the ASF dual-hosted git repository.

ericpai pushed a change to branch feature/iotdb-4639
in repository https://gitbox.apache.org/repos/asf/iotdb.git


 discard 70e268f105 [IOTDB-4639] Support limit, slimit, offset and soffset in tag aggregation
     add aaa4147cd8 [IOTDB-4022] Adjust the storage_group_report_threshold according to memory for writing (#6920)
     add 3c92951245 change compression ratio log level from debug to info (#7593)
     add bbe369add1 [IOTDB-4205] Use logical path to take place of absolute path in snapshot log (#7535)
     add cecfe9b2be [IOTDB-4623] Enhance the stability of remove-confignode.sh when executed in non-running node (#7591)
     add 90733d8289 [IOTDB-4646] Illegal privilege APPLY_TEMPLATE on seriesPath root.ln.** (#7597)
     add d8012d29b8 [IOTDB-4589] Register/recover trigger when registering/restart a datanode (#7575)
     add 5fb78ab80e [IOTDB-4648] Fix bug ConsensusManager won't initialize when restart
     add 66467bc30d [IOTDB-3067] Eliminate PhysicalPlan usage in SchemaRegion (#7573)
     add 089161ecef [docfix] add a sentence in chapter “kill query” to conclude (#7608)
     add 11c3681445 Update 0.14.0-preview3 website (#7611)
     add 928e01fae3 update org.apache.kafka:kafka_2.13 2.8.1 to 2.8.2 (#7606)
     add cbf51cc26f Optimizing regex matching in Regexp (#7618)
     add 26d6c9e265 [IOTDB-4658] Fix ConfigNode restart bug and add Cluster restart IT (#7623)
     add c1c8fbaa77 Fix time unit in the ttl log (#7628)
     add 0ebc42fd83 [IOTDB-4654] Fix concurrent bug caused by sharing same ChunkMetadata
     add c912f937cd [IODB-4657] Fix PatternTreeMap#getOverlapped does not return correct values (#7625)
     add a4fe367436 [IOTDB-4643] Add Unknown_DataNode_Detector (#7585)
     add 53a436f93a Refactor IT classes and packages (#7626)
     add d1358dd09f [IOTDB-4647] Fix CSV import error when import header name with type (#7600)
     add 4eaa59103c [IOTDB-4650] Support starting reading from tail in RewriteTsFileTool (#7604)
     add 5836e07d6d Add detailed error messages while query is time out (#7632)
     add cf6d85062d [IOTDB-4656] Expose client retry configurations in RatisConsensus
     add e18af3de47 update construct method of pendingBatch. (#7548)
     add f33130b9fc [IOTDB-4653] add time precision units when setting TTL (#7639)
     add dbef84905a [IOTDB-4649] Fix the problem that constants which have same valueString but different types can not be distinguished. (#7619)
     add 08b6c1514b [IOTDB-4636] Add check to avoid flush empty chunk group (#7635)
     add 2cb85a9286 [IOTDB-4636] Fix IndexOutOfBoundsException when compacting aligned series (#7638)
     add aac98fec73 [IOTDB-3656] mpp load supports modification (#7354)
     add 5b91cecdeb [IOTDB-4680] fix error msg "%s" in load statement  (#7645)
     add a078e88daa [IOTDB-4256] Implement analyzer for SELECT INTO statement (#7588)
     add 79bfe4d123 [IOTDB-3462] Update ratis version to 2.4.0 (#7651)
     add 1b71c37754 [IOTDB-4647] Fix CSV import error when import header name with type (#7636)
     add 993782d2de [IOTDB-4679] Make MPPDataExchangeService use internal_address instead of rpc_address (#7648)
     add a639c09875 Added changes and user docs to rpc sqls (#7633)
     add 40779e48ad [IOTDB-4381] Implement Trigger fire process (#7355)
     add 84aa99226a [IOTDB-4683] Fix REJECT_THERSHOLD init error in SystemInfo (#7649)
     add 75d853837c [IOTDB-4250][IOTDB-4628] Support multiple pipes and update drop semantics (#7581)
     add 127263dd3b [IOTDB-4627]Trigger transfer (#7643)
     add f2ffb494a2 Perfect add/remove confignode process (#7656)
     add 80dca5c7bb [IOTDB-4688] use streaming md5 computing to replace blocking md5
     add b20f49525e [IOTDB-4689] Use seperate channel for heartbeat / appendEntries
     add 88903b3189 Make default timeout parameter in SessionIT from 1s to 60s (#7647)
     add fd8ced4f07 [IOTDB-4690] Add new configs for RatisConsensus (2.4.0)
     add 723ecb42cf [IOTDB-4534] Add IT for Trigger Execution (#7657)
     add 40571eb259 [IOTDB-4698]Implement interface of getLocationOfStatefulTrigger (#7663)
     add d0d2ec30a8 Disable StandaloneMppIT (#7667)
     add 66e01dfcfc [IOTDB-4699] Override peer's equals and hashcode
     add a12f45e42e [IOTDB-4669] Scheduled task for checking trigger-table of DataNode (#7660)
     add 8303f187b6 [IOTDB-4694] Make sure memTable snapshot is made before flush operation (#7662)
     add e489286abe [github-7180] refactor seriesNumberMonitor and additional properties, cherry pick from rel/0.13 (#7661)
     add 895ab3bc8c [IOTDB-4532] Add ITs for Trigger Management (#7671)
     add d89fbfaa48 [IOTDB-4535] Chinese vesion of Trigger user doc (#7680)
     add 63768fb039 Grafana plugin Modify pluginId and readme files (#7679)
     add 22c07901f7 Disable the IT of the original standalone architecture (#7681)
     add 3cfa037755 update website about release-0.13.3 (#7686)
     add 0396163fcf [IOTDB-4685] Refactor ConfigNode Consensus heartbeat statistics (#7642)
     add e6fb0a51d9 [IOTDB-4705] English version of Trigger user doc (#7688)
     add aabb052dca [IOTDB-4711] Bind DataNodeInternalService to correct address (#7683)
     add 30bf896095 [IOTDB-4706] Call Trigger.restore() when recovering trigger instances
     add 81237589e8 New distribution package structure (#7672)
     add d66d6445ed [IOTDB-4714] Rename TPipeInfo to TCreatePipeReq (#7692)
     add 631fad8860 Fix schema region recover bug (#7696)
     add 2fea01176c Bump flink.version from 1.14.5 to 1.14.6 (#7614)
     add ca7b2b8311 [IOTDB-4641] New Standalone Sync Receiver TsFile Loader Implement (#7610)
     add f9f9721969 [IOTDB-3562] Support Deactivate Template in cluster (#7674)
     add 6101e132d6 [IOTDB-4293] BufferedPipeDataQueue supports discontinuous serialNumber (#7664)
     new 122bb13005 [IOTDB-4639] Support limit, slimit, offset and soffset in tag aggregation
     new 2159cc7516 Add special limit clause for group by tags
     new 04d71fc7f2 Add hard mapping from output expression to result column

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (70e268f105)
            \
             N -- N -- N   refs/heads/feature/iotdb-4639 (04d71fc7f2)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/workflows/main-unix.yml                    |    2 +-
 .github/workflows/main-win.yml                     |    2 +-
 .github/workflows/standalone-it-for-mpp.yml        |  160 ++-
 .gitignore                                         |    1 +
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |   31 +-
 .../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4  |    5 +
 .../main/java/org/apache/iotdb/tool/ImportCsv.java |   20 +-
 confignode/src/assembly/confignode.xml             |   10 +-
 .../resources/conf/iotdb-confignode.properties     |   41 +-
 .../conf/{logback.xml => logback-confignode.xml}   |   20 +-
 .../assembly/resources/sbin/remove-confignode.bat  |    2 +-
 .../assembly/resources/sbin/remove-confignode.sh   |    2 +-
 .../assembly/resources/sbin/start-confignode.bat   |    2 +-
 .../assembly/resources/sbin/start-confignode.sh    |    2 +-
 .../confignode/client/ConfigNodeRequestType.java   |    2 +-
 .../confignode/client/DataNodeRequestType.java     |    9 +-
 .../client/async/AsyncDataNodeClientPool.java      |   45 +-
 .../client/async/handlers/AsyncClientHandler.java  |   10 +-
 .../heartbeat/DataNodeHeartbeatHandler.java        |   34 +-
 ...RPCHandler.java => DeleteSchemaRPCHandler.java} |    6 +-
 .../client/sync/SyncConfigNodeClientPool.java      |    4 +-
 .../iotdb/confignode/conf/ConfigNodeConfig.java    |  180 ++-
 .../iotdb/confignode/conf/ConfigNodeConstant.java  |    7 +-
 .../confignode/conf/ConfigNodeDescriptor.java      |   96 +-
 .../confignode/conf/ConfigNodeRemoveCheck.java     |   20 +-
 .../confignode/conf/SystemPropertiesUtils.java     |   24 +-
 .../consensus/request/ConfigPhysicalPlan.java      |   52 +-
 .../consensus/request/ConfigPhysicalPlanType.java  |   12 +-
 .../{GetRoutingPlan.java => GetRegionIdPlan.java}  |   10 +-
 ...ePlan.java => GetTransferringTriggersPlan.java} |    8 +-
 .../GetTriggerJarPlan.java}                        |   37 +-
 .../GetTriggerLocationPlan.java}                   |   31 +-
 .../request/read/GetTriggerTablePlan.java          |   22 +-
 .../template/GetTemplateSetInfoPlan.java}          |   37 +-
 .../write/{ => datanode}/RegisterDataNodePlan.java |   20 +-
 .../write/{ => datanode}/RemoveDataNodePlan.java   |   27 +-
 .../write/{ => function}/CreateFunctionPlan.java   |    2 +-
 .../write/{ => function}/DropFunctionPlan.java     |    2 +-
 .../{ => partition}/UpdateRegionLocationPlan.java  |    2 +-
 .../write/{ => procedure}/DeleteProcedurePlan.java |    2 +-
 .../write/{ => procedure}/UpdateProcedurePlan.java |    2 +-
 .../write/region/OfferRegionMaintainTasksPlan.java |    2 +-
 .../write/statistics/UpdateLoadStatisticsPlan.java |  125 +++
 .../sync/DropPipePlan.java}                        |   28 +-
 .../UpdateTriggerLocationPlan.java}                |   62 +-
 .../UpdateTriggersOnTransferNodesPlan.java}        |   75 +-
 .../consensus/response/DataNodeRegisterResp.java   |   11 +
 .../{GetRoutingResp.java => GetRegionIdResp.java}  |   10 +-
 ...etRoutingResp.java => TemplateSetInfoResp.java} |   29 +-
 .../response/TransferringTriggersResp.java         |   27 +-
 .../{GetRoutingResp.java => TriggerJarResp.java}   |   25 +-
 ...etRoutingResp.java => TriggerLocationResp.java} |   30 +-
 .../statemachine/PartitionRegionStateMachine.java  |   17 +-
 .../confignode/manager/ClusterSchemaManager.java   |    7 +
 .../iotdb/confignode/manager/ConfigManager.java    |  144 ++-
 .../iotdb/confignode/manager/ConsensusManager.java |   27 +-
 .../apache/iotdb/confignode/manager/IManager.java  |   35 +-
 .../iotdb/confignode/manager/ProcedureManager.java |   74 +-
 .../iotdb/confignode/manager/SyncManager.java      |    8 +-
 .../iotdb/confignode/manager/TriggerManager.java   |  128 ++-
 .../iotdb/confignode/manager/UDFManager.java       |    4 +-
 .../iotdb/confignode/manager/load/LoadManager.java |  112 +-
 .../manager/load/balancer/RouteBalancer.java       |    6 +-
 .../manager/load/balancer/router/IRouter.java      |    2 +-
 .../load/balancer/router/LazyGreedyRouter.java     |    2 +-
 .../manager/load/balancer/router/LeaderRouter.java |   13 +-
 .../balancer/router/LoadScoreGreedyRouter.java     |   13 +-
 .../confignode/manager/node/BaseNodeCache.java     |   48 +-
 .../manager/node/ConfigNodeHeartbeatCache.java     |   49 +-
 .../manager/node/DataNodeHeartbeatCache.java       |   44 +-
 .../iotdb/confignode/manager/node/NodeManager.java |  195 +++-
 .../manager/partition/PartitionManager.java        |   59 +-
 .../confignode/manager/partition/RegionCache.java  |   35 +-
 .../manager/partition/RegionGroupCache.java        |  114 +-
 .../manager/partition/RegionHeartbeatSample.java   |   12 +-
 .../confignode/persistence/ProcedureInfo.java      |    4 +-
 .../iotdb/confignode/persistence/TriggerInfo.java  |   91 +-
 .../iotdb/confignode/persistence/UDFInfo.java      |    4 +-
 .../persistence/executor/ConfigPlanExecutor.java   |   56 +-
 .../persistence/metric/NodeInfoMetrics.java        |    2 +-
 .../persistence/{ => node}/NodeInfo.java           |  150 +--
 .../persistence/node/NodeStatistics.java           |  134 +++
 .../persistence/partition/PartitionInfo.java       |   77 +-
 .../persistence/partition/RegionGroup.java         |    3 +
 .../partition/StorageGroupPartitionTable.java      |    8 +-
 .../{ => maintainer}/RegionCreateTask.java         |    2 +-
 .../{ => maintainer}/RegionDeleteTask.java         |    2 +-
 .../{ => maintainer}/RegionMaintainTask.java       |    2 +-
 .../{ => maintainer}/RegionMaintainType.java       |    2 +-
 .../statistics/RegionGroupStatistics.java          |  145 +++
 .../partition/statistics/RegionStatistics.java     |  111 ++
 .../persistence/schema/ClusterSchemaInfo.java      |   48 +
 .../persistence/schema/TemplateTable.java          |   16 +
 .../persistence/sync/ClusterSyncInfo.java          |   43 +-
 .../confignode/procedure/ProcedureExecutor.java    |    2 +-
 .../procedure/env/ConfigNodeProcedureEnv.java      |   35 +-
 .../procedure/env/DataNodeRemoveHandler.java       |    6 +-
 .../procedure/impl/CreateTriggerProcedure.java     |    5 +-
 .../impl/node/AddConfigNodeProcedure.java          |   17 +-
 .../impl/node/RemoveConfigNodeProcedure.java       |   32 +-
 .../impl/schema/DataNodeRegionGroupUtil.java       |   81 ++
 .../procedure/impl/schema/DataNodeRegionTask.java  |  195 ++++
 .../impl/schema/DeactivateTemplateProcedure.java   |  487 ++++++++
 .../DeleteStorageGroupProcedure.java               |    7 +-
 .../DeleteTimeSeriesProcedure.java                 |  333 ++----
 .../statemachine/CreateRegionGroupsProcedure.java  |    4 +-
 .../impl/sync/AbstractOperatePipeProcedure.java    |    6 +-
 .../procedure/impl/sync/CreatePipeProcedure.java   |    9 +-
 .../procedure/impl/sync/DropPipeProcedure.java     |   12 +-
 .../procedure/state/AddConfigNodeState.java        |    2 +-
 .../procedure/state/RemoveConfigNodeState.java     |    2 +-
 .../DeactivateTemplateState.java}                  |    6 +-
 .../{ => schema}/DeleteStorageGroupState.java      |    2 +-
 .../state/{ => schema}/DeleteTimeSeriesState.java  |    2 +-
 .../procedure/store/ConfigProcedureStore.java      |    4 +-
 .../procedure/store/ProcedureFactory.java          |   13 +-
 .../iotdb/confignode/service/ConfigNode.java       |   20 +-
 .../confignode/service/ConfigNodeCommandLine.java  |   23 +-
 .../thrift/ConfigNodeRPCServiceProcessor.java      |   53 +-
 .../request/ConfigPhysicalPlanSerDeTest.java       |  185 +++-
 .../request/write/RemoveDataNodePlanTest.java      |  173 ---
 .../load/balancer/router/LazyGreedyRouterTest.java |    8 +-
 .../load/balancer/router/LeaderRouterTest.java     |  152 +--
 .../balancer/router/LoadScoreGreedyRouterTest.java |    4 +-
 .../manager/partition/RegionGroupCacheTest.java    |   81 +-
 .../iotdb/confignode/persistence/NodeInfoTest.java |   69 +-
 .../confignode/persistence/PartitionInfoTest.java  |   45 +-
 .../node/NodeStatisticsTest.java}                  |   36 +-
 .../statistics/RegionGroupStatisticsTest.java      |   56 +
 .../statistics/RegionStatisticsTest.java}          |   36 +-
 .../impl/DeactivateTemplateProcedureTest.java      |   89 ++
 .../impl/DeleteStorageGroupProcedureTest.java      |    2 +-
 .../impl/DeleteTimeSeriesProcedureTest.java        |    2 +-
 .../procedure/impl/OperatePipeProcedureTest.java   |    8 +-
 .../thrift/ConfigNodeRPCServiceProcessorTest.java  |  338 ------
 .../confignode1conf/iotdb-confignode.properties    |    3 +-
 .../confignode2conf/iotdb-confignode.properties    |    3 +-
 .../confignode3conf/iotdb-confignode.properties    |    1 +
 consensus/pom.xml                                  |    2 +-
 .../org/apache/iotdb/consensus/common/Peer.java    |   16 +-
 .../apache/iotdb/consensus/config/RatisConfig.java |  122 +-
 .../multileader/logdispatcher/LogDispatcher.java   |   18 +-
 .../multileader/logdispatcher/PendingBatch.java    |   11 +-
 .../ratis/FileInfoWithDelayedMd5Computing.java     |   75 --
 .../iotdb/consensus/ratis/RatisConsensus.java      |    7 +-
 .../iotdb/consensus/ratis/SnapshotStorage.java     |    2 +-
 .../org/apache/iotdb/consensus/ratis/Utils.java    |    8 +
 .../multileader/logdispatcher/SyncStatusTest.java  |   25 +-
 .../apache/iotdb/consensus/ratis/SnapshotTest.java |    3 +
 distribution/src/assembly/all.xml                  |   44 +-
 distribution/src/assembly/confignode.xml           |   10 +-
 distribution/src/assembly/datanode.xml             |    8 +-
 docs/Download/README.md                            |   42 +-
 docs/UserGuide/Alert/Alerting.md                   |  123 ++-
 docs/UserGuide/Alert/Triggers.md                   | 1162 ++++++--------------
 docs/UserGuide/Cluster/Cluster-Concept.md          |   18 +-
 docs/UserGuide/Cluster/Cluster-Setup.md            |   12 +-
 docs/UserGuide/Delete-Data/TTL.md                  |   16 +-
 .../Maintenance-Tools/Maintenance-Command.md       |  102 +-
 docs/UserGuide/Operate-Metadata/Template.md        |   38 +-
 docs/UserGuide/Reference/DataNode-Config-Manual.md |    9 +
 docs/zh/Download/README.md                         |   42 +-
 docs/zh/UserGuide/Alert/Alerting.md                |  108 +-
 docs/zh/UserGuide/Alert/Triggers.md                | 1128 ++++++-------------
 docs/zh/UserGuide/Cluster/Cluster-Setup.md         |   12 +-
 docs/zh/UserGuide/Delete-Data/TTL.md               |   18 +-
 .../Maintenance-Tools/Maintenance-Command.md       |  101 +-
 docs/zh/UserGuide/Operate-Metadata/Template.md     |   40 +-
 .../UserGuide/Reference/DataNode-Config-Manual.md  |   10 +-
 example/kafka/pom.xml                              |    2 +-
 .../iotdb/trigger/ClusterAlertingExample.java      |    8 +-
 .../org/apache/iotdb/trigger/LoggerTrigger.java    |   86 ++
 .../iotdb/external/api/IPropertiesLoader.java      |   12 +-
 ...sNumerLimiter.java => ISeriesNumerMonitor.java} |    8 +-
 .../iotdb/flink/tsfile/util/TSFileConfigUtil.java  |    1 +
 .../util/TSFileConfigUtilCompletenessTest.java     |   13 +-
 grafana-plugin/README.md                           |  363 +++++-
 grafana-plugin/src/plugin.json                     |    4 +-
 integration-test/checkstyle.xml                    |    8 +-
 integration-test/import-control.xml                |   82 +-
 .../trigger/example/TriggerFireTimesCounter.java   |   87 ++
 .../java/org/apache/iotdb/it/env/AbstractEnv.java  |  115 +-
 .../org/apache/iotdb/it/env/ConfigNodeWrapper.java |    2 +-
 .../org/apache/iotdb/it/env/DataNodeWrapper.java   |    2 +-
 .../java/org/apache/iotdb/it/env/MppConfig.java    |   11 +-
 .../org/apache/iotdb/it/env/RemoteServerEnv.java   |   19 +-
 .../org/apache/iotdb/it/utils/TsFileGenerator.java |  232 ++++
 .../org/apache/iotdb/itbase/env/BaseConfig.java    |   12 +-
 .../java/org/apache/iotdb/itbase/env/BaseEnv.java  |   12 +-
 .../{ => it}/IoTDBClusterPartitionIT.java          |  138 ++-
 .../iotdb/confignode/it/IoTDBClusterRestartIT.java |   87 ++
 .../confignode/{ => it}/IoTDBConfigNodeIT.java     |   19 +-
 .../{ => it}/IoTDBConfigNodeSnapshotIT.java        |   21 +-
 .../it/IoTDBConfigNodeSwitchLeaderIT.java          |  236 ++++
 .../iotdb/confignode/it/IoTDBStorageGroupIT.java   |  184 ++++
 .../org/apache/iotdb/db/it/IOTDBLoadTsFileIT.java  |  340 +++---
 .../java/org/apache/iotdb/db/it/IoTDBFilterIT.java |   24 +-
 .../org/apache/iotdb/db/it/IoTDBFilterNullIT.java  |    3 +
 .../it/aggregation/IoTDBAggregationByLevelIT.java  |    3 +
 .../it/aggregation/IoTDBAggregationDeleteIT.java   |    3 +
 .../aggregation/IoTDBAggregationScanOrderIT.java   |    3 +
 .../aggregation/IoTDBAggregationSmallDataIT.java   |    3 +
 .../db/it/aggregation/IoTDBTagAggregationIT.java   |  105 +-
 .../aligned/IoTDBAggregationWithDeletion2IT.java   |    1 +
 .../it/aligned/IoTDBAggregationWithDeletionIT.java |    1 +
 .../db/it/aligned/IoTDBAlignedLastQuery2IT.java    |    1 +
 .../db/it/aligned/IoTDBAlignedLastQuery3IT.java    |    1 +
 .../db/it/aligned/IoTDBAlignedLastQueryIT.java     |    1 +
 .../db/it/aligned/IoTDBAlignedSeriesQuery2IT.java  |    1 +
 .../db/it/aligned/IoTDBAlignedSeriesQuery3IT.java  |    1 +
 .../db/it/aligned/IoTDBAlignedSeriesQueryIT.java   |    1 +
 .../IoTDBAlignedSeriesQueryWithDeletionIT.java     |    1 +
 .../db/it/aligned/IoTDBGroupByLevelQueryIT.java    |    1 +
 ...GroupByQueryWithValueFilterWithDeletion2IT.java |    1 +
 ...BGroupByQueryWithValueFilterWithDeletionIT.java |    1 +
 ...upByQueryWithoutValueFilterWithDeletion2IT.java |    1 +
 ...oupByQueryWithoutValueFilterWithDeletionIT.java |    1 +
 .../it/aligned/IoTDBLastQueryWithDeletion2IT.java  |    1 +
 .../it/aligned/IoTDBLastQueryWithDeletionIT.java   |    1 +
 .../aligned/IoTDBLastQueryWithoutLastCache2IT.java |    1 +
 .../aligned/IoTDBLastQueryWithoutLastCacheIT.java  |    1 +
 ...DBLastQueryWithoutLastCacheWithDeletion2IT.java |    1 +
 ...TDBLastQueryWithoutLastCacheWithDeletionIT.java |    1 +
 ...BRawQueryWithoutValueFilterWithDeletion2IT.java |    1 +
 ...DBRawQueryWithoutValueFilterWithDeletionIT.java |    1 +
 .../org/apache/iotdb/db/it/env/StandaloneEnv.java  |   20 +-
 .../db/it/schema/IoTDBDeactivateTemplateIT.java    |  231 ++++
 .../org/apache/iotdb/db/it/sync/IoTDBPipeIT.java   |   69 +-
 .../apache/iotdb/db/it/sync/IoTDBPipeSinkIT.java   |    7 +-
 .../apache/iotdb/db/it/sync/SyncTransportTest.java |  323 ++++++
 .../db/it/trigger/IoTDBTriggerExecutionIT.java     |  265 +++++
 .../db/it/trigger/IoTDBTriggerManagementIT.java    |  486 ++++++++
 .../db/it/{aligned => utils}/AlignedWriteUtil.java |    2 +-
 .../db/it/withoutNull/IoTDBWithoutAllNullIT.java   |    3 +
 .../db/it/withoutNull/IoTDBWithoutAnyNullIT.java   |    3 +
 .../withoutNull/IoTDBWithoutNullAllFilterIT.java   |    3 +
 .../withoutNull/IoTDBWithoutNullAnyFilterIT.java   |    3 +
 .../{ => it}/IoTDBSessionAlignedInsertIT.java      |    4 +-
 .../session/{ => it}/IoTDBSessionComplexIT.java    |    4 +-
 .../{ => it}/IoTDBSessionDisableMemControlIT.java  |    4 +-
 .../session/{ => it}/IoTDBSessionInsertNulIT.java  |    6 +-
 .../IoTDBSessionInsertWithTriggerExecutionIT.java  |  337 ++++++
 .../session/{ => it}/IoTDBSessionSimpleIT.java     |    4 +-
 .../{ => it}/IoTDBSessionSyntaxConventionIT.java   |    4 +-
 .../{SessionTest.java => it/SessionIT.java}        |    9 +-
 .../src/test/resources/TriggerFireTimesCounter.jar |  Bin 0 -> 1324 bytes
 ...IoTDBLoadExternalTsFileWithTimePartitionIT.java |  329 ------
 .../db/integration/IoTDBRepeatPatternNameIT.java   |   67 ++
 .../iotdb/db/integration/IoTDBSnapshotIT.java      |   60 +-
 metrics/dropwizard-metrics/pom.xml                 |    6 -
 ...otdb-metric.yml => iotdb-confignode-metric.yml} |    0
 ...{iotdb-metric.yml => iotdb-datanode-metric.yml} |    0
 .../metrics/config/MetricConfigDescriptor.java     |   31 +-
 .../iotdb/metrics/config/MetricConstant.java       |    4 +-
 .../apache/iotdb/commons/cluster/NodeStatus.java   |    2 +-
 .../iotdb/commons/concurrent/ThreadName.java       |    1 +
 .../apache/iotdb/commons/conf/IoTDBConstant.java   |   13 +-
 ...ception.java => PipeAlreadyExistException.java} |   12 +-
 .../exception/sync/PipeNotExistException.java      |    4 -
 .../sync/PipeSinkAlreadyExistException.java        |   12 +-
 ...eption.java => PipeSinkBeingUsedException.java} |   12 +-
 .../exception/sync/PipeSinkNotExistException.java  |   12 +-
 .../commons/executable/ExecutableManager.java      |   11 +
 .../commons/partition/DataPartitionTable.java      |    4 +-
 .../commons/partition/SchemaPartitionTable.java    |    2 +-
 .../commons/partition/SeriesPartitionTable.java    |    2 +-
 .../org/apache/iotdb/commons/path/PartialPath.java |   17 +
 .../apache/iotdb/commons/path/PatternTreeMap.java  |   44 +-
 .../iotdb/commons/sync/metadata/SyncMetadata.java  |  122 +-
 .../commons/sync/persistence/SyncLogReader.java    |   31 +-
 .../apache/iotdb/commons/sync/pipe/PipeStatus.java |    1 -
 .../iotdb/commons/trigger/TriggerInformation.java  |   15 +
 .../apache/iotdb/commons/trigger/TriggerTable.java |   45 +
 .../org/apache/iotdb/commons/utils/AuthUtils.java  |    1 +
 .../commons/utils/ThriftConfigNodeSerDeUtils.java  |   19 -
 .../commons/sync/metedata/SyncMetadataTest.java    |  189 ++++
 pom.xml                                            |    2 +-
 .../java/org/apache/iotdb/RewriteTsFileTool.java   |  249 ++++-
 .../schemaregion/rocksdb/RSchemaRegion.java        |   55 +-
 .../schemaregion/rocksdb/mnode/REntityMNode.java   |   20 +
 .../resources/conf/iotdb-datanode.properties       |   85 +-
 .../conf/{logback.xml => logback-datanode.xml}     |   52 +-
 .../assembly/resources/sbin/remove-datanode.bat    |    2 +-
 .../src/assembly/resources/sbin/remove-datanode.sh |    2 +-
 .../src/assembly/resources/sbin/start-datanode.bat |    2 +-
 .../src/assembly/resources/sbin/start-datanode.sh  |    2 +-
 .../assembly/resources/sbin/start-new-server.bat   |    2 +-
 .../assembly/resources/sbin/start-new-server.sh    |    2 +-
 .../src/assembly/resources/sbin/start-server.bat   |    2 +-
 server/src/assembly/resources/sbin/start-server.sh |    2 +-
 server/src/assembly/server.xml                     |   10 +-
 .../apache/iotdb/db/client/ConfigNodeClient.java   |   84 +-
 .../java/org/apache/iotdb/db/conf/IoTDBConfig.java |  196 +++-
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |  116 +-
 .../db/consensus/DataRegionConsensusImpl.java      |   25 +
 .../db/consensus/SchemaRegionConsensusImpl.java    |   25 +
 .../impl/ReadChunkCompactionPerformer.java         |   21 +-
 .../iotdb/db/engine/flush/MemTableFlushTask.java   |   10 +-
 .../iotdb/db/engine/load/AlignedChunkData.java     |    9 +-
 .../org/apache/iotdb/db/engine/load/ChunkData.java |   14 +-
 .../apache/iotdb/db/engine/load/DeletionData.java  |   72 ++
 .../iotdb/db/engine/load/LoadTsFileManager.java    |   29 +-
 .../iotdb/db/engine/load/NonAlignedChunkData.java  |    1 +
 .../load/{ChunkData.java => TsFileData.java}       |   42 +-
 .../iotdb/db/engine/snapshot/SnapshotFileSet.java  |    4 +-
 .../iotdb/db/engine/snapshot/SnapshotLoader.java   |  377 ++++---
 .../db/engine/snapshot/SnapshotLogAnalyzer.java    |   61 +-
 .../iotdb/db/engine/snapshot/SnapshotLogger.java   |   47 +-
 .../iotdb/db/engine/snapshot/SnapshotTaker.java    |   16 +-
 .../iotdb/db/engine/storagegroup/DataRegion.java   |   38 +-
 .../{StorageGroupInfo.java => DataRegionInfo.java} |   19 +-
 .../db/engine/storagegroup/TsFileManager.java      |    5 +-
 .../db/engine/storagegroup/TsFileProcessor.java    |   79 +-
 .../engine/storagegroup/TsFileProcessorInfo.java   |   16 +-
 .../storagegroup/timeindex/DeviceTimeIndex.java    |    5 +-
 .../query/QueryTimeoutRuntimeException.java        |    9 +
 .../iotdb/db/metadata/LocalSchemaProcessor.java    |    2 +-
 .../apache/iotdb/db/metadata/idtable/IDTable.java  |    8 +-
 .../db/metadata/idtable/IDTableHashmapImpl.java    |   12 +-
 .../db/metadata/logfile/BufferedSerializer.java    |   38 +-
 .../db/metadata/logfile/FakeCRC32Deserializer.java |   91 ++
 .../db/metadata/logfile/FakeCRC32Serializer.java   |   65 ++
 .../logfile/IDeserializer.java}                    |   25 +-
 .../iotdb/db/metadata/logfile/ISerializer.java     |   28 +-
 .../iotdb/db/metadata/logfile/MLogTxtWriter.java   |    2 +-
 .../iotdb/db/metadata/logfile/SchemaLogReader.java |  247 +++++
 .../iotdb/db/metadata/logfile/SchemaLogWriter.java |  114 ++
 .../iotdb/db/metadata/mnode/EntityMNode.java       |   38 +
 .../iotdb/db/metadata/mnode/IEntityMNode.java      |    8 +
 .../iotdb/db/metadata/mnode/InternalMNode.java     |    8 +-
 .../iotdb/db/metadata/mtree/ConfigMTree.java       |   39 +
 .../db/metadata/mtree/MTreeBelowSGMemoryImpl.java  |  102 +-
 .../db/metadata/mtree/traverser/Traverser.java     |   19 +-
 .../traverser/collector/MeasurementCollector.java  |    3 +-
 .../plan/schemaregion/ISchemaRegionPlan.java       |   12 +-
 .../plan/schemaregion/SchemaRegionPlanType.java    |   79 ++
 .../plan/schemaregion/SchemaRegionPlanVisitor.java |  107 ++
 .../impl/ActivateTemplateInClusterPlanImpl.java    |   79 ++
 .../impl/ActivateTemplatePlanImpl.java}            |   28 +-
 .../impl/AutoCreateDeviceMNodePlanImpl.java}       |   28 +-
 .../schemaregion/impl/ChangeAliasPlanImpl.java     |   37 +-
 .../schemaregion/impl/ChangeTagOffsetPlanImpl.java |   37 +-
 .../impl/CreateAlignedTimeSeriesPlanImpl.java      |  171 +++
 .../impl/CreateTimeSeriesPlanImpl.java             |  163 +++
 .../impl/DeactivateTemplatePlanImpl.java}          |   25 +-
 .../impl/DeleteTimeSeriesPlanImpl.java             |   27 +-
 .../impl/PreDeactivateTemplatePlanImpl.java}       |   34 +-
 .../impl/PreDeleteTimeSeriesPlanImpl.java}         |   28 +-
 .../RollbackPreDeactivateTemplatePlanImpl.java}    |   34 +-
 .../impl/RollbackPreDeleteTimeSeriesPlanImpl.java} |   28 +-
 .../impl/SchemaRegionPlanDeserializer.java         |  380 +++++++
 .../schemaregion/impl/SchemaRegionPlanFactory.java |  146 +++
 .../impl/SchemaRegionPlanSerializer.java           |  450 ++++++++
 .../impl/SchemaRegionPlanTxtSerializer.java        |  273 +++++
 .../schemaregion/impl/SetTemplatePlanImpl.java}    |   62 +-
 .../schemaregion/impl/UnsetTemplatePlanImpl.java}  |   62 +-
 .../write/IActivateTemplateInClusterPlan.java      |   60 +
 .../schemaregion/write/IActivateTemplatePlan.java  |   28 +-
 .../write/IAutoCreateDeviceMNodePlan.java          |   28 +-
 .../plan/schemaregion/write/IChangeAliasPlan.java  |   32 +-
 .../schemaregion/write/IChangeTagOffsetPlan.java   |   32 +-
 .../write/ICreateAlignedTimeSeriesPlan.java        |   80 ++
 .../schemaregion/write/ICreateTimeSeriesPlan.java  |   79 ++
 .../write/IDeactivateTemplatePlan.java}            |   36 +-
 .../schemaregion/write/IDeleteTimeSeriesPlan.java  |   28 +-
 .../write/IPreDeactivateTemplatePlan.java}         |   36 +-
 .../write/IPreDeleteTimeSeriesPlan.java            |   28 +-
 .../write/IRollbackPreDeactivateTemplatePlan.java  |   45 +
 .../write/IRollbackPreDeleteTimeSeriesPlan.java    |   28 +-
 .../plan/schemaregion/write/ISetTemplatePlan.java  |   31 +-
 .../schemaregion/write/IUnsetTemplatePlan.java     |   31 +-
 .../db/metadata/schemaregion/ISchemaRegion.java    |   43 +-
 .../db/metadata/schemaregion/SchemaEngine.java     |   46 +-
 .../schemaregion/SchemaRegionMemoryImpl.java       |  539 ++++++---
 .../schemaregion/SchemaRegionSchemaFileImpl.java   |  387 ++++---
 .../iotdb/db/metadata/template/Template.java       |    5 +-
 .../metadata/visitor/SchemaExecutionVisitor.java   |  103 +-
 .../db/mpp/common/header/ColumnHeaderConstant.java |   37 +-
 .../db/mpp/common/header/DatasetHeaderFactory.java |   10 +-
 .../execution/exchange/MPPDataExchangeService.java |    8 +-
 .../execution/executor/RegionWriteExecutor.java    |   36 +-
 .../schema/PathsUsingTemplateScanOperator.java     |   21 +-
 .../apache/iotdb/db/mpp/plan/analyze/Analysis.java |   67 +-
 .../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java  |  372 +++++--
 .../db/mpp/plan/analyze/ConcatPathRewriter.java    |   43 +-
 .../iotdb/db/mpp/plan/analyze/SelectIntoUtils.java |  105 ++
 .../iotdb/db/mpp/plan/constant/StatementType.java  |    2 +
 .../db/mpp/plan/execution/QueryExecution.java      |   15 +-
 .../plan/execution/config/ConfigTaskVisitor.java   |   17 +-
 .../config/executor/ClusterConfigTaskExecutor.java |  116 +-
 .../config/executor/IConfigTaskExecutor.java       |    8 +-
 .../executor/StandaloneConfigTaskExecutor.java     |   16 +-
 .../{GetRegionTask.java => GetRegionIdTask.java}   |   22 +-
 .../execution/config/metadata/ShowClusterTask.java |    4 +-
 .../template/DeactivateSchemaTemplateTask.java     |   45 +
 .../mpp/plan/expression/leaf/ConstantOperand.java  |    4 +-
 .../plan/expression/leaf/TimeSeriesOperand.java    |    9 +
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |  141 ++-
 .../db/mpp/plan/parser/StatementGenerator.java     |    4 +-
 .../db/mpp/plan/planner/LogicalPlanBuilder.java    |   19 +-
 .../db/mpp/plan/planner/LogicalPlanVisitor.java    |    4 +-
 .../db/mpp/plan/planner/OperatorTreeGenerator.java |    2 +-
 .../plan/planner/distribution/SourceRewriter.java  |   88 +-
 .../mpp/plan/planner/plan/node/PlanNodeType.java   |   14 +-
 .../db/mpp/plan/planner/plan/node/PlanVisitor.java |   15 +
 .../plan/node/load/LoadSingleTsFileNode.java       |   69 +-
 .../planner/plan/node/load/LoadTsFileNode.java     |    3 +
 .../plan/node/load/LoadTsFilePieceNode.java        |   35 +-
 .../metedata/read/PathsUsingTemplateScanNode.java  |   36 +-
 .../node/metedata/read/SchemaQueryScanNode.java    |   10 +
 .../node/metedata/write/ActivateTemplateNode.java  |   15 +-
 .../write/CreateAlignedTimeSeriesNode.java         |   25 +-
 .../node/metedata/write/CreateTimeSeriesNode.java  |   17 +-
 .../metedata/write/DeactivateTemplateNode.java     |  128 +++
 .../metedata/write/PreDeactivateTemplateNode.java  |  128 +++
 .../write/RollbackPreDeactivateTemplateNode.java   |  130 +++
 .../parameter/DeviceViewIntoPathDescriptor.java    |  208 ++++
 .../planner/plan/parameter/IntoPathDescriptor.java |  167 +++
 .../plan/scheduler/load/LoadTsFileScheduler.java   |    7 +
 .../db/mpp/plan/statement/StatementVisitor.java    |   12 +-
 .../plan/statement/component/IntoComponent.java    |  237 ++++
 .../db/mpp/plan/statement/component/IntoItem.java  |   73 ++
 .../plan/statement/crud/LoadTsFileStatement.java   |    8 +-
 .../db/mpp/plan/statement/crud/QueryStatement.java |   57 +-
 ...ionStatement.java => GetRegionIdStatement.java} |    6 +-
 ...ement.java => DeactivateTemplateStatement.java} |   44 +-
 .../template/ShowPathsUsingTemplateStatement.java  |   22 +-
 .../dag/input/ConstantInputReader.java             |    3 +-
 .../transformation/dag/util/TransformUtils.java    |    3 +-
 .../db/protocol/mqtt/PayloadFormatManager.java     |    5 +-
 .../sys/ActivateTemplateInClusterPlan.java         |   19 +-
 .../db/qp/physical/sys/ActivateTemplatePlan.java   |    8 +-
 .../qp/physical/sys/AutoCreateDeviceMNodePlan.java |    8 +-
 .../iotdb/db/qp/physical/sys/ChangeAliasPlan.java  |    3 +-
 .../db/qp/physical/sys/ChangeTagOffsetPlan.java    |    3 +-
 .../physical/sys/CreateAlignedTimeSeriesPlan.java  |   38 +-
 .../db/qp/physical/sys/CreateTimeSeriesPlan.java   |    3 +-
 .../db/qp/physical/sys/DeleteTimeSeriesPlan.java   |    8 +-
 .../qp/physical/sys/PreDeleteTimeSeriesPlan.java   |    3 +-
 .../sys/RollbackPreDeleteTimeSeriesPlan.java       |    4 +-
 .../iotdb/db/qp/physical/sys/SetTemplatePlan.java  |    3 +-
 .../db/qp/physical/sys/UnsetTemplatePlan.java      |    3 +-
 .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java    |   34 +-
 .../metadata/DiskAlignedChunkMetadataLoader.java   |    2 +-
 .../chunk/metadata/DiskChunkMetadataLoader.java    |    2 +-
 .../org/apache/iotdb/db/rescon/SystemInfo.java     |   53 +-
 .../java/org/apache/iotdb/db/service/DataNode.java |  133 ++-
 .../db/service/DataNodeInternalRPCService.java     |    2 +-
 .../db/service/DataNodeServerCommandLine.java      |   36 +-
 .../java/org/apache/iotdb/db/service/IoTDB.java    |    4 -
 .../java/org/apache/iotdb/db/service/NewIoTDB.java |    3 -
 .../db/service/ResourcesInformationHolder.java     |   29 +-
 .../impl/DataNodeInternalRPCServiceImpl.java       |  209 +++-
 .../java/org/apache/iotdb/db/sync/SyncService.java |  170 ++-
 .../db/sync/common/ClusterSyncInfoFetcher.java     |    7 +-
 .../iotdb/db/sync/common/ISyncInfoFetcher.java     |    4 +-
 .../apache/iotdb/db/sync/common/LocalSyncInfo.java |   22 +-
 .../iotdb/db/sync/common/LocalSyncInfoFetcher.java |   11 +-
 .../sync/pipedata/queue/BufferedPipeDataQueue.java |   70 +-
 .../db/sync/receiver/load/DeletionLoader.java      |   52 +-
 .../iotdb/db/sync/receiver/load/ILoader.java       |   20 +
 .../iotdb/db/sync/receiver/load/TsFileLoader.java  |   58 +-
 .../org/apache/iotdb/db/sync/sender/pipe/Pipe.java |    7 +
 .../iotdb/db/sync/sender/pipe/TsFilePipe.java      |   49 +-
 .../db/sync/transport/client/SenderManager.java    |    2 +
 .../apache/iotdb/db/tools/schema/MLogParser.java   |  122 +-
 .../iotdb/db/trigger/executor/TriggerExecutor.java |   59 +-
 .../db/trigger/executor/TriggerFireResult.java     |   57 +
 .../db/trigger/executor/TriggerFireVisitor.java    |  423 +++++++
 .../trigger/service/TriggerInformationUpdater.java |  104 ++
 .../trigger/service/TriggerManagementService.java  |  249 ++++-
 .../java/org/apache/iotdb/db/utils/FilesUtils.java |   43 +
 .../org/apache/iotdb/db/utils/JarLoaderUtil.java   |  150 ---
 .../java/org/apache/iotdb/db/utils/QueryUtils.java |   16 +-
 .../apache/iotdb/db/utils/sync/SyncPipeUtil.java   |    6 +-
 .../java/org/apache/iotdb/db/wal/node/WALNode.java |   70 +-
 .../ReadChunkCompactionPerformerAlignedTest.java   |   79 ++
 .../db/engine/snapshot/IoTDBSnapshotTest.java      |   13 +-
 .../db/engine/storagegroup/DataRegionTest.java     |   40 +
 .../engine/storagegroup/TsFileProcessorTest.java   |    4 +-
 .../engine/storagegroup/TsFileProcessorV2Test.java |    4 +-
 .../iotdb/db/metadata/path/PatternTreeMapTest.java |   88 +-
 .../plan/SchemaRegionPlanCompatibilityTest.java    |  334 ++++++
 .../db/mpp/common/schematree/NodeRefTest.java      |   47 +
 .../mpp/execution/operator/OperatorMemoryTest.java |    6 +-
 .../iotdb/db/mpp/plan/analyze/AnalyzeTest.java     |  169 +++
 .../iotdb/db/mpp/plan/plan/LogicalPlannerTest.java |   36 +
 .../manager => persistence}/LocalSyncInfoTest.java |   23 +-
 .../recovery => persistence}/SyncLogTest.java      |   36 +-
 .../sync/pipedata/BufferedPipeDataQueueTest.java   |   95 ++
 .../iotdb/db/sync/transport/SyncTransportTest.java |  357 ------
 .../org/apache/iotdb/db/tools/MLogParserTest.java  |   17 -
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |    4 +-
 .../src/main/thrift/confignode.thrift              |  114 +-
 thrift/src/main/thrift/datanode.thrift             |   71 +-
 .../iotdb/tsfile/common/conf/TSFileConfig.java     |   22 +
 .../iotdb/tsfile/common/conf/TSFileDescriptor.java |    4 +-
 .../tsfile/common/constant/TsFileConstant.java     |    4 +
 .../file/metadata/AlignedTimeSeriesMetadata.java   |   15 +
 .../iotdb/tsfile/file/metadata/ChunkMetadata.java  |   18 +
 .../tsfile/file/metadata/TimeseriesMetadata.java   |    7 +
 .../iotdb/tsfile/read/filter/operator/Regexp.java  |   48 +-
 .../tsfile/write/chunk/AlignedChunkWriterImpl.java |   12 +
 .../apache/iotdb/tsfile/write/record/Tablet.java   |  341 +++++-
 .../iotdb/tsfile/write/writer/TsFileIOWriter.java  |    4 +
 .../iotdb/tsfile/write/record/TabletTest.java      |   65 ++
 506 files changed, 20528 insertions(+), 7876 deletions(-)
 rename confignode/src/assembly/resources/conf/{logback.xml => logback-confignode.xml} (86%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/{DeleteTimeSeriesRPCHandler.java => DeleteSchemaRPCHandler.java} (95%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/{GetRoutingPlan.java => GetRegionIdPlan.java} (94%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/{GetTriggerTablePlan.java => GetTransferringTriggersPlan.java} (83%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/{write/DropFunctionPlan.java => read/GetTriggerJarPlan.java} (59%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/{write/DropFunctionPlan.java => read/GetTriggerLocationPlan.java} (66%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/{write/DropFunctionPlan.java => read/template/GetTemplateSetInfoPlan.java} (54%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => datanode}/RegisterDataNodePlan.java (74%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => datanode}/RemoveDataNodePlan.java (82%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => function}/CreateFunctionPlan.java (97%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => function}/DropFunctionPlan.java (96%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => partition}/UpdateRegionLocationPlan.java (97%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => procedure}/DeleteProcedurePlan.java (96%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{ => procedure}/UpdateProcedurePlan.java (97%)
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/statistics/UpdateLoadStatisticsPlan.java
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/{read/GetTriggerTablePlan.java => write/sync/DropPipePlan.java} (66%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{CreateFunctionPlan.java => trigger/UpdateTriggerLocationPlan.java} (51%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/write/{RemoveDataNodePlan.java => trigger/UpdateTriggersOnTransferNodesPlan.java} (54%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/{GetRoutingResp.java => GetRegionIdResp.java} (83%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/{GetRoutingResp.java => TemplateSetInfoResp.java} (62%)
 copy server/src/main/java/org/apache/iotdb/db/exception/query/QueryTimeoutRuntimeException.java => confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/TransferringTriggersResp.java (57%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/{GetRoutingResp.java => TriggerJarResp.java} (63%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/{GetRoutingResp.java => TriggerLocationResp.java} (59%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/persistence/{ => node}/NodeInfo.java (81%)
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/persistence/node/NodeStatistics.java
 rename confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/{ => maintainer}/RegionCreateTask.java (98%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/{ => maintainer}/RegionDeleteTask.java (97%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/{ => maintainer}/RegionMaintainTask.java (98%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/{ => maintainer}/RegionMaintainType.java (92%)
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/statistics/RegionGroupStatistics.java
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/persistence/partition/statistics/RegionStatistics.java
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DataNodeRegionGroupUtil.java
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DataNodeRegionTask.java
 create mode 100644 confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeactivateTemplateProcedure.java
 rename confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/{statemachine => schema}/DeleteStorageGroupProcedure.java (96%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/{statemachine => schema}/DeleteTimeSeriesProcedure.java (60%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/{DeleteTimeSeriesState.java => schema/DeactivateTemplateState.java} (88%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/{ => schema}/DeleteStorageGroupState.java (93%)
 rename confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/{ => schema}/DeleteTimeSeriesState.java (94%)
 delete mode 100644 confignode/src/test/java/org/apache/iotdb/confignode/consensus/request/write/RemoveDataNodePlanTest.java
 copy confignode/src/test/java/org/apache/iotdb/confignode/{procedure/impl/DeleteStorageGroupProcedureTest.java => persistence/node/NodeStatisticsTest.java} (53%)
 create mode 100644 confignode/src/test/java/org/apache/iotdb/confignode/persistence/partition/statistics/RegionGroupStatisticsTest.java
 copy confignode/src/test/java/org/apache/iotdb/confignode/{procedure/impl/DeleteStorageGroupProcedureTest.java => persistence/partition/statistics/RegionStatisticsTest.java} (53%)
 create mode 100644 confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/DeactivateTemplateProcedureTest.java
 delete mode 100644 confignode/src/test/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessorTest.java
 delete mode 100644 consensus/src/main/java/org/apache/iotdb/consensus/ratis/FileInfoWithDelayedMd5Computing.java
 create mode 100644 example/trigger/src/main/java/org/apache/iotdb/trigger/LoggerTrigger.java
 rename external-api/src/main/java/org/apache/iotdb/external/api/{ISeriesNumerLimiter.java => ISeriesNumerMonitor.java} (82%)
 create mode 100644 integration-test/src/main/java/org/apache/iotdb/db/trigger/example/TriggerFireTimesCounter.java
 create mode 100644 integration-test/src/main/java/org/apache/iotdb/it/utils/TsFileGenerator.java
 rename integration-test/src/test/java/org/apache/iotdb/confignode/{ => it}/IoTDBClusterPartitionIT.java (85%)
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/confignode/it/IoTDBClusterRestartIT.java
 rename integration-test/src/test/java/org/apache/iotdb/confignode/{ => it}/IoTDBConfigNodeIT.java (97%)
 rename integration-test/src/test/java/org/apache/iotdb/confignode/{ => it}/IoTDBConfigNodeSnapshotIT.java (94%)
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/confignode/it/IoTDBConfigNodeSwitchLeaderIT.java
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/confignode/it/IoTDBStorageGroupIT.java
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBDeactivateTemplateIT.java
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/db/it/sync/SyncTransportTest.java
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/db/it/trigger/IoTDBTriggerExecutionIT.java
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/db/it/trigger/IoTDBTriggerManagementIT.java
 rename integration-test/src/test/java/org/apache/iotdb/db/it/{aligned => utils}/AlignedWriteUtil.java (99%)
 rename integration-test/src/test/java/org/apache/iotdb/session/{ => it}/IoTDBSessionAlignedInsertIT.java (99%)
 rename integration-test/src/test/java/org/apache/iotdb/session/{ => it}/IoTDBSessionComplexIT.java (99%)
 rename integration-test/src/test/java/org/apache/iotdb/session/{ => it}/IoTDBSessionDisableMemControlIT.java (98%)
 rename integration-test/src/test/java/org/apache/iotdb/session/{ => it}/IoTDBSessionInsertNulIT.java (99%)
 create mode 100644 integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionInsertWithTriggerExecutionIT.java
 rename integration-test/src/test/java/org/apache/iotdb/session/{ => it}/IoTDBSessionSimpleIT.java (99%)
 rename integration-test/src/test/java/org/apache/iotdb/session/{ => it}/IoTDBSessionSyntaxConventionIT.java (99%)
 rename integration-test/src/test/java/org/apache/iotdb/session/{SessionTest.java => it/SessionIT.java} (95%)
 create mode 100644 integration-test/src/test/resources/TriggerFireTimesCounter.jar
 delete mode 100644 integration/src/test/java/org/apache/iotdb/db/integration/IoTDBLoadExternalTsFileWithTimePartitionIT.java
 create mode 100644 integration/src/test/java/org/apache/iotdb/db/integration/IoTDBRepeatPatternNameIT.java
 copy metrics/interface/src/main/assembly/resources/conf/{iotdb-metric.yml => iotdb-confignode-metric.yml} (100%)
 rename metrics/interface/src/main/assembly/resources/conf/{iotdb-metric.yml => iotdb-datanode-metric.yml} (100%)
 copy node-commons/src/main/java/org/apache/iotdb/commons/exception/sync/{PipeNotExistException.java => PipeAlreadyExistException.java} (67%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/AddConfigNodeState.java => node-commons/src/main/java/org/apache/iotdb/commons/exception/sync/PipeSinkAlreadyExistException.java (75%)
 copy node-commons/src/main/java/org/apache/iotdb/commons/exception/sync/{PipeNotExistException.java => PipeSinkBeingUsedException.java} (73%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/AddConfigNodeState.java => node-commons/src/main/java/org/apache/iotdb/commons/exception/sync/PipeSinkNotExistException.java (76%)
 create mode 100644 node-commons/src/test/java/org/apache/iotdb/commons/sync/metedata/SyncMetadataTest.java
 rename server/src/assembly/resources/conf/{logback.xml => logback-datanode.xml} (84%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/engine/load/DeletionData.java
 copy server/src/main/java/org/apache/iotdb/db/engine/load/{ChunkData.java => TsFileData.java} (53%)
 rename server/src/main/java/org/apache/iotdb/db/engine/storagegroup/{StorageGroupInfo.java => DataRegionInfo.java} (80%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/logfile/BufferedSerializer.java (50%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/logfile/FakeCRC32Deserializer.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/logfile/FakeCRC32Serializer.java
 copy server/src/main/java/org/apache/iotdb/db/{exception/query/QueryTimeoutRuntimeException.java => metadata/logfile/IDeserializer.java} (58%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/logfile/ISerializer.java (58%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/logfile/SchemaLogReader.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/logfile/SchemaLogWriter.java
 copy confignode/src/main/java/org/apache/iotdb/confignode/procedure/state/AddConfigNodeState.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/ISchemaRegionPlan.java (80%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/SchemaRegionPlanType.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/SchemaRegionPlanVisitor.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/ActivateTemplateInClusterPlanImpl.java
 copy server/src/main/java/org/apache/iotdb/db/{exception/query/QueryTimeoutRuntimeException.java => metadata/plan/schemaregion/impl/ActivateTemplatePlanImpl.java} (57%)
 copy server/src/main/java/org/apache/iotdb/db/{exception/query/QueryTimeoutRuntimeException.java => metadata/plan/schemaregion/impl/AutoCreateDeviceMNodePlanImpl.java} (58%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/ChangeAliasPlanImpl.java (54%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/ChangeTagOffsetPlanImpl.java (53%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/CreateAlignedTimeSeriesPlanImpl.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/CreateTimeSeriesPlanImpl.java
 copy server/src/main/java/org/apache/iotdb/db/{exception/query/QueryTimeoutRuntimeException.java => metadata/plan/schemaregion/impl/DeactivateTemplatePlanImpl.java} (56%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/DeleteTimeSeriesPlanImpl.java (55%)
 copy server/src/main/java/org/apache/iotdb/db/metadata/{mnode/IEntityMNode.java => plan/schemaregion/impl/PreDeactivateTemplatePlanImpl.java} (56%)
 copy server/src/main/java/org/apache/iotdb/db/{exception/query/QueryTimeoutRuntimeException.java => metadata/plan/schemaregion/impl/PreDeleteTimeSeriesPlanImpl.java} (59%)
 copy server/src/main/java/org/apache/iotdb/db/metadata/{mnode/IEntityMNode.java => plan/schemaregion/impl/RollbackPreDeactivateTemplatePlanImpl.java} (56%)
 copy server/src/main/java/org/apache/iotdb/db/{exception/query/QueryTimeoutRuntimeException.java => metadata/plan/schemaregion/impl/RollbackPreDeleteTimeSeriesPlanImpl.java} (57%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/SchemaRegionPlanDeserializer.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/SchemaRegionPlanFactory.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/SchemaRegionPlanSerializer.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/impl/SchemaRegionPlanTxtSerializer.java
 copy server/src/main/java/org/apache/iotdb/db/{qp/physical/sys/SetTemplatePlan.java => metadata/plan/schemaregion/impl/SetTemplatePlanImpl.java} (55%)
 copy server/src/main/java/org/apache/iotdb/db/{qp/physical/sys/UnsetTemplatePlan.java => metadata/plan/schemaregion/impl/UnsetTemplatePlanImpl.java} (54%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IActivateTemplateInClusterPlan.java
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IActivateTemplatePlan.java (54%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IAutoCreateDeviceMNodePlan.java (54%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IChangeAliasPlan.java (53%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IChangeTagOffsetPlan.java (53%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/ICreateAlignedTimeSeriesPlan.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/ICreateTimeSeriesPlan.java
 copy server/src/main/java/org/apache/iotdb/db/metadata/{mnode/IEntityMNode.java => plan/schemaregion/write/IDeactivateTemplatePlan.java} (50%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IDeleteTimeSeriesPlan.java (52%)
 copy server/src/main/java/org/apache/iotdb/db/metadata/{mnode/IEntityMNode.java => plan/schemaregion/write/IPreDeactivateTemplatePlan.java} (50%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IPreDeleteTimeSeriesPlan.java (54%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IRollbackPreDeactivateTemplatePlan.java
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IRollbackPreDeleteTimeSeriesPlan.java (53%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/ISetTemplatePlan.java (54%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/metadata/plan/schemaregion/write/IUnsetTemplatePlan.java (54%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/SelectIntoUtils.java
 rename server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/{GetRegionTask.java => GetRegionIdTask.java} (81%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/execution/config/metadata/template/DeactivateSchemaTemplateTask.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/DeactivateTemplateNode.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/PreDeactivateTemplateNode.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/metedata/write/RollbackPreDeactivateTemplateNode.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/parameter/DeviceViewIntoPathDescriptor.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/parameter/IntoPathDescriptor.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoComponent.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoItem.java
 rename server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/{GetRegionStatement.java => GetRegionIdStatement.java} (94%)
 copy server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/metadata/template/{ShowPathsUsingTemplateStatement.java => DeactivateTemplateStatement.java} (50%)
 copy confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/GetTriggerTablePlan.java => server/src/main/java/org/apache/iotdb/db/service/ResourcesInformationHolder.java (54%)
 create mode 100644 server/src/main/java/org/apache/iotdb/db/trigger/executor/TriggerFireResult.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/trigger/executor/TriggerFireVisitor.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/trigger/service/TriggerInformationUpdater.java
 create mode 100644 server/src/main/java/org/apache/iotdb/db/utils/FilesUtils.java
 delete mode 100644 server/src/main/java/org/apache/iotdb/db/utils/JarLoaderUtil.java
 create mode 100644 server/src/test/java/org/apache/iotdb/db/metadata/plan/SchemaRegionPlanCompatibilityTest.java
 create mode 100644 server/src/test/java/org/apache/iotdb/db/mpp/common/schematree/NodeRefTest.java
 rename server/src/test/java/org/apache/iotdb/db/sync/{receiver/manager => persistence}/LocalSyncInfoTest.java (83%)
 rename server/src/test/java/org/apache/iotdb/db/sync/{receiver/recovery => persistence}/SyncLogTest.java (83%)
 delete mode 100644 server/src/test/java/org/apache/iotdb/db/sync/transport/SyncTransportTest.java
 create mode 100644 tsfile/src/test/java/org/apache/iotdb/tsfile/write/record/TabletTest.java


[iotdb] 03/03: Add hard mapping from output expression to result column

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ericpai pushed a commit to branch feature/iotdb-4639
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 04d71fc7f20b07967838e015b1fca84dadfb2eef
Author: ericpai <er...@hotmail.com>
AuthorDate: Wed Oct 19 15:59:12 2022 +0800

    Add hard mapping from output expression to result column
---
 .../db/it/aggregation/IoTDBTagAggregationIT.java   | 102 ++++++---
 .../apache/iotdb/db/mpp/plan/analyze/Analysis.java |  26 ++-
 .../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java  | 249 +++++++++++----------
 .../db/mpp/plan/analyze/ConcatPathRewriter.java    |  43 ++--
 .../db/mpp/plan/planner/LogicalPlanBuilder.java    |  12 +-
 .../db/mpp/plan/statement/crud/QueryStatement.java |   2 +-
 6 files changed, 256 insertions(+), 178 deletions(-)

diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java
index c481ca9718..ac906a3148 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java
@@ -99,7 +99,7 @@ public class IoTDBTagAggregationIT {
     // Expected result set:
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
     // |  k1|count(t)|
-    // avg(t)|max_time(t)|min_time(t)|max_value(t)|min_value(t)|extreme(t)|
+    // AVG(t)|MAX_TIME(t)|MIN_TIME(t)|MAX_VALUE(t)|MIN_VALUE(t)|EXTREME(t)|
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
     // |k1v1|       6| 2.600000003973643|         10|          1|         6.5|         1.1|
     // 6.5|
@@ -123,13 +123,13 @@ public class IoTDBTagAggregationIT {
         Assert.assertEquals(6.5F, resultSet.getFloat(8), DELTA);
         Assert.assertTrue(resultSet.next());
         Assert.assertEquals("k1v2", resultSet.getString("k1"));
-        Assert.assertEquals(4L, resultSet.getLong("count(t)"));
-        Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA);
-        Assert.assertEquals(10L, resultSet.getLong("max_time(t)"));
-        Assert.assertEquals(1L, resultSet.getLong("min_time(t)"));
-        Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA);
-        Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
-        Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
+        Assert.assertEquals(4L, resultSet.getLong("COUNT(t)"));
+        Assert.assertEquals(3.1D, resultSet.getDouble("AVG(t)"), DELTA);
+        Assert.assertEquals(10L, resultSet.getLong("MAX_TIME(t)"));
+        Assert.assertEquals(1L, resultSet.getLong("MIN_TIME(t)"));
+        Assert.assertEquals(5.4F, resultSet.getFloat("MAX_VALUE(t)"), DELTA);
+        Assert.assertEquals(1.3F, resultSet.getFloat("MIN_VALUE(t)"), DELTA);
+        Assert.assertEquals(5.4F, resultSet.getFloat("EXTREME(t)"), DELTA);
         Assert.assertTrue(resultSet.next());
         Assert.assertNull(resultSet.getString(1));
         Assert.assertEquals(4L, resultSet.getLong(2));
@@ -153,7 +153,7 @@ public class IoTDBTagAggregationIT {
     String query = "SELECT COUNT(t + 1), AVG(t + 1) FROM root.sg.** GROUP BY TAGS(k1)";
     // Expected result set:
     // +----+------------+------------------+
-    // |  k1|count(t + 1)|        avg(t + 1)|
+    // |  k1|COUNT(t + 1)|        AVG(t + 1)|
     // +----+------------+------------------+
     // |k1v1|           6| 3.600000003973643|
     // |k1v2|           4|3.1000000536441803|
@@ -205,8 +205,8 @@ public class IoTDBTagAggregationIT {
         "SELECT COUNT(t), AVG(t), MAX_TIME(t), MIN_TIME(t), MAX_VALUE(t), MIN_VALUE(t), EXTREME(t) FROM root.sg.** GROUP BY TAGS(k1) HAVING avg(t) > 3";
     // Expected result set:
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
-    // |  k1|count(t)|
-    // avg(t)|max_time(t)|min_time(t)|max_value(t)|min_value(t)|extreme(t)|
+    // |  k1|COUNT(t)|
+    // AVG(t)|MAX_TIME(t)|MIN_TIME(t)|MAX_VALUE(t)|MIN_VALUE(t)|EXTREME(t)|
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
     // |k1v2|       4|3.1000000536441803|         10|          1|         5.4|         1.3|
     // 5.4|
@@ -219,13 +219,13 @@ public class IoTDBTagAggregationIT {
         Assert.assertEquals(8, resultSet.getMetaData().getColumnCount());
         Assert.assertTrue(resultSet.next());
         Assert.assertEquals("k1v2", resultSet.getString("k1"));
-        Assert.assertEquals(4L, resultSet.getLong("count(t)"));
-        Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA);
-        Assert.assertEquals(10L, resultSet.getLong("max_time(t)"));
-        Assert.assertEquals(1L, resultSet.getLong("min_time(t)"));
-        Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA);
-        Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
-        Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
+        Assert.assertEquals(4L, resultSet.getLong("COUNT(t)"));
+        Assert.assertEquals(3.1D, resultSet.getDouble("AVG(t)"), DELTA);
+        Assert.assertEquals(10L, resultSet.getLong("MAX_TIME(t)"));
+        Assert.assertEquals(1L, resultSet.getLong("MIN_TIME(t)"));
+        Assert.assertEquals(5.4F, resultSet.getFloat("MAX_VALUE(t)"), DELTA);
+        Assert.assertEquals(1.3F, resultSet.getFloat("MIN_VALUE(t)"), DELTA);
+        Assert.assertEquals(5.4F, resultSet.getFloat("EXTREME(t)"), DELTA);
         Assert.assertTrue(resultSet.next());
         Assert.assertNull(resultSet.getString(1));
         Assert.assertEquals(4L, resultSet.getLong(2));
@@ -248,7 +248,7 @@ public class IoTDBTagAggregationIT {
     String query = "SELECT COUNT(t) FROM root.sg.** GROUP BY TAGS(k1, k2)";
     // Expected result set:
     // +----+----+--------+
-    // |  k1|  k2|count(t)|
+    // |  k1|  k2|COUNT(t)|
     // +----+----+--------+
     // |k1v1|k2v1|       2|
     // |k1v1|k2v2|       2|
@@ -276,7 +276,7 @@ public class IoTDBTagAggregationIT {
           Assert.assertTrue(resultSet.next());
           Assert.assertEquals(objects[0], resultSet.getString("k1"));
           Assert.assertEquals(objects[1], resultSet.getString("k2"));
-          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
+          Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)"));
         }
         Assert.assertFalse(resultSet.next());
       }
@@ -291,7 +291,49 @@ public class IoTDBTagAggregationIT {
     String query = "SELECT COUNT(t) from root.sg.** GROUP BY ([0, 20), 10ms), TAGS(k1)";
     // Expected result set:
     // +-----------------------------+----+--------+
-    // |                         Time|  k1|count(t)|
+    // |                         Time|  k1|COUNT(t)|
+    // +-----------------------------+----+--------+
+    // |1970-01-01T08:00:00.000+08:00|k1v1|       3|
+    // |1970-01-01T08:00:00.000+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.000+08:00|null|       2|
+    // |1970-01-01T08:00:00.010+08:00|k1v1|       3|
+    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.010+08:00|null|       2|
+    // +-----------------------------+----+--------+
+    Object[][] expected =
+        new Object[][] {
+          {0L, "k1v1", 3L},
+          {0L, "k1v2", 2L},
+          {0L, null, 2L},
+          {10L, "k1v1", 3L},
+          {10L, "k1v2", 2L},
+          {10L, null, 2L},
+        };
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      try (ResultSet resultSet = statement.executeQuery(query)) {
+        Assert.assertEquals(3, resultSet.getMetaData().getColumnCount());
+        for (Object[] objects : expected) {
+          Assert.assertTrue(resultSet.next());
+          Assert.assertEquals(objects[0], resultSet.getLong("Time"));
+          Assert.assertEquals(objects[1], resultSet.getString("k1"));
+          Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)"));
+        }
+        Assert.assertFalse(resultSet.next());
+      }
+    } catch (SQLException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void testAlongWithTimeAggregationWithAlias() {
+    String query =
+        "SELECT COUNT(t), COUNT(t), COUNT(t) as a from root.sg.** GROUP BY ([0, 20), 10ms), TAGS(k1)";
+    // Expected result set:
+    // +-----------------------------+----+--------+
+    // |                         Time|  k1|COUNT(t)|
     // +-----------------------------+----+--------+
     // |1970-01-01T08:00:00.000+08:00|k1v1|       3|
     // |1970-01-01T08:00:00.000+08:00|k1v2|       2|
@@ -317,7 +359,7 @@ public class IoTDBTagAggregationIT {
           Assert.assertTrue(resultSet.next());
           Assert.assertEquals(objects[0], resultSet.getLong("Time"));
           Assert.assertEquals(objects[1], resultSet.getString("k1"));
-          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
+          Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)"));
         }
         Assert.assertFalse(resultSet.next());
       }
@@ -332,7 +374,7 @@ public class IoTDBTagAggregationIT {
     String query = "SELECT COUNT(t) from root.sg.** GROUP BY ([0, 20), 15ms, 5ms), TAGS(k1)";
     // Expected result set:
     // +-----------------------------+----+--------+
-    // |                         Time|  k1|count(t)|
+    // |                         Time|  k1|COUNT(t)|
     // +-----------------------------+----+--------+
     // |1970-01-01T08:00:00.000+08:00|k1v1|       6|
     // |1970-01-01T08:00:00.000+08:00|k1v2|       4|
@@ -370,7 +412,7 @@ public class IoTDBTagAggregationIT {
           Assert.assertTrue(resultSet.next());
           Assert.assertEquals(objects[0], resultSet.getLong("Time"));
           Assert.assertEquals(objects[1], resultSet.getString("k1"));
-          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
+          Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)"));
         }
         Assert.assertFalse(resultSet.next());
       }
@@ -386,7 +428,7 @@ public class IoTDBTagAggregationIT {
         "SELECT COUNT(t) from root.sg.** GROUP BY ([0, 20), 10ms), TAGS(k1) ORDER BY TIME DESC";
     // Expected result set:
     // +-----------------------------+----+--------+
-    // |                         Time|  k1|count(t)|
+    // |                         Time|  k1|COUNT(t)|
     // +-----------------------------+----+--------+
     // |1970-01-01T08:00:00.010+08:00|k1v1|       3|
     // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
@@ -412,7 +454,7 @@ public class IoTDBTagAggregationIT {
           Assert.assertTrue(resultSet.next());
           Assert.assertEquals(objects[0], resultSet.getLong("Time"));
           Assert.assertEquals(objects[1], resultSet.getString("k1"));
-          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
+          Assert.assertEquals(objects[2], resultSet.getLong("COUNT(t)"));
         }
         Assert.assertFalse(resultSet.next());
       }
@@ -427,7 +469,7 @@ public class IoTDBTagAggregationIT {
     String query = "SELECT COUNT(t) FROM root.sg.** WHERE time > 1 GROUP BY TAGS(k1)";
     // Expected result set:
     // +----+--------+
-    // |  k1|count(t)|
+    // |  k1|COUNT(t)|
     // +----+--------+
     // |k1v1|       3|
     // |k1v2|       2|
@@ -439,13 +481,13 @@ public class IoTDBTagAggregationIT {
         Assert.assertEquals(2, resultSet.getMetaData().getColumnCount());
         Assert.assertTrue(resultSet.next());
         Assert.assertEquals("k1v1", resultSet.getString("k1"));
-        Assert.assertEquals(3, resultSet.getLong("count(t)"));
+        Assert.assertEquals(3, resultSet.getLong("COUNT(t)"));
         Assert.assertTrue(resultSet.next());
         Assert.assertEquals("k1v2", resultSet.getString("k1"));
-        Assert.assertEquals(2, resultSet.getLong("count(t)"));
+        Assert.assertEquals(2, resultSet.getLong("COUNT(t)"));
         Assert.assertTrue(resultSet.next());
         Assert.assertNull(resultSet.getString("k1"));
-        Assert.assertEquals(2, resultSet.getLong("count(t)"));
+        Assert.assertEquals(2, resultSet.getLong("COUNT(t)"));
         Assert.assertFalse(resultSet.next());
       }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
index dec1ba3ba8..5df0de4175 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
@@ -29,6 +29,7 @@ import org.apache.iotdb.db.mpp.common.NodeRef;
 import org.apache.iotdb.db.mpp.common.header.DatasetHeader;
 import org.apache.iotdb.db.mpp.common.schematree.ISchemaTree;
 import org.apache.iotdb.db.mpp.plan.expression.Expression;
+import org.apache.iotdb.db.mpp.plan.expression.ResultColumn;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.FillDescriptor;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.GroupByTimeParameter;
@@ -39,6 +40,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.read.filter.basic.Filter;
 import org.apache.iotdb.tsfile.utils.Pair;
 
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -74,6 +76,14 @@ public class Analysis {
   // fail.
   private String failMessage;
 
+  // As every result column will be analyzed with path concatenation and wildcard removing to
+  // generate one or more output expressions. We can maintain a map from output expression to
+  // original result column for later use.
+  // Note that if multiple expressions come from one single ResultColumn, the right object's
+  // REFERENCE should be equal, aka outputExpressions.get(i).right ==
+  // outputExpressions.get(j).right, NOT VALUE equal.
+  private List<Pair<Expression, ResultColumn>> outputExpressions = new ArrayList<>();
+
   /////////////////////////////////////////////////////////////////////////////////////////////////
   // Query Analysis (used in ALIGN BY TIME)
   /////////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,7 +106,7 @@ public class Analysis {
   // tag keys specified in `GROUP BY TAG` clause
   private List<String> tagKeys;
 
-  // {tag values -> {grouped expression -> output expressions}}
+  // {tag values -> {grouped expression -> source timeseries expressions}}
   // For different combination of tag keys, the grouped expression may be different. Let's say there
   // are 3 timeseries root.sg.d1.temperature, root.sg.d1.status, root.sg.d2.temperature, and their
   // tags are [k1=v1], [k1=v1] and [k1=v2] respectively. For query "SELECT last_value(**) FROM root
@@ -105,7 +115,7 @@ public class Analysis {
   // Thus, the aggregation results of bucket [v1] and [v2] are different. Bucket [v1] has 2
   // aggregation results last_value(temperature) and last_value(status), whereas bucket [v2] only
   // has [last_value(temperature)].
-  private Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+  private Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
       tagValuesToGroupedTimeseriesOperands;
 
   /////////////////////////////////////////////////////////////////////////////////////////////////
@@ -486,14 +496,22 @@ public class Analysis {
     this.tagKeys = tagKeys;
   }
 
-  public Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+  public Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
       getTagValuesToGroupedTimeseriesOperands() {
     return tagValuesToGroupedTimeseriesOperands;
   }
 
   public void setTagValuesToGroupedTimeseriesOperands(
-      Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+      Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
           tagValuesToGroupedTimeseriesOperands) {
     this.tagValuesToGroupedTimeseriesOperands = tagValuesToGroupedTimeseriesOperands;
   }
+
+  public List<Pair<Expression, ResultColumn>> getOutputExpressions() {
+    return outputExpressions;
+  }
+
+  public void setOutputExpressions(List<Pair<Expression, ResultColumn>> outputExpressions) {
+    this.outputExpressions = outputExpressions;
+  }
 }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
index 6cb199c569..250ad76c79 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
@@ -26,6 +26,7 @@ import org.apache.iotdb.commons.partition.DataPartition;
 import org.apache.iotdb.commons.partition.DataPartitionQueryParam;
 import org.apache.iotdb.commons.partition.SchemaNodeManagementPartition;
 import org.apache.iotdb.commons.partition.SchemaPartition;
+import org.apache.iotdb.commons.path.AlignedPath;
 import org.apache.iotdb.commons.path.MeasurementPath;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.path.PathPatternTree;
@@ -50,6 +51,7 @@ import org.apache.iotdb.db.mpp.plan.Coordinator;
 import org.apache.iotdb.db.mpp.plan.execution.ExecutionResult;
 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.ResultColumn;
 import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
 import org.apache.iotdb.db.mpp.plan.expression.multi.FunctionExpression;
 import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.DeviceViewIntoPathDescriptor;
@@ -64,7 +66,6 @@ import org.apache.iotdb.db.mpp.plan.statement.component.FillComponent;
 import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent;
 import org.apache.iotdb.db.mpp.plan.statement.component.IntoComponent;
 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.SortItem;
 import org.apache.iotdb.db.mpp.plan.statement.component.SortKey;
 import org.apache.iotdb.db.mpp.plan.statement.component.WhereCondition;
@@ -194,7 +195,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
       // concat path and construct path pattern tree
       PathPatternTree patternTree = new PathPatternTree();
       queryStatement =
-          (QueryStatement) new ConcatPathRewriter().rewrite(queryStatement, patternTree);
+          (QueryStatement) new ConcatPathRewriter(analysis).rewrite(queryStatement, patternTree);
       analysis.setStatement(queryStatement);
 
       // request schema fetch API
@@ -229,11 +230,9 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         analyzeOrderBy(analysis, queryStatement);
         return analyzeLast(analysis, schemaTree.getAllMeasurement(), schemaTree);
       }
-
-      List<Pair<Expression, String>> outputExpressions;
       if (queryStatement.isAlignByDevice()) {
         Set<PartialPath> deviceSet = analyzeFrom(queryStatement, schemaTree);
-        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree, deviceSet);
+        analyzeSelect(analysis, queryStatement, schemaTree, deviceSet);
 
         Map<String, Set<Expression>> deviceToAggregationExpressions = new HashMap<>();
         analyzeHaving(
@@ -245,17 +244,17 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         analyzeDeviceToSourceTransform(analysis, queryStatement);
 
         analyzeDeviceToSource(analysis, queryStatement);
-        analyzeDeviceView(analysis, queryStatement, outputExpressions);
+        analyzeDeviceView(analysis, queryStatement);
 
-        analyzeInto(analysis, queryStatement, deviceSet, outputExpressions);
+        analyzeInto(analysis, queryStatement, deviceSet);
       } else {
-        outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree);
+        analyzeSelect(analysis, queryStatement, schemaTree);
 
         analyzeHaving(analysis, queryStatement, schemaTree);
-        analyzeGroupByLevel(analysis, queryStatement, outputExpressions);
-        analyzeGroupByTag(analysis, queryStatement, outputExpressions, schemaTree);
+        analyzeGroupByLevel(analysis, queryStatement);
+        analyzeGroupByTag(analysis, queryStatement, schemaTree);
         Set<Expression> selectExpressions =
-            outputExpressions.stream()
+            analysis.getOutputExpressions().stream()
                 .map(Pair::getLeft)
                 .collect(Collectors.toCollection(LinkedHashSet::new));
         analysis.setSelectExpressions(selectExpressions);
@@ -267,7 +266,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
 
         analyzeSource(analysis, queryStatement);
 
-        analyzeInto(analysis, queryStatement, outputExpressions);
+        analyzeInto(analysis, queryStatement);
       }
 
       analyzeGroupBy(analysis, queryStatement);
@@ -275,7 +274,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
       analyzeFill(analysis, queryStatement);
 
       // generate result set header according to output expressions
-      analyzeOutput(analysis, queryStatement, outputExpressions);
+      analyzeOutput(analysis, queryStatement);
 
       // fetch partition information
       analyzeDataPartition(analysis, queryStatement, schemaTree);
@@ -367,27 +366,25 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     return analysis;
   }
 
-  private List<Pair<Expression, String>> analyzeSelect(
+  private void analyzeSelect(
       Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
-    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
+    List<Pair<Expression, ResultColumn>> outputExpressions = new ArrayList<>();
     boolean isGroupByLevel = queryStatement.isGroupByLevel();
+    boolean isGroupByTag = queryStatement.isGroupByTag();
     ColumnPaginationController paginationController =
         new ColumnPaginationController(
             queryStatement.getSeriesLimit(),
             queryStatement.getSeriesOffset(),
             queryStatement.isLastQuery() || isGroupByLevel);
-
-    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
-      boolean hasAlias = resultColumn.hasAlias();
+    for (Pair<Expression, ResultColumn> resultColumn : analysis.getOutputExpressions()) {
+      boolean hasAlias = resultColumn.getRight().hasAlias();
       List<Expression> resultExpressions =
-          ExpressionAnalyzer.removeWildcardInExpression(resultColumn.getExpression(), schemaTree);
-      if (hasAlias
-          && !queryStatement.isGroupByLevel()
-          && !queryStatement.isGroupByTag()
-          && resultExpressions.size() > 1) {
+          ExpressionAnalyzer.removeWildcardInExpression(resultColumn.getLeft(), schemaTree);
+      if (hasAlias && !isGroupByLevel && !isGroupByTag && resultExpressions.size() > 1) {
         throw new SemanticException(
             String.format(
-                "alias '%s' can only be matched with one time series", resultColumn.getAlias()));
+                "alias '%s' can only be matched with one time series",
+                resultColumn.getRight().getAlias()));
       }
       for (Expression expression : resultExpressions) {
         if (paginationController.hasCurOffset()) {
@@ -397,20 +394,13 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         if (paginationController.hasCurLimit()) {
           if (isGroupByLevel) {
             analyzeExpression(analysis, expression);
-            outputExpressions.add(new Pair<>(expression, resultColumn.getAlias()));
-            queryStatement
-                .getGroupByLevelComponent()
-                .updateIsCountStar(resultColumn.getExpression());
+            outputExpressions.add(new Pair<>(expression, resultColumn.getRight()));
+            queryStatement.getGroupByLevelComponent().updateIsCountStar(resultColumn.getLeft());
           } else {
             Expression expressionWithoutAlias =
                 ExpressionAnalyzer.removeAliasFromExpression(expression);
-            String alias =
-                !Objects.equals(expressionWithoutAlias, expression)
-                    ? expression.getExpressionString()
-                    : null;
-            alias = hasAlias ? resultColumn.getAlias() : alias;
             analyzeExpression(analysis, expressionWithoutAlias);
-            outputExpressions.add(new Pair<>(expressionWithoutAlias, alias));
+            outputExpressions.add(new Pair<>(expressionWithoutAlias, resultColumn.getRight()));
           }
           paginationController.consumeLimit();
         } else {
@@ -418,7 +408,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         }
       }
     }
-    return outputExpressions;
+    analysis.setOutputExpressions(outputExpressions);
   }
 
   private Set<PartialPath> analyzeFrom(QueryStatement queryStatement, ISchemaTree schemaTree) {
@@ -436,21 +426,21 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     return deviceSet;
   }
 
-  private List<Pair<Expression, String>> analyzeSelect(
+  private void analyzeSelect(
       Analysis analysis,
       QueryStatement queryStatement,
       ISchemaTree schemaTree,
       Set<PartialPath> deviceSet) {
-    List<Pair<Expression, String>> outputExpressions = new ArrayList<>();
+    List<Pair<Expression, org.apache.iotdb.db.mpp.plan.expression.ResultColumn>> outputExpressions =
+        new ArrayList<>();
     Map<String, Set<Expression>> deviceToSelectExpressions = new HashMap<>();
 
     ColumnPaginationController paginationController =
         new ColumnPaginationController(
             queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
-
-    for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) {
-      Expression selectExpression = resultColumn.getExpression();
-      boolean hasAlias = resultColumn.hasAlias();
+    for (Pair<Expression, ResultColumn> resultColumn : analysis.getOutputExpressions()) {
+      Expression selectExpression = resultColumn.getLeft();
+      boolean hasAlias = resultColumn.getRight().hasAlias();
 
       // select expression after removing wildcard
       // use LinkedHashMap for order-preserving
@@ -471,7 +461,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
       if (hasAlias && measurementToDeviceSelectExpressions.keySet().size() > 1) {
         throw new SemanticException(
             String.format(
-                "alias '%s' can only be matched with one time series", resultColumn.getAlias()));
+                "alias '%s' can only be matched with one time series",
+                resultColumn.getRight().getAlias()));
       }
 
       for (Expression measurementExpression : measurementToDeviceSelectExpressions.keySet()) {
@@ -494,13 +485,9 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
           // add outputExpressions
           Expression measurementExpressionWithoutAlias =
               ExpressionAnalyzer.removeAliasFromExpression(measurementExpression);
-          String alias =
-              !Objects.equals(measurementExpressionWithoutAlias, measurementExpression)
-                  ? measurementExpression.getExpressionString()
-                  : null;
-          alias = hasAlias ? resultColumn.getAlias() : alias;
           analyzeExpression(analysis, measurementExpressionWithoutAlias);
-          outputExpressions.add(new Pair<>(measurementExpressionWithoutAlias, alias));
+          outputExpressions.add(
+              new Pair<>(measurementExpressionWithoutAlias, resultColumn.getRight()));
 
           // add deviceToSelectExpressions
           for (String deviceName : deviceToSelectExpressionsOfOneMeasurement.keySet()) {
@@ -518,9 +505,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         }
       }
     }
-
+    analysis.setOutputExpressions(outputExpressions);
     analysis.setDeviceToSelectExpressions(deviceToSelectExpressions);
-    return outputExpressions;
   }
 
   private void analyzeHaving(
@@ -584,10 +570,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     analysis.setHavingExpression(havingExpression);
   }
 
-  private void analyzeGroupByLevel(
-      Analysis analysis,
-      QueryStatement queryStatement,
-      List<Pair<Expression, String>> outputExpressions) {
+  private void analyzeGroupByLevel(Analysis analysis, QueryStatement queryStatement) {
     if (!queryStatement.isGroupByLevel()) {
       return;
     }
@@ -596,12 +579,12 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         new GroupByLevelController(queryStatement.getGroupByLevelComponent().getLevels());
 
     Set<Expression> groupedSelectExpressions = new LinkedHashSet<>();
-    for (int i = 0; i < outputExpressions.size(); i++) {
-      Pair<Expression, String> expressionAliasPair = outputExpressions.get(i);
+    for (int i = 0; i < analysis.getOutputExpressions().size(); i++) {
+      Pair<Expression, ResultColumn> expressionAliasPair = analysis.getOutputExpressions().get(i);
       boolean isCountStar = queryStatement.getGroupByLevelComponent().isCountStar(i);
       Expression groupedExpression =
           groupByLevelController.control(
-              isCountStar, expressionAliasPair.left, expressionAliasPair.right);
+              isCountStar, expressionAliasPair.left, expressionAliasPair.right.getAlias());
       groupedSelectExpressions.add(groupedExpression);
     }
 
@@ -617,7 +600,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
           groupByLevelController.getGroupedExpressionToRawExpressionsMap());
     }
 
-    outputExpressions.clear();
+    analysis.getOutputExpressions().clear();
     ColumnPaginationController paginationController =
         new ColumnPaginationController(
             queryStatement.getSeriesLimit(), queryStatement.getSeriesOffset(), false);
@@ -633,7 +616,12 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
                 groupByLevelController.getAlias(groupedExpression.getExpressionString()));
         Expression groupedExpressionWithoutAlias = outputExpression.left;
         analyzeExpression(analysis, groupedExpressionWithoutAlias);
-        outputExpressions.add(outputExpression);
+        analysis
+            .getOutputExpressions()
+            .add(
+                new Pair<>(
+                    outputExpression.getLeft(),
+                    new ResultColumn(outputExpression.getLeft(), outputExpression.getRight())));
         updateGroupByLevelExpressions(
             groupedExpressionWithoutAlias,
             groupByLevelExpressions,
@@ -693,17 +681,14 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
    * <p>TODO: support slimit/soffset/value filter
    */
   private void analyzeGroupByTag(
-      Analysis analysis,
-      QueryStatement queryStatement,
-      List<Pair<Expression, String>> outputExpressions,
-      ISchemaTree schemaTree) {
+      Analysis analysis, QueryStatement queryStatement, ISchemaTree schemaTree) {
     if (!queryStatement.isGroupByTag()) {
       return;
     }
     if (analysis.hasValueFilter()) {
       throw new SemanticException("Only time filters are supported in GROUP BY TAGS query");
     }
-    Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+    Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
         tagValuesToGroupedTimeseriesOperands = new HashMap<>();
     LinkedHashMap<Expression, Set<Expression>> groupByTagOutputExpressions = new LinkedHashMap<>();
     List<String> tagKeys = queryStatement.getGroupByTagComponent().getTagKeys();
@@ -711,62 +696,90 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     Map<MeasurementPath, Map<String, String>> queriedTagMap = new HashMap<>();
     allSelectedPath.forEach(v -> queriedTagMap.put(v, v.getTagMap()));
 
-    for (Pair<Expression, String> outputExpressionAndAlias : outputExpressions) {
-      if (!(outputExpressionAndAlias.getLeft() instanceof FunctionExpression
-          && outputExpressionAndAlias.getLeft().getExpressions().get(0) instanceof TimeSeriesOperand
-          && outputExpressionAndAlias.getLeft().isBuiltInAggregationFunctionExpression())) {
-        throw new SemanticException(
-            outputExpressionAndAlias.getLeft()
-                + " can't be used in group by tag. It will be supported in the future.");
-      }
-      FunctionExpression outputExpression = (FunctionExpression) outputExpressionAndAlias.getLeft();
-      MeasurementPath measurementPath =
-          (MeasurementPath)
-              ((TimeSeriesOperand) outputExpression.getExpressions().get(0)).getPath();
-      MeasurementPath fakePath = null;
-      try {
-        fakePath =
-            new MeasurementPath(measurementPath.getMeasurement(), measurementPath.getSeriesType());
-      } catch (IllegalPathException e) {
-        // do nothing
+    for (Pair<Expression, ResultColumn> pair : analysis.getOutputExpressions()) {
+      List<Expression> aggregationExpressions =
+          ExpressionAnalyzer.searchAggregationExpressions(pair.left);
+      copySeriesDataTypeToExpression(pair.left, pair.right.getExpression());
+      for (Expression exp : aggregationExpressions) {
+        // TODO: avg(s1 + s2) will be supported in the future
+        if (exp.getExpressions().size() > 1) {
+          throw new SemanticException(
+              pair.left + " can't be used in group by tag. It will be supported in the future.");
+        }
+        FunctionExpression outputExpression = (FunctionExpression) exp;
+        MeasurementPath measurementPath =
+            (MeasurementPath)
+                ((TimeSeriesOperand) outputExpression.getExpressions().get(0)).getPath();
+
+        Expression groupedExpression = pair.getRight().getExpression();
+        groupByTagOutputExpressions
+            .computeIfAbsent(groupedExpression, v -> new HashSet<>())
+            .add(exp);
+        Map<String, String> tagMap = queriedTagMap.get(measurementPath);
+        List<String> tagValues = new ArrayList<>();
+        for (String tagKey : tagKeys) {
+          tagValues.add(tagMap.get(tagKey));
+        }
+        tagValuesToGroupedTimeseriesOperands
+            .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
+            .computeIfAbsent(groupedExpression, key -> new HashSet<>())
+            .add(outputExpression.getExpressions().get(0));
       }
-      Expression measurementExpression = new TimeSeriesOperand(fakePath);
-      Expression groupedExpression =
-          new FunctionExpression(
-              outputExpression.getFunctionName(),
-              outputExpression.getFunctionAttributes(),
-              Collections.singletonList(measurementExpression));
-      groupByTagOutputExpressions
-          .computeIfAbsent(groupedExpression, v -> new HashSet<>())
-          .add(outputExpression);
-      Map<String, String> tagMap = queriedTagMap.get(measurementPath);
-      List<String> tagValues = new ArrayList<>();
-      for (String tagKey : tagKeys) {
-        tagValues.add(tagMap.get(tagKey));
+    }
+
+    // Keep the original output columns to the final data set
+    List<Pair<Expression, ResultColumn>> outputColumns = new ArrayList<>();
+    for (int i = 0; i < analysis.getOutputExpressions().size(); i++) {
+      // As the expression's equal() compares the expression string instead, if user inputs 2 same
+      // expressions in the select clause, they may be de-duplicated by the equals() comparison.
+      ResultColumn curRc = analysis.getOutputExpressions().get(i).right;
+      if (i == 0 || curRc != analysis.getOutputExpressions().get(i - 1).right) {
+        analyzeExpression(analysis, curRc.getExpression());
+        outputColumns.add(
+            new Pair<>(
+                curRc.getExpression(), new ResultColumn(curRc.getExpression(), curRc.getAlias())));
       }
-      tagValuesToGroupedTimeseriesOperands
-          .computeIfAbsent(tagValues, key -> new LinkedHashMap<>())
-          .computeIfAbsent(groupedExpression, key -> new ArrayList<>())
-          .add(outputExpression.getExpressions().get(0));
     }
 
-    outputExpressions.clear();
+    analysis.getOutputExpressions().clear();
     for (String tagKey : tagKeys) {
       Expression tagKeyExpression =
           TimeSeriesOperand.constructColumnHeaderExpression(tagKey, TSDataType.TEXT);
       analyzeExpression(analysis, tagKeyExpression);
-      outputExpressions.add(new Pair<>(tagKeyExpression, null));
+      analysis
+          .getOutputExpressions()
+          .add(new Pair<>(tagKeyExpression, new ResultColumn(tagKeyExpression, null)));
     }
     for (Expression groupByTagOutputExpression : groupByTagOutputExpressions.keySet()) {
-      // TODO: support alias
       analyzeExpression(analysis, groupByTagOutputExpression);
-      outputExpressions.add(new Pair<>(groupByTagOutputExpression, null));
     }
+    analysis.getOutputExpressions().addAll(outputColumns);
     analysis.setTagKeys(queryStatement.getGroupByTagComponent().getTagKeys());
     analysis.setTagValuesToGroupedTimeseriesOperands(tagValuesToGroupedTimeseriesOperands);
     analysis.setCrossGroupByExpressions(groupByTagOutputExpressions);
   }
 
+  /**
+   * Copy a measurement type from source expression to target expression recursively. The source and
+   * target expressions should have the same format in expression. e.g. avg(s1) + 1 + sum(s2) has
+   * the same format with avg(root.sg.d1.s1) + 1 + sum(root.sg.d1.s2), but avg(root.sg.d1.s1) + 1 +
+   * min_value(root.sg.d1.s2) doesn't. source should be a {@link MeasurementPath} or {@link
+   * AlignedPath}.
+   */
+  private void copySeriesDataTypeToExpression(Expression source, Expression target) {
+    if (source instanceof TimeSeriesOperand) {
+      TimeSeriesOperand sourceExp = (TimeSeriesOperand) source;
+      TimeSeriesOperand targetExp = (TimeSeriesOperand) target;
+      targetExp.setPath(
+          new MeasurementPath(targetExp.getPath(), sourceExp.getPath().getSeriesType()));
+      return;
+    }
+    for (int i = 0; i < source.getExpressions().size(); i++) {
+      copySeriesDataTypeToExpression(
+          source.getExpressions().get(i), target.getExpressions().get(i));
+    }
+  }
+
   private void analyzeDeviceToAggregation(
       Analysis analysis,
       QueryStatement queryStatement,
@@ -942,10 +955,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         conJunctions.stream().distinct().collect(Collectors.toList()));
   }
 
-  private void analyzeDeviceView(
-      Analysis analysis,
-      QueryStatement queryStatement,
-      List<Pair<Expression, String>> outputExpressions) {
+  private void analyzeDeviceView(Analysis analysis, QueryStatement queryStatement) {
     Expression deviceExpression =
         new TimeSeriesOperand(
             new MeasurementPath(new PartialPath(COLUMN_DEVICE, false), TSDataType.TEXT));
@@ -953,7 +963,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     Set<Expression> selectExpressions = new LinkedHashSet<>();
     selectExpressions.add(deviceExpression);
     selectExpressions.addAll(
-        outputExpressions.stream()
+        analysis.getOutputExpressions().stream()
             .map(Pair::getLeft)
             .collect(Collectors.toCollection(LinkedHashSet::new)));
     analysis.setSelectExpressions(selectExpressions);
@@ -1008,10 +1018,7 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     analysis.setDeviceViewInputIndexesMap(deviceViewInputIndexesMap);
   }
 
-  private void analyzeOutput(
-      Analysis analysis,
-      QueryStatement queryStatement,
-      List<Pair<Expression, String>> outputExpressions) {
+  private void analyzeOutput(Analysis analysis, QueryStatement queryStatement) {
     if (queryStatement.isSelectInto()) {
       analysis.setRespDatasetHeader(
           DatasetHeaderFactory.getSelectIntoHeader(queryStatement.isAlignByDevice()));
@@ -1025,11 +1032,11 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
       columnHeaders.add(new ColumnHeader(COLUMN_DEVICE, TSDataType.TEXT, null));
     }
     columnHeaders.addAll(
-        outputExpressions.stream()
+        analysis.getOutputExpressions().stream()
             .map(
                 expressionAliasPair -> {
                   String columnName = expressionAliasPair.left.getExpressionString();
-                  String alias = expressionAliasPair.right;
+                  String alias = expressionAliasPair.right.getAlias();
                   return new ColumnHeader(
                       columnName, analysis.getType(expressionAliasPair.left), alias);
                 })
@@ -1095,17 +1102,14 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
   }
 
   private void analyzeInto(
-      Analysis analysis,
-      QueryStatement queryStatement,
-      Set<PartialPath> deviceSet,
-      List<Pair<Expression, String>> outputExpressions) {
+      Analysis analysis, QueryStatement queryStatement, Set<PartialPath> deviceSet) {
     if (!queryStatement.isSelectInto()) {
       return;
     }
 
     List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
     List<Expression> sourceColumns =
-        outputExpressions.stream()
+        analysis.getOutputExpressions().stream()
             .map(Pair::getLeft)
             .collect(Collectors.toCollection(ArrayList::new));
 
@@ -1142,16 +1146,13 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     analysis.setDeviceViewIntoPathDescriptor(deviceViewIntoPathDescriptor);
   }
 
-  private void analyzeInto(
-      Analysis analysis,
-      QueryStatement queryStatement,
-      List<Pair<Expression, String>> outputExpressions) {
+  private void analyzeInto(Analysis analysis, QueryStatement queryStatement) {
     if (!queryStatement.isSelectInto()) {
       return;
     }
 
     List<Expression> sourceColumns =
-        outputExpressions.stream()
+        analysis.getOutputExpressions().stream()
             .map(Pair::getLeft)
             .collect(Collectors.toCollection(ArrayList::new));
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java
index 71273d5c12..9a5e6216bc 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/ConcatPathRewriter.java
@@ -27,10 +27,10 @@ import org.apache.iotdb.db.mpp.plan.statement.Statement;
 import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn;
 import org.apache.iotdb.db.mpp.plan.statement.component.SelectComponent;
 import org.apache.iotdb.db.mpp.plan.statement.crud.QueryStatement;
+import org.apache.iotdb.tsfile.utils.Pair;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * This rewriter:
@@ -43,6 +43,11 @@ import java.util.stream.Collectors;
 public class ConcatPathRewriter {
 
   private PathPatternTree patternTree;
+  private final Analysis analysis;
+
+  public ConcatPathRewriter(Analysis analysis) {
+    this.analysis = analysis;
+  }
 
   public Statement rewrite(Statement statement, PathPatternTree patternTree)
       throws StatementAnalyzeException {
@@ -53,12 +58,21 @@ public class ConcatPathRewriter {
     List<PartialPath> prefixPaths = queryStatement.getFromComponent().getPrefixPaths();
 
     if (queryStatement.isAlignByDevice()) {
-      queryStatement.getSelectComponent().getResultColumns().stream()
-          .map(ResultColumn::getExpression)
+      queryStatement
+          .getSelectComponent()
+          .getResultColumns()
           .forEach(
-              expression ->
-                  ExpressionAnalyzer.constructPatternTreeFromExpression(
-                      expression, prefixPaths, patternTree));
+              resultColumn -> {
+                ExpressionAnalyzer.constructPatternTreeFromExpression(
+                    resultColumn.getExpression(), prefixPaths, patternTree);
+                analysis
+                    .getOutputExpressions()
+                    .add(
+                        new Pair<>(
+                            resultColumn.getExpression(),
+                            new org.apache.iotdb.db.mpp.plan.expression.ResultColumn(
+                                resultColumn.getExpression(), resultColumn.getAlias())));
+              });
     } else {
       // concat SELECT with FROM
       List<ResultColumn> resultColumns =
@@ -93,6 +107,9 @@ public class ConcatPathRewriter {
     List<ResultColumn> resultColumns = new ArrayList<>();
     for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
       boolean needAliasCheck = resultColumn.hasAlias() && !isGroupByLevel;
+      org.apache.iotdb.db.mpp.plan.expression.ResultColumn originalResultColumn =
+          new org.apache.iotdb.db.mpp.plan.expression.ResultColumn(
+              resultColumn.getExpression(), resultColumn.getAlias());
       List<Expression> resultExpressions =
           ExpressionAnalyzer.concatExpressionWithSuffixPaths(
               resultColumn.getExpression(), prefixPaths, patternTree);
@@ -101,13 +118,13 @@ public class ConcatPathRewriter {
             String.format(
                 "alias '%s' can only be matched with one time series", resultColumn.getAlias()));
       }
-      resultColumns.addAll(
-          resultExpressions.stream()
-              .map(
-                  expression ->
-                      new ResultColumn(
-                          expression, resultColumn.getAlias(), resultColumn.getColumnType()))
-              .collect(Collectors.toList()));
+      resultExpressions.forEach(
+          expression -> {
+            resultColumns.add(
+                new ResultColumn(
+                    expression, resultColumn.getAlias(), resultColumn.getColumnType()));
+            analysis.getOutputExpressions().add(new Pair<>(expression, originalResultColumn));
+          });
     }
     return resultColumns;
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
index 6f7087c10c..b26276a7c6 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
@@ -223,7 +223,7 @@ public class LogicalPlanBuilder {
       Set<Expression> sourceTransformExpressions,
       LinkedHashMap<Expression, Set<Expression>> crossGroupByAggregations,
       List<String> tagKeys,
-      Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+      Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
           tagValuesToGroupedTimeseriesOperands) {
     boolean needCheckAscending = groupByTimeParameter == null;
     Map<PartialPath, List<AggregationDescriptor>> ascendingAggregations = new HashMap<>();
@@ -400,7 +400,7 @@ public class LogicalPlanBuilder {
       Set<Expression> aggregationExpressions,
       LinkedHashMap<Expression, Set<Expression>> crossGroupByExpressions,
       List<String> tagKeys,
-      Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+      Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
           tagValuesToGroupedTimeseriesOperands) {
     if (curStep.isOutputPartial()) {
       if (groupByTimeParameter != null && groupByTimeParameter.hasOverlap()) {
@@ -645,7 +645,7 @@ public class LogicalPlanBuilder {
 
   private PlanNode createGroupByTagNode(
       List<String> tagKeys,
-      Map<List<String>, LinkedHashMap<Expression, List<Expression>>>
+      Map<List<String>, LinkedHashMap<Expression, Set<Expression>>>
           tagValuesToGroupedTimeseriesOperands,
       Collection<Expression> groupByTagOutputExpressions,
       List<PlanNode> children,
@@ -655,7 +655,7 @@ public class LogicalPlanBuilder {
     SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
         tagValuesToAggregationDescriptors = new TreeMap<>(GroupByTagNode::tagValuesComparator);
     for (List<String> tagValues : tagValuesToGroupedTimeseriesOperands.keySet()) {
-      LinkedHashMap<Expression, List<Expression>> groupedTimeseriesOperands =
+      LinkedHashMap<Expression, Set<Expression>> groupedTimeseriesOperands =
           tagValuesToGroupedTimeseriesOperands.get(tagValues);
       List<CrossSeriesAggregationDescriptor> aggregationDescriptors = new ArrayList<>();
 
@@ -667,12 +667,12 @@ public class LogicalPlanBuilder {
         }
         Expression next = iter.next();
         if (next.equals(groupByTagOutputExpression)) {
-          String functionName = ((FunctionExpression) next).getFunctionName().toUpperCase();
+          String functionName = ((FunctionExpression) next).getFunctionName().toLowerCase();
           CrossSeriesAggregationDescriptor aggregationDescriptor =
               new CrossSeriesAggregationDescriptor(
                   functionName,
                   curStep,
-                  groupedTimeseriesOperands.get(next),
+                  new ArrayList<>(groupedTimeseriesOperands.get(next)),
                   next.getExpressions().get(0));
           aggregationDescriptors.add(aggregationDescriptor);
         } else {
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
index e894c70d06..f6cfa83493 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
@@ -325,7 +325,7 @@ public class QueryStatement extends Statement {
           throw new SemanticException("Raw data and aggregation hybrid query is not supported.");
         }
         outputColumn.add(
-            resultColumn.getAlias() != null
+            resultColumn.hasAlias()
                 ? resultColumn.getAlias()
                 : resultColumn.getExpression().getExpressionString());
       }


[iotdb] 01/03: [IOTDB-4639] Support limit, slimit, offset and soffset in tag aggregation

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ericpai pushed a commit to branch feature/iotdb-4639
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 122bb130058524c97a7ff6e49e152b7fe1ca7efe
Author: ericpai <er...@hotmail.com>
AuthorDate: Fri Oct 14 15:49:29 2022 +0800

    [IOTDB-4639] Support limit, slimit, offset and soffset in tag aggregation
---
 docs/UserGuide/Query-Data/Aggregate-Query.md       |  62 +++--
 docs/zh/UserGuide/Query-Data/Aggregate-Query.md    |  61 +++--
 .../db/it/aggregation/IoTDBTagAggregationIT.java   | 264 +++++++++------------
 .../operator/process/TagAggregationOperator.java   |   2 +-
 .../db/mpp/plan/planner/LogicalPlanBuilder.java    |   6 +-
 .../planner/plan/node/process/GroupByTagNode.java  |  59 ++++-
 .../plan/node/process/GroupByTagNodeSerdeTest.java |  39 ++-
 7 files changed, 303 insertions(+), 190 deletions(-)

diff --git a/docs/UserGuide/Query-Data/Aggregate-Query.md b/docs/UserGuide/Query-Data/Aggregate-Query.md
index b23d21ef38..7b04b13a97 100644
--- a/docs/UserGuide/Query-Data/Aggregate-Query.md
+++ b/docs/UserGuide/Query-Data/Aggregate-Query.md
@@ -540,7 +540,7 @@ The results are
 +--------+------------------+
 | Beijing|104.04666697184244|
 |Shanghai|107.85000076293946|
-|    NULL| 50.84999910990397|
+|    null| 50.84999910990397|
 +--------+------------------+
 Total line number = 3
 It costs 0.231s
@@ -549,7 +549,7 @@ It costs 0.231s
 From the results we can see that the differences between aggregation by tags query and aggregation by time or level query are:
 1. Aggregation query by tags will no longer remove wildcard to raw timeseries, but do the aggregation through the data of multiple timeseries, which have the same tag value.
 2. Except for the aggregate result column, the result set contains the key-value column of the grouped tag. The column name is the tag key, and the values in the column are tag values which present in the searched timeseries.
-If some searched timeseries doesn't have the grouped tag, a `NULL` value in the key-value column of the grouped tag will be presented, which means the aggregation of all the timeseries lacking the tagged key.
+If some searched timeseries doesn't have the grouped tag, a null value in the key-value column of the grouped tag will be presented, which means the aggregation of all the timeseries lacking the tagged key.
 
 ### Aggregation query by multiple tags
 
@@ -571,11 +571,11 @@ The results
 +--------+--------+------------------+
 |    city|workshop|  avg(temperature)|
 +--------+--------+------------------+
-|    NULL|    NULL| 50.84999910990397|
-|Shanghai|      w1|113.01666768391927|
+| Beijing|      w1|103.73750019073486|
 | Beijing|      w2| 104.4000004359654|
+|Shanghai|      w1|113.01666768391927|
 |Shanghai|      w2|100.10000038146973|
-| Beijing|      w1|103.73750019073486|
+|    null|    null| 50.84999910990397|
 +--------+--------+------------------+
 Total line number = 5
 It costs 0.027s
@@ -601,16 +601,51 @@ The results
 +-----------------------------+--------+--------+------------------+
 |                         Time|    city|workshop|  avg(temperature)|
 +-----------------------------+--------+--------+------------------+
-|1970-01-01T08:00:01.000+08:00|    NULL|    NULL| 50.91999893188476|
-|1970-01-01T08:00:01.000+08:00|Shanghai|      w1|113.20000076293945|
+|1970-01-01T08:00:01.000+08:00| Beijing|      w1|103.81666692097981|
 |1970-01-01T08:00:01.000+08:00| Beijing|      w2|             103.4|
+|1970-01-01T08:00:01.000+08:00|Shanghai|      w1|113.20000076293945|
 |1970-01-01T08:00:01.000+08:00|Shanghai|      w2| 100.1999994913737|
-|1970-01-01T08:00:01.000+08:00| Beijing|      w1|103.81666692097981|
-|1970-01-01T08:00:06.000+08:00|    NULL|    NULL|              50.5|
-|1970-01-01T08:00:06.000+08:00|Shanghai|      w1| 112.6500015258789|
+|1970-01-01T08:00:01.000+08:00|    null|    null| 50.91999893188476|
+|1970-01-01T08:00:06.000+08:00| Beijing|      w1|             103.5|
 |1970-01-01T08:00:06.000+08:00| Beijing|      w2| 106.9000015258789|
+|1970-01-01T08:00:06.000+08:00|Shanghai|      w1| 112.6500015258789|
 |1970-01-01T08:00:06.000+08:00|Shanghai|      w2| 99.80000305175781|
+|1970-01-01T08:00:06.000+08:00|    null|    null|              50.5|
++-----------------------------+--------+--------+------------------+
+```
+
+### The Order of the Output of Aggregation Query by Tags
+
+Under one aggregate time window, the tag values are compared one by one according to the keys' order specified in `GROUP BY TAGS`. 
+The order is the one of value string comparison. The string comparison is implemented by [`String::compareTo`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareTo-java.lang.String-) in Java.
+
+When executing an aggregation query based on time window, the `ORDER BY TIME` clause can be added to indicate the time output order. 
+Different time windows will be output in the specified order, and the records in each window will be output in the tag comparison order.
+
+The above query can be output in a time descending order.
+
+SQL
+
+```SQL
+SELECT AVG(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop) ORDER BY TIME DESC;
+```
+
+The results
+
+```
++-----------------------------+--------+--------+------------------+
+|                         Time|    city|workshop|  avg(temperature)|
++-----------------------------+--------+--------+------------------+
 |1970-01-01T08:00:06.000+08:00| Beijing|      w1|             103.5|
+|1970-01-01T08:00:06.000+08:00| Beijing|      w2| 106.9000015258789|
+|1970-01-01T08:00:06.000+08:00|Shanghai|      w1| 112.6500015258789|
+|1970-01-01T08:00:06.000+08:00|Shanghai|      w2| 99.80000305175781|
+|1970-01-01T08:00:06.000+08:00|    null|    null|              50.5|
+|1970-01-01T08:00:01.000+08:00| Beijing|      w1|103.81666692097981|
+|1970-01-01T08:00:01.000+08:00| Beijing|      w2|             103.4|
+|1970-01-01T08:00:01.000+08:00|Shanghai|      w1|113.20000076293945|
+|1970-01-01T08:00:01.000+08:00|Shanghai|      w2| 100.1999994913737|
+|1970-01-01T08:00:01.000+08:00|    null|    null| 50.91999893188476|
 +-----------------------------+--------+--------+------------------+
 ```
 
@@ -623,10 +658,9 @@ As this feature is still under development, some queries have not been completed
 
 > 1. Temporarily not support `HAVING` clause to filter the results.
 > 2. Temporarily not support ordering by tag values.
-> 3. Temporarily not support `LIMIT`,`OFFSET`,`SLIMIT`,`SOFFSET`.
-> 4. Temporarily not support `ALIGN BY DEVICE`.
-> 5. Temporarily not support expressions as aggregation function parameter,e.g. `count(s+1)`.
-> 6. Not support the value filter, which stands the same with the `GROUP BY LEVEL` query.
+> 3. Temporarily not support `ALIGN BY DEVICE`.
+> 4. Temporarily not support expressions as aggregation function parameter,e.g. `count(s+1)`.
+> 5. Not support the value filter, which stands the same with the `GROUP BY LEVEL` query.
 
 ## Aggregate result filtering
 
diff --git a/docs/zh/UserGuide/Query-Data/Aggregate-Query.md b/docs/zh/UserGuide/Query-Data/Aggregate-Query.md
index db44805857..269cd601fc 100644
--- a/docs/zh/UserGuide/Query-Data/Aggregate-Query.md
+++ b/docs/zh/UserGuide/Query-Data/Aggregate-Query.md
@@ -529,7 +529,7 @@ SELECT AVG(temperature) FROM root.factory1.** GROUP BY TAGS(city);
 +--------+------------------+
 | Beijing|104.04666697184244|
 |Shanghai|107.85000076293946|
-|    NULL| 50.84999910990397|
+|    null| 50.84999910990397|
 +--------+------------------+
 Total line number = 3
 It costs 0.231s
@@ -538,7 +538,7 @@ It costs 0.231s
 从结果集中可以看到,和时间区间聚合、按层次聚合相比,标签聚合的查询结果的不同点是:
 1. 标签聚合查询的聚合结果不会再做去星号展开,而是将多个时间序列的数据作为一个整体进行聚合计算。
 2. 标签聚合查询除了输出聚合结果列,还会输出聚合标签的键值列。该列的列名为聚合指定的标签键,列的值则为所有查询的时间序列中出现的该标签的值。
-如果某些时间序列未设置该标签,则在键值列中有一行单独的 `NULL` ,代表未设置标签的所有时间序列数据的聚合结果。
+如果某些时间序列未设置该标签,则在键值列中有一行单独空值 ,代表未设置标签的所有时间序列数据的聚合结果。
 
 ### 多标签聚合查询
 
@@ -558,11 +558,11 @@ SELECT avg(temperature) FROM root.factory1.** GROUP BY TAGS(city, workshop);
 +--------+--------+------------------+
 |    city|workshop|  avg(temperature)|
 +--------+--------+------------------+
-|    NULL|    NULL| 50.84999910990397|
-|Shanghai|      w1|113.01666768391927|
+| Beijing|      w1|103.73750019073486|
 | Beijing|      w2| 104.4000004359654|
+|Shanghai|      w1|113.01666768391927|
 |Shanghai|      w2|100.10000038146973|
-| Beijing|      w1|103.73750019073486|
+|    null|    null| 50.84999910990397|
 +--------+--------+------------------+
 Total line number = 5
 It costs 0.027s
@@ -588,31 +588,62 @@ SELECT AVG(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS
 +-----------------------------+--------+--------+------------------+
 |                         Time|    city|workshop|  avg(temperature)|
 +-----------------------------+--------+--------+------------------+
-|1970-01-01T08:00:01.000+08:00|    NULL|    NULL| 50.91999893188476|
-|1970-01-01T08:00:01.000+08:00|Shanghai|      w1|113.20000076293945|
+|1970-01-01T08:00:01.000+08:00| Beijing|      w1|103.81666692097981|
 |1970-01-01T08:00:01.000+08:00| Beijing|      w2|             103.4|
+|1970-01-01T08:00:01.000+08:00|Shanghai|      w1|113.20000076293945|
 |1970-01-01T08:00:01.000+08:00|Shanghai|      w2| 100.1999994913737|
-|1970-01-01T08:00:01.000+08:00| Beijing|      w1|103.81666692097981|
-|1970-01-01T08:00:06.000+08:00|    NULL|    NULL|              50.5|
-|1970-01-01T08:00:06.000+08:00|Shanghai|      w1| 112.6500015258789|
+|1970-01-01T08:00:01.000+08:00|    null|    null| 50.91999893188476|
+|1970-01-01T08:00:06.000+08:00| Beijing|      w1|             103.5|
 |1970-01-01T08:00:06.000+08:00| Beijing|      w2| 106.9000015258789|
+|1970-01-01T08:00:06.000+08:00|Shanghai|      w1| 112.6500015258789|
 |1970-01-01T08:00:06.000+08:00|Shanghai|      w2| 99.80000305175781|
-|1970-01-01T08:00:06.000+08:00| Beijing|      w1|             103.5|
+|1970-01-01T08:00:06.000+08:00|    null|    null|              50.5|
 +-----------------------------+--------+--------+------------------+
 ```
 
 和标签聚合相比,基于时间区间的标签聚合的查询会首先按照时间区间划定聚合范围,在时间区间内部再根据指定的标签顺序,进行相应数据的聚合计算。在输出的结果集中,会包含一列时间列,该时间列值的含义和时间区间聚合查询的相同。
 
+### 标签聚合查询输出结果顺序
+
+在同聚合时间区间中,按照 `GROUP BY TAGS` 中指定的标签键依次比较,输出顺序为字符串的比较顺序。
+字符串的比较方式通过 Java 中的 [`String::compareTo`](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#compareTo-java.lang.String-) 实现。
+使用基于时间区间的聚合查询时,可以通过 `ORDER BY TIME` 指定时间顺序,时间区间按照指定的时间顺序输出,时间区间内仍然按照标签比较顺序输出。
+
+例如,上面的查询可以按照时间序列倒序输出
+
+SQL 语句如下
+
+```SQL
+SELECT AVG(temperature) FROM root.factory1.** GROUP BY ([1000, 10000), 5s), TAGS(city, workshop) ORDER BY TIME DESC;
+```
+
+查询结果如下
+
+```
++-----------------------------+--------+--------+------------------+
+|                         Time|    city|workshop|  avg(temperature)|
++-----------------------------+--------+--------+------------------+
+|1970-01-01T08:00:06.000+08:00| Beijing|      w1|             103.5|
+|1970-01-01T08:00:06.000+08:00| Beijing|      w2| 106.9000015258789|
+|1970-01-01T08:00:06.000+08:00|Shanghai|      w1| 112.6500015258789|
+|1970-01-01T08:00:06.000+08:00|Shanghai|      w2| 99.80000305175781|
+|1970-01-01T08:00:06.000+08:00|    null|    null|              50.5|
+|1970-01-01T08:00:01.000+08:00| Beijing|      w1|103.81666692097981|
+|1970-01-01T08:00:01.000+08:00| Beijing|      w2|             103.4|
+|1970-01-01T08:00:01.000+08:00|Shanghai|      w1|113.20000076293945|
+|1970-01-01T08:00:01.000+08:00|Shanghai|      w2| 100.1999994913737|
+|1970-01-01T08:00:01.000+08:00|    null|    null| 50.91999893188476|
++-----------------------------+--------+--------+------------------+
+```
 ### 标签聚合查询的限制
 
 由于标签聚合功能仍然处于开发阶段,目前有如下未实现功能。
 
 > 1. 暂不支持 `HAVING` 子句过滤查询结果。
 > 2. 暂不支持结果按照标签值排序。
-> 3. 暂不支持 `LIMIT`,`OFFSET`,`SLIMIT`,`SOFFSET`。
-> 4. 暂不支持 `ALIGN BY DEVICE`。
-> 5. 暂不支持聚合函数内部包含表达式,例如 `count(s+1)`。
-> 6. 不支持值过滤条件聚合,和分层聚合查询行为保持一致。
+> 3. 暂不支持 `ALIGN BY DEVICE`。
+> 4. 暂不支持聚合函数内部包含表达式,例如 `count(s+1)`。
+> 5. 不支持值过滤条件聚合,和分层聚合查询行为保持一致。
 
 ## 聚合结果过滤
 
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java
index e679657064..c481ca9718 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aggregation/IoTDBTagAggregationIT.java
@@ -35,10 +35,6 @@ import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
 
 import static org.junit.Assert.fail;
 
@@ -105,11 +101,11 @@ public class IoTDBTagAggregationIT {
     // |  k1|count(t)|
     // avg(t)|max_time(t)|min_time(t)|max_value(t)|min_value(t)|extreme(t)|
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
-    // |k1v2|       4|3.1000000536441803|         10|          1|         5.4|         1.3|
-    // 5.4|
     // |k1v1|       6| 2.600000003973643|         10|          1|         6.5|         1.1|
     // 6.5|
-    // |NULL|       4|  4.89999994635582|         10|          1|         8.7|         1.6|
+    // |k1v2|       4|3.1000000536441803|         10|          1|         5.4|         1.3|
+    // 5.4|
+    // |null|       4|  4.89999994635582|         10|          1|         8.7|         1.6|
     // 8.7|
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -117,15 +113,6 @@ public class IoTDBTagAggregationIT {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(8, resultSet.getMetaData().getColumnCount());
         Assert.assertTrue(resultSet.next());
-        Assert.assertEquals("k1v2", resultSet.getString("k1"));
-        Assert.assertEquals(4L, resultSet.getLong("count(t)"));
-        Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA);
-        Assert.assertEquals(10L, resultSet.getLong("max_time(t)"));
-        Assert.assertEquals(1L, resultSet.getLong("min_time(t)"));
-        Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA);
-        Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
-        Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
-        Assert.assertTrue(resultSet.next());
         Assert.assertEquals("k1v1", resultSet.getString(1));
         Assert.assertEquals(6L, resultSet.getLong(2));
         Assert.assertEquals(2.6D, resultSet.getDouble(3), DELTA);
@@ -135,7 +122,16 @@ public class IoTDBTagAggregationIT {
         Assert.assertEquals(1.1F, resultSet.getFloat(7), DELTA);
         Assert.assertEquals(6.5F, resultSet.getFloat(8), DELTA);
         Assert.assertTrue(resultSet.next());
-        Assert.assertEquals("NULL", resultSet.getString(1));
+        Assert.assertEquals("k1v2", resultSet.getString("k1"));
+        Assert.assertEquals(4L, resultSet.getLong("count(t)"));
+        Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA);
+        Assert.assertEquals(10L, resultSet.getLong("max_time(t)"));
+        Assert.assertEquals(1L, resultSet.getLong("min_time(t)"));
+        Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA);
+        Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
+        Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
+        Assert.assertTrue(resultSet.next());
+        Assert.assertNull(resultSet.getString(1));
         Assert.assertEquals(4L, resultSet.getLong(2));
         Assert.assertEquals(4.9D, resultSet.getDouble(3), DELTA);
         Assert.assertEquals(10L, resultSet.getLong(4));
@@ -159,24 +155,15 @@ public class IoTDBTagAggregationIT {
     // +----+------------+------------------+
     // |  k1|count(t + 1)|        avg(t + 1)|
     // +----+------------+------------------+
-    // |k1v2|           4|3.1000000536441803|
     // |k1v1|           6| 3.600000003973643|
-    // |NULL|           4|  5.89999994635582|
+    // |k1v2|           4|3.1000000536441803|
+    // |null|           4|  5.89999994635582|
     // +----+------------+------------------+
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(8, resultSet.getMetaData().getColumnCount());
         Assert.assertTrue(resultSet.next());
-        Assert.assertEquals("k1v2", resultSet.getString("k1"));
-        Assert.assertEquals(4L, resultSet.getLong("count(t)"));
-        Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA);
-        Assert.assertEquals(10L, resultSet.getLong("max_time(t)"));
-        Assert.assertEquals(1L, resultSet.getLong("min_time(t)"));
-        Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA);
-        Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
-        Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
-        Assert.assertTrue(resultSet.next());
         Assert.assertEquals("k1v1", resultSet.getString(1));
         Assert.assertEquals(6L, resultSet.getLong(2));
         Assert.assertEquals(2.6D, resultSet.getDouble(3), DELTA);
@@ -186,7 +173,16 @@ public class IoTDBTagAggregationIT {
         Assert.assertEquals(1.1F, resultSet.getFloat(7), DELTA);
         Assert.assertEquals(6.5F, resultSet.getFloat(8), DELTA);
         Assert.assertTrue(resultSet.next());
-        Assert.assertEquals("NULL", resultSet.getString(1));
+        Assert.assertEquals("k1v2", resultSet.getString("k1"));
+        Assert.assertEquals(4L, resultSet.getLong("count(t)"));
+        Assert.assertEquals(3.1D, resultSet.getDouble("avg(t)"), DELTA);
+        Assert.assertEquals(10L, resultSet.getLong("max_time(t)"));
+        Assert.assertEquals(1L, resultSet.getLong("min_time(t)"));
+        Assert.assertEquals(5.4F, resultSet.getFloat("max_value(t)"), DELTA);
+        Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
+        Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
+        Assert.assertTrue(resultSet.next());
+        Assert.assertNull(resultSet.getString(1));
         Assert.assertEquals(4L, resultSet.getLong(2));
         Assert.assertEquals(4.9D, resultSet.getDouble(3), DELTA);
         Assert.assertEquals(10L, resultSet.getLong(4));
@@ -214,7 +210,7 @@ public class IoTDBTagAggregationIT {
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
     // |k1v2|       4|3.1000000536441803|         10|          1|         5.4|         1.3|
     // 5.4|
-    // |NULL|       4|  4.89999994635582|         10|          1|         8.7|         1.6|
+    // |null|       4|  4.89999994635582|         10|          1|         8.7|         1.6|
     // 8.7|
     // +----+--------+------------------+-----------+-----------+------------+------------+----------+
     try (Connection connection = EnvFactory.getEnv().getConnection();
@@ -231,7 +227,7 @@ public class IoTDBTagAggregationIT {
         Assert.assertEquals(1.3F, resultSet.getFloat("min_value(t)"), DELTA);
         Assert.assertEquals(5.4F, resultSet.getFloat("extreme(t)"), DELTA);
         Assert.assertTrue(resultSet.next());
-        Assert.assertEquals("NULL", resultSet.getString(1));
+        Assert.assertNull(resultSet.getString(1));
         Assert.assertEquals(4L, resultSet.getLong(2));
         Assert.assertEquals(4.9D, resultSet.getDouble(3), DELTA);
         Assert.assertEquals(10L, resultSet.getLong(4));
@@ -254,29 +250,35 @@ public class IoTDBTagAggregationIT {
     // +----+----+--------+
     // |  k1|  k2|count(t)|
     // +----+----+--------+
-    // |NULL|NULL|       2|
-    // |NULL|k2v1|       2|
-    // |k1v1|NULL|       2|
-    // |k1v2|k2v1|       2|
-    // |k1v1|k2v2|       2|
     // |k1v1|k2v1|       2|
+    // |k1v1|k2v2|       2|
+    // |k1v1|null|       2|
+    // |k1v2|k2v1|       2|
     // |k1v2|k2v2|       2|
+    // |null|k2v1|       2|
+    // |null|null|       2|
     // +----+----+--------+
+    Object[][] expected =
+        new Object[][] {
+          {"k1v1", "k2v1", 2L},
+          {"k1v1", "k2v2", 2L},
+          {"k1v1", null, 2L},
+          {"k1v2", "k2v1", 2L},
+          {"k1v2", "k2v2", 2L},
+          {null, "k2v1", 2L},
+          {null, null, 2L},
+        };
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(3, resultSet.getMetaData().getColumnCount());
-        Set<List<String>> groups = new HashSet<>();
-        for (int i = 0; i < 7; i++) {
+        for (Object[] objects : expected) {
           Assert.assertTrue(resultSet.next());
-          List<String> tagValues = new ArrayList<>(2);
-          tagValues.add(resultSet.getString("k1"));
-          tagValues.add(resultSet.getString("k2"));
-          groups.add(tagValues);
-          Assert.assertEquals(2L, resultSet.getLong("count(t)"));
+          Assert.assertEquals(objects[0], resultSet.getString("k1"));
+          Assert.assertEquals(objects[1], resultSet.getString("k2"));
+          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
         }
         Assert.assertFalse(resultSet.next());
-        Assert.assertEquals(7, groups.size());
       }
     } catch (SQLException e) {
       e.printStackTrace();
@@ -291,42 +293,32 @@ public class IoTDBTagAggregationIT {
     // +-----------------------------+----+--------+
     // |                         Time|  k1|count(t)|
     // +-----------------------------+----+--------+
-    // |1970-01-01T08:00:00.000+08:00|k1v2|       2|
     // |1970-01-01T08:00:00.000+08:00|k1v1|       3|
-    // |1970-01-01T08:00:00.000+08:00|NULL|       2|
-    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.000+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.000+08:00|null|       2|
     // |1970-01-01T08:00:00.010+08:00|k1v1|       3|
-    // |1970-01-01T08:00:00.010+08:00|NULL|       2|
+    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.010+08:00|null|       2|
     // +-----------------------------+----+--------+
+    Object[][] expected =
+        new Object[][] {
+          {0L, "k1v1", 3L},
+          {0L, "k1v2", 2L},
+          {0L, null, 2L},
+          {10L, "k1v1", 3L},
+          {10L, "k1v2", 2L},
+          {10L, null, 2L},
+        };
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(3, resultSet.getMetaData().getColumnCount());
-        Set<String> groups = new HashSet<>();
-        for (int i = 0; i < 6; i++) {
+        for (Object[] objects : expected) {
           Assert.assertTrue(resultSet.next());
-          if (i < 3) {
-            Assert.assertEquals(0L, resultSet.getLong("Time"));
-          } else {
-            Assert.assertEquals(10L, resultSet.getLong("Time"));
-          }
-          String tagValue = resultSet.getString("k1");
-          switch (tagValue) {
-            case "k1v1":
-              Assert.assertEquals(3L, resultSet.getLong("count(t)"));
-              break;
-            case "k1v2":
-              Assert.assertEquals(2L, resultSet.getLong("count(t)"));
-              break;
-            case "NULL":
-              Assert.assertEquals(2L, resultSet.getLong("count(t)"));
-              break;
-            default:
-              fail("Unexpected tag value: " + tagValue);
-          }
-          groups.add(tagValue);
+          Assert.assertEquals(objects[0], resultSet.getLong("Time"));
+          Assert.assertEquals(objects[1], resultSet.getString("k1"));
+          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
         }
-        Assert.assertEquals(3, groups.size());
         Assert.assertFalse(resultSet.next());
       }
     } catch (SQLException e) {
@@ -342,48 +334,48 @@ public class IoTDBTagAggregationIT {
     // +-----------------------------+----+--------+
     // |                         Time|  k1|count(t)|
     // +-----------------------------+----+--------+
-    // |1970-01-01T08:00:00.000+08:00|k1v2|       4|
     // |1970-01-01T08:00:00.000+08:00|k1v1|       6|
-    // |1970-01-01T08:00:00.000+08:00|NULL|       4|
-    // |1970-01-01T08:00:00.005+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.000+08:00|k1v2|       4|
+    // |1970-01-01T08:00:00.000+08:00|null|       4|
     // |1970-01-01T08:00:00.005+08:00|k1v1|       3|
-    // |1970-01-01T08:00:00.005+08:00|NULL|       2|
-    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.005+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.005+08:00|null|       2|
     // |1970-01-01T08:00:00.010+08:00|k1v1|       3|
-    // |1970-01-01T08:00:00.010+08:00|NULL|       2|
-    // |1970-01-01T08:00:00.015+08:00|k1v2|       0|
+    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
+    // |1970-01-01T08:00:00.010+08:00|null|       2|
     // |1970-01-01T08:00:00.015+08:00|k1v1|       0|
-    // |1970-01-01T08:00:00.015+08:00|NULL|       0|
+    // |1970-01-01T08:00:00.015+08:00|k1v2|       0|
+    // |1970-01-01T08:00:00.015+08:00|null|       0|
     // +-----------------------------+----+--------+
-    long[][] expectedValue = new long[][] {{4L, 6L, 4L}, {2L, 3L, 2L}, {2L, 3L, 2L}, {0L, 0L, 0L}};
-    long[] expectedTime = new long[] {0L, 5L, 10L, 15L};
+    Object[][] expected =
+        new Object[][] {
+          {0L, "k1v1", 6L},
+          {0L, "k1v2", 4L},
+          {0L, null, 4L},
+          {5L, "k1v1", 3L},
+          {5L, "k1v2", 2L},
+          {5L, null, 2L},
+          {10L, "k1v1", 3L},
+          {10L, "k1v2", 2L},
+          {10L, null, 2L},
+          {15L, "k1v1", 0L},
+          {15L, "k1v2", 0L},
+          {15L, null, 0L},
+        };
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(3, resultSet.getMetaData().getColumnCount());
-        for (int i = 0; i < 4; i++) {
-          for (int j = 0; j < 3; j++) {
-            Assert.assertTrue(resultSet.next());
-            String tagValue = resultSet.getString("k1");
-            switch (tagValue) {
-              case "k1v2":
-                Assert.assertEquals(expectedTime[i], resultSet.getLong("Time"));
-                Assert.assertEquals(expectedValue[i][0], resultSet.getLong("count(t)"));
-                break;
-              case "k1v1":
-                Assert.assertEquals(expectedValue[i][1], resultSet.getLong("count(t)"));
-                break;
-              case "NULL":
-                Assert.assertEquals(expectedValue[i][2], resultSet.getLong("count(t)"));
-                break;
-              default:
-                fail("Unexpected tag value: " + tagValue);
-            }
-          }
+        for (Object[] objects : expected) {
+          Assert.assertTrue(resultSet.next());
+          Assert.assertEquals(objects[0], resultSet.getLong("Time"));
+          Assert.assertEquals(objects[1], resultSet.getString("k1"));
+          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
         }
         Assert.assertFalse(resultSet.next());
       }
     } catch (SQLException e) {
+      e.printStackTrace();
       fail(e.getMessage());
     }
   }
@@ -396,42 +388,32 @@ public class IoTDBTagAggregationIT {
     // +-----------------------------+----+--------+
     // |                         Time|  k1|count(t)|
     // +-----------------------------+----+--------+
-    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
     // |1970-01-01T08:00:00.010+08:00|k1v1|       3|
+    // |1970-01-01T08:00:00.010+08:00|k1v2|       2|
     // |1970-01-01T08:00:00.010+08:00|NULL|       2|
-    // |1970-01-01T08:00:00.000+08:00|k1v2|       2|
     // |1970-01-01T08:00:00.000+08:00|k1v1|       3|
+    // |1970-01-01T08:00:00.000+08:00|k1v2|       2|
     // |1970-01-01T08:00:00.000+08:00|NULL|       2|
     // +-----------------------------+----+--------+
+    Object[][] expected =
+        new Object[][] {
+          {10L, "k1v1", 3L},
+          {10L, "k1v2", 2L},
+          {10L, null, 2L},
+          {0L, "k1v1", 3L},
+          {0L, "k1v2", 2L},
+          {0L, null, 2L},
+        };
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(3, resultSet.getMetaData().getColumnCount());
-        Set<String> groups = new HashSet<>();
-        for (int i = 0; i < 6; i++) {
+        for (Object[] objects : expected) {
           Assert.assertTrue(resultSet.next());
-          if (i < 3) {
-            Assert.assertEquals(10L, resultSet.getLong("Time"));
-          } else {
-            Assert.assertEquals(0L, resultSet.getLong("Time"));
-          }
-          String tagValue = resultSet.getString("k1");
-          switch (tagValue) {
-            case "k1v1":
-              Assert.assertEquals(3L, resultSet.getLong("count(t)"));
-              break;
-            case "k1v2":
-              Assert.assertEquals(2L, resultSet.getLong("count(t)"));
-              break;
-            case "NULL":
-              Assert.assertEquals(2L, resultSet.getLong("count(t)"));
-              break;
-            default:
-              fail("Unexpected tag value: " + tagValue);
-          }
-          groups.add(tagValue);
+          Assert.assertEquals(objects[0], resultSet.getLong("Time"));
+          Assert.assertEquals(objects[1], resultSet.getString("k1"));
+          Assert.assertEquals(objects[2], resultSet.getLong("count(t)"));
         }
-        Assert.assertEquals(3, groups.size());
         Assert.assertFalse(resultSet.next());
       }
     } catch (SQLException e) {
@@ -447,36 +429,26 @@ public class IoTDBTagAggregationIT {
     // +----+--------+
     // |  k1|count(t)|
     // +----+--------+
-    // |k1v2|       2|
     // |k1v1|       3|
+    // |k1v2|       2|
     // |NULL|       2|
     // +----+--------+
     try (Connection connection = EnvFactory.getEnv().getConnection();
         Statement statement = connection.createStatement()) {
       try (ResultSet resultSet = statement.executeQuery(query)) {
         Assert.assertEquals(2, resultSet.getMetaData().getColumnCount());
-        Set<String> groups = new HashSet<>();
-        for (int i = 0; i < 3; i++) {
-          Assert.assertTrue(resultSet.next());
-          String tagValue = resultSet.getString("k1");
-          switch (tagValue) {
-            case "k1v1":
-              Assert.assertEquals(3L, resultSet.getLong("count(t)"));
-              break;
-            case "k1v2":
-              Assert.assertEquals(2L, resultSet.getLong("count(t)"));
-              break;
-            case "NULL":
-              Assert.assertEquals(2L, resultSet.getLong("count(t)"));
-              break;
-            default:
-              fail("Unexpected tag value: " + tagValue);
-          }
-          groups.add(tagValue);
-        }
-        Assert.assertEquals(3, groups.size());
+        Assert.assertTrue(resultSet.next());
+        Assert.assertEquals("k1v1", resultSet.getString("k1"));
+        Assert.assertEquals(3, resultSet.getLong("count(t)"));
+        Assert.assertTrue(resultSet.next());
+        Assert.assertEquals("k1v2", resultSet.getString("k1"));
+        Assert.assertEquals(2, resultSet.getLong("count(t)"));
+        Assert.assertTrue(resultSet.next());
+        Assert.assertNull(resultSet.getString("k1"));
+        Assert.assertEquals(2, resultSet.getLong("count(t)"));
         Assert.assertFalse(resultSet.next());
       }
+
     } catch (SQLException e) {
       e.printStackTrace();
       fail(e.getMessage());
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/TagAggregationOperator.java b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/TagAggregationOperator.java
index 4abbd1dcb3..8ebc3716c5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/TagAggregationOperator.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/execution/operator/process/TagAggregationOperator.java
@@ -151,7 +151,7 @@ public class TagAggregationOperator implements ProcessOperator {
 
       for (int i = 0; i < group.size(); i++) {
         if (group.get(i) == null) {
-          columnBuilders[i].writeBinary(new Binary("NULL"));
+          columnBuilders[i].appendNull();
         } else {
           columnBuilders[i].writeBinary(new Binary(group.get(i)));
         }
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
index 31643cd550..6f7087c10c 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/LogicalPlanBuilder.java
@@ -98,6 +98,8 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -650,8 +652,8 @@ public class LogicalPlanBuilder {
       AggregationStep curStep,
       GroupByTimeParameter groupByTimeParameter,
       Ordering scanOrder) {
-    Map<List<String>, List<CrossSeriesAggregationDescriptor>> tagValuesToAggregationDescriptors =
-        new HashMap<>();
+    SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
+        tagValuesToAggregationDescriptors = new TreeMap<>(GroupByTagNode::tagValuesComparator);
     for (List<String> tagValues : tagValuesToGroupedTimeseriesOperands.keySet()) {
       LinkedHashMap<Expression, List<Expression>> groupedTimeseriesOperands =
           tagValuesToGroupedTimeseriesOperands.get(tagValues);
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByTagNode.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByTagNode.java
index e0ef548508..c8c03b024d 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByTagNode.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/planner/plan/node/process/GroupByTagNode.java
@@ -36,18 +36,23 @@ import java.io.DataOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import java.util.stream.Collectors;
 
 public class GroupByTagNode extends MultiChildNode {
 
   private final List<String> tagKeys;
-  private final Map<List<String>, List<CrossSeriesAggregationDescriptor>>
+
+  /**
+   * the tag values should be in a deterministic order so that the output is deterministic as well.
+   */
+  private final SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
       tagValuesToAggregationDescriptors;
+
   private final List<String> outputColumnNames;
 
   // The parameter of `group by time`.
@@ -62,7 +67,8 @@ public class GroupByTagNode extends MultiChildNode {
       @Nullable GroupByTimeParameter groupByTimeParameter,
       Ordering scanOrder,
       List<String> tagKeys,
-      Map<List<String>, List<CrossSeriesAggregationDescriptor>> tagValuesToAggregationDescriptors,
+      SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
+          tagValuesToAggregationDescriptors,
       List<String> outputColumnNames) {
     super(id, children);
     this.groupByTimeParameter = groupByTimeParameter;
@@ -77,7 +83,8 @@ public class GroupByTagNode extends MultiChildNode {
       @Nullable GroupByTimeParameter groupByTimeParameter,
       Ordering scanOrder,
       List<String> tagKeys,
-      Map<List<String>, List<CrossSeriesAggregationDescriptor>> tagValuesToAggregationDescriptors,
+      SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
+          tagValuesToAggregationDescriptors,
       List<String> outputColumnNames) {
     super(id);
     this.groupByTimeParameter = groupByTimeParameter;
@@ -217,7 +224,7 @@ public class GroupByTagNode extends MultiChildNode {
     return tagKeys;
   }
 
-  public Map<List<String>, List<CrossSeriesAggregationDescriptor>>
+  public SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
       getTagValuesToAggregationDescriptors() {
     return tagValuesToAggregationDescriptors;
   }
@@ -228,8 +235,8 @@ public class GroupByTagNode extends MultiChildNode {
 
     // Tag values to aggregation descriptors.
     int numOfEntries = ReadWriteIOUtils.readInt(byteBuffer);
-    Map<List<String>, List<CrossSeriesAggregationDescriptor>> tagValuesToAggregationDescriptors =
-        new HashMap<>();
+    SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
+        tagValuesToAggregationDescriptors = new TreeMap<>(GroupByTagNode::tagValuesComparator);
     while (numOfEntries > 0) {
       List<String> tagValues = ReadWriteIOUtils.readStringList(byteBuffer);
       List<CrossSeriesAggregationDescriptor> aggregationDescriptors = new ArrayList<>();
@@ -309,4 +316,40 @@ public class GroupByTagNode extends MultiChildNode {
                 list -> list.stream().map(CrossSeriesAggregationDescriptor::getInputExpressions))
             .collect(Collectors.toList()));
   }
+
+  /**
+   * The comparator of tag values in GROUP BY tag query, it uses the following rules to sort:
+   *
+   * <p>1. As each group of tag values must have the same length, so there's no need to compare the
+   * size of the lists.
+   *
+   * <p>2. Let v1(i) be the ith element in v1, then v1 < v2 iff there exists any i (0 <= i <
+   * len(v1)) that
+   *
+   * <ul>
+   *   <li>a. v1(j) == v2(j) when 0 <= j < i, and
+   *   <li>b. v1(i) < v2(i) in natual order of String, or
+   *       <ul>
+   *         <li>b1. v1(i) != null and v2(i) == null.
+   *       </ul>
+   * </ul>
+   *
+   * <p>The NULL value will be output in the last of every in-series aggregation group.
+   */
+  public static int tagValuesComparator(List<String> v1, List<String> v2) {
+    Validate.isTrue(v1.size() == v2.size());
+    for (int i = 0; i < v1.size(); i++) {
+      if (Objects.equals(v1.get(i), v2.get(i))) {
+        continue;
+      }
+      if (v2.get(i) == null) {
+        return -1;
+      }
+      if (v1.get(i) == null) {
+        return 1;
+      }
+      return v1.get(i).compareTo(v2.get(i));
+    }
+    return 0;
+  }
 }
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/process/GroupByTagNodeSerdeTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/process/GroupByTagNodeSerdeTest.java
index feaaf4fcaa..378c1facd2 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/process/GroupByTagNodeSerdeTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/node/process/GroupByTagNodeSerdeTest.java
@@ -34,6 +34,7 @@ import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.GroupByTimeParameter;
 import org.apache.iotdb.db.mpp.plan.statement.component.Ordering;
 import org.apache.iotdb.db.query.aggregation.AggregationType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.utils.Pair;
 
 import org.junit.Assert;
 import org.junit.Test;
@@ -44,10 +45,10 @@ import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 public class GroupByTagNodeSerdeTest {
 
@@ -85,8 +86,8 @@ public class GroupByTagNodeSerdeTest {
             AggregationType.AVG.name().toLowerCase(),
             AggregationStep.PARTIAL,
             Collections.singletonList(new TimeSeriesOperand(new PartialPath("root.sg.d1.s1"))));
-    Map<List<String>, List<CrossSeriesAggregationDescriptor>> tagValuesToAggregationDescriptors =
-        new HashMap<>();
+    SortedMap<List<String>, List<CrossSeriesAggregationDescriptor>>
+        tagValuesToAggregationDescriptors = new TreeMap<>(GroupByTagNode::tagValuesComparator);
     tagValuesToAggregationDescriptors.put(
         Arrays.asList("v1", "v2"), Arrays.asList(s1MaxTime, s1Avg));
     GroupByTagNode expectedNode =
@@ -119,4 +120,34 @@ public class GroupByTagNodeSerdeTest {
     ByteBuffer buffer = ByteBuffer.wrap(byteArray);
     Assert.assertEquals(expectedNode, PlanNodeDeserializeHelper.deserialize(buffer));
   }
+
+  @Test
+  public void testTagValueComparator() {
+    List<Pair<List<String>, List<String>>> testCases =
+        Arrays.asList(
+            new Pair<>(Arrays.asList("x", "y", "z"), Arrays.asList("A", "B", "C")),
+            new Pair<>(Arrays.asList("x", "y", "z"), Arrays.asList("x", null, "z")),
+            new Pair<>(Arrays.asList(null, "y", "z"), Arrays.asList("x", null, null)),
+            new Pair<>(Arrays.asList(null, null, null), Arrays.asList(null, null, null)),
+            new Pair<>(Arrays.asList("x", "y", "z"), Arrays.asList("x", "y", "z")),
+            new Pair<>(Arrays.asList("x", "yz"), Arrays.asList("x", "y")));
+    int[] expected = new int[] {1, -1, 1, 0, 0, 1};
+    for (int i = 0; i < testCases.size(); i++) {
+      Pair<List<String>, List<String>> testCase = testCases.get(i);
+      if (expected[i] == 0) {
+        Assert.assertEquals(
+            testCase.toString(),
+            expected[i],
+            GroupByTagNode.tagValuesComparator(testCase.left, testCase.right));
+      } else if (expected[i] > 0) {
+        Assert.assertTrue(
+            testCase.toString(),
+            GroupByTagNode.tagValuesComparator(testCase.left, testCase.right) > 0);
+      } else {
+        Assert.assertTrue(
+            testCase.toString(),
+            GroupByTagNode.tagValuesComparator(testCase.left, testCase.right) < 0);
+      }
+    }
+  }
 }


[iotdb] 02/03: Add special limit clause for group by tags

Posted by er...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ericpai pushed a commit to branch feature/iotdb-4639
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 2159cc751607f253bbc9890f0c07497aed0ec07e
Author: ericpai <er...@hotmail.com>
AuthorDate: Wed Oct 19 10:34:03 2022 +0800

    Add special limit clause for group by tags
---
 .../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4   |  2 +-
 .../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java  |  5 ++-
 .../iotdb/db/mpp/plan/parser/ASTVisitor.java       |  5 +++
 .../db/mpp/plan/statement/crud/QueryStatement.java | 19 +++++++++---
 .../iotdb/db/mpp/plan/plan/LogicalPlannerTest.java | 36 ++++++++++++++++++++++
 5 files changed, 60 insertions(+), 7 deletions(-)

diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 5ef759a569..5621932b60 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -428,7 +428,7 @@ specialClause
     | groupByTimeClause havingClause? orderByClause? specialLimit? #groupByTimeStatement
     | groupByFillClause havingClause? orderByClause? specialLimit? #groupByFillStatement
     | groupByLevelClause havingClause? orderByClause? specialLimit? #groupByLevelStatement
-    | groupByTagClause orderByClause? #groupByTagStatement
+    | groupByTagClause orderByClause? specialLimit? #groupByTagStatement
     | fillClause orderByClause? specialLimit? #fillStatement
     ;
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
index 925d5558ec..6cb199c569 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
@@ -381,7 +381,10 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
       boolean hasAlias = resultColumn.hasAlias();
       List<Expression> resultExpressions =
           ExpressionAnalyzer.removeWildcardInExpression(resultColumn.getExpression(), schemaTree);
-      if (hasAlias && !queryStatement.isGroupByLevel() && resultExpressions.size() > 1) {
+      if (hasAlias
+          && !queryStatement.isGroupByLevel()
+          && !queryStatement.isGroupByTag()
+          && resultExpressions.size() > 1) {
         throw new SemanticException(
             String.format(
                 "alias '%s' can only be matched with one time series", resultColumn.getAlias()));
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 14bf81bd82..c7a94881e5 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -1124,6 +1124,11 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
       parseOrderByClause(ctx.orderByClause());
     }
 
+    // parse limit & offset
+    if (ctx.specialLimit() != null) {
+      return visit(ctx.specialLimit());
+    }
+
     return queryStatement;
   }
 
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
index ae6586de5f..e894c70d06 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
@@ -314,18 +314,27 @@ public class QueryStatement extends Statement {
         throw new SemanticException("AGGREGATION doesn't support disable align clause.");
       }
       if (isGroupByLevel() && isAlignByDevice()) {
-        throw new SemanticException("group by level does not support align by device now.");
+        throw new SemanticException("GROUP BY LEVEL does not support align by device now.");
       }
       if (isGroupByTag() && isAlignByDevice()) {
-        throw new SemanticException("group by tag does not support align by device now.");
-      }
-      if (isGroupByTag() && isGroupByLevel()) {
-        throw new SemanticException("group by level cannot be used togather with group by tag");
+        throw new SemanticException("GROUP BY TAGS does not support align by device now.");
       }
+      Set<String> outputColumn = new HashSet<>();
       for (ResultColumn resultColumn : selectComponent.getResultColumns()) {
         if (resultColumn.getColumnType() != ResultColumn.ColumnType.AGGREGATION) {
           throw new SemanticException("Raw data and aggregation hybrid query is not supported.");
         }
+        outputColumn.add(
+            resultColumn.getAlias() != null
+                ? resultColumn.getAlias()
+                : resultColumn.getExpression().getExpressionString());
+      }
+      if (isGroupByTag()) {
+        for (String s : getGroupByTagComponent().getTagKeys()) {
+          if (outputColumn.contains(s)) {
+            throw new SemanticException("Output column is duplicated with the tag key: " + s);
+          }
+        }
       }
     } else {
       if (isGroupByTime() || isGroupByLevel()) {
diff --git a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java
index fe2b9500a0..410cabafff 100644
--- a/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/mpp/plan/plan/LogicalPlannerTest.java
@@ -683,6 +683,42 @@ public class LogicalPlannerTest {
     }
   }
 
+  @Test
+  public void testGroupByTagWithIllegalSpecialLimitClause() {
+    String[] inputSql =
+        new String[] {
+          "select max_value(s1) from root.** group by tags(key1) disable align",
+          "select max_value(s1) from root.** group by tags(key1) align by device",
+          "select max_value(s1) from root.** group by tags(key1) without null any",
+        };
+    String[] expectedMsg =
+        new String[] {
+          "AGGREGATION doesn't support disable align clause",
+          "GROUP BY TAGS does not support align by device now",
+          "WITHOUT NULL clause is not supported yet"
+        };
+    for (int i = 0; i < inputSql.length; i++) {
+      try {
+        parseSQLToPlanNode(inputSql[i]);
+        fail();
+      } catch (Exception e) {
+        Assert.assertTrue(inputSql[i], e.getMessage().contains(expectedMsg[i]));
+      }
+    }
+  }
+
+  @Test
+  public void testGroupByTagWithDuplicatedAliasWithTagKey() {
+    String sql = "select max_value(s1) as key1 from root.** group by tags(key1)";
+    try {
+      parseSQLToPlanNode(sql);
+      fail();
+    } catch (Exception e) {
+      Assert.assertTrue(
+          e.getMessage().contains("Output column is duplicated with the tag key: key1"));
+    }
+  }
+
   private PlanNode parseSQLToPlanNode(String sql) {
     Statement statement = StatementGenerator.createStatement(sql, ZonedDateTime.now().getOffset());
     MPPQueryContext context = new MPPQueryContext(new QueryId("test_query"));