2121
2222package org .apache .iotdb .db .queryengine .plan .relational .planner ;
2323
24- import org .apache .iotdb .commons .schema .table .column .TsTableColumnCategory ;
25- import org .apache .iotdb .db .queryengine .common .MPPQueryContext ;
24+ import org .apache .iotdb .common .rpc .thrift .TSStatus ;
25+ import org .apache .iotdb .commons .exception .IoTDBException ;
26+ import org .apache .iotdb .commons .schema .column .ColumnHeader ;
27+ import org .apache .iotdb .db .protocol .session .SessionManager ;
28+ import org .apache .iotdb .db .queryengine .common .QueryId ;
29+ import org .apache .iotdb .db .queryengine .common .header .DatasetHeader ;
30+ import org .apache .iotdb .db .queryengine .plan .Coordinator ;
31+ import org .apache .iotdb .db .queryengine .plan .execution .ExecutionResult ;
32+ import org .apache .iotdb .db .queryengine .plan .execution .QueryExecution ;
2633import org .apache .iotdb .db .queryengine .plan .planner .plan .LogicalQueryPlan ;
27- import org .apache .iotdb .db .queryengine .plan .relational .metadata .ColumnSchema ;
28- import org .apache .iotdb .db .queryengine .plan .relational .metadata .TableSchema ;
2934import org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern ;
3035import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .ComparisonExpression ;
3136import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .Expression ;
3237import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .LongLiteral ;
33- import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .Query ;
34- import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .QuerySpecification ;
35- import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .SelectItem ;
36- import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .SingleColumn ;
3738import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .SymbolReference ;
38- import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .Table ;
39- import org .apache .iotdb .db .queryengine .plan .relational .sql .ast .With ;
40- import org .apache .iotdb .db .utils .cte .CteDataStore ;
4139
4240import com .google .common .collect .ImmutableList ;
4341import com .google .common .collect .ImmutableMap ;
4442import com .google .common .collect .ImmutableSet ;
4543import org .apache .tsfile .enums .TSDataType ;
46- import org .apache .tsfile .read .common .type .Type ;
47- import org .apache .tsfile .read .common .type .TypeFactory ;
44+ import org .apache .tsfile .read .common .block .TsBlock ;
45+ import org .apache .tsfile .read .common .block .column .LongColumn ;
46+ import org .apache .tsfile .read .common .block .column .TimeColumn ;
4847import org .junit .Before ;
48+ import org .junit .BeforeClass ;
4949import org .junit .Test ;
50+ import org .junit .runner .RunWith ;
5051import org .mockito .Mockito ;
51- import org .mockito .invocation .InvocationOnMock ;
52+ import org .powermock .core .classloader .annotations .PowerMockIgnore ;
53+ import org .powermock .core .classloader .annotations .PrepareForTest ;
54+ import org .powermock .modules .junit4 .PowerMockRunner ;
5255
5356import java .util .Collections ;
5457import java .util .List ;
5558import java .util .Optional ;
56- import java .util .stream .Collectors ;
5759
5860import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanAssert .assertPlan ;
5961import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .aggregation ;
6062import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .aggregationFunction ;
6163import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .cteScan ;
64+ import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .explainAnalyze ;
6265import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .filter ;
6366import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .limit ;
6467import static org .apache .iotdb .db .queryengine .plan .relational .planner .assertions .PlanMatchPattern .offset ;
7073import static org .apache .iotdb .db .queryengine .plan .relational .sql .ast .ComparisonExpression .Operator .GREATER_THAN ;
7174import static org .apache .iotdb .db .queryengine .plan .relational .sql .ast .SortItem .NullOrdering .LAST ;
7275import static org .apache .iotdb .db .queryengine .plan .relational .sql .ast .SortItem .Ordering .ASCENDING ;
76+ import static org .powermock .api .mockito .PowerMockito .mockStatic ;
77+ import static org .powermock .api .mockito .PowerMockito .when ;
7378
79+ @ PowerMockIgnore ({"com.sun.org.apache.xerces.*" , "javax.xml.*" , "org.xml.*" , "javax.management.*" })
80+ @ RunWith (PowerMockRunner .class )
81+ @ PrepareForTest ({Coordinator .class , SessionManager .class })
7482public class CteMaterializerTest {
75- private PlanTester planTester ;
83+ private static PlanTester planTester ;
84+ private static Coordinator mockCoordinator ;
7685
77- @ Before
78- public void setUp () {
86+ @ BeforeClass
87+ public static void prepareEnv () {
7988 planTester = new PlanTester ();
80- mockSubquery ();
89+ mockStatic (Coordinator .class );
90+ mockStatic (SessionManager .class );
91+
92+ // Create a mock Coordinator instance
93+ mockCoordinator = Mockito .mock (Coordinator .class );
94+ when (Coordinator .getInstance ()).thenReturn (mockCoordinator );
95+
96+ // Create mock SessionManager
97+ SessionManager mockSessionManager = Mockito .mock (SessionManager .class );
98+ when (SessionManager .getInstance ()).thenReturn (mockSessionManager );
99+
100+ // Mock TSStatus with success status
101+ TSStatus mockStatus = Mockito .mock (TSStatus .class );
102+ when (mockStatus .getCode ()).thenReturn (200 ); // Success status code
103+
104+ // Create a real ExecutionResult instance
105+ ExecutionResult mockResult = new ExecutionResult (new QueryId ("1" ), mockStatus );
106+
107+ // Mock the executeForTableModel method
108+ when (mockCoordinator .executeForTableModel (
109+ Mockito .any (), // Statement
110+ Mockito .any (), // SqlParser
111+ Mockito .any (), // IClientSession
112+ Mockito .anyLong (), // queryId
113+ Mockito .any (), // SessionInfo
114+ Mockito .anyString (), // String
115+ Mockito .any (), // Metadata
116+ Mockito .anyMap (), // Map<NodeRef<Table>, CteDataStore>
117+ Mockito .any (), // ExplainType
118+ Mockito .anyLong (), // timeOut
119+ Mockito .anyBoolean ())) // userQuery
120+ .thenReturn (mockResult );
81121 }
82122
83- private Type convertType (String columnName ) {
84- switch (columnName ) {
85- case "time" :
86- return TypeFactory .getType (TSDataType .TIMESTAMP );
87- case "s1" :
88- case "a1" :
89- return TypeFactory .getType (TSDataType .INT64 );
90- default :
91- }
92- return null ;
123+ @ Before
124+ public void setUp () throws IoTDBException {
125+ // Create QueryExecution mock
126+ QueryExecution mockQueryExecution = Mockito .mock (QueryExecution .class );
127+ when (mockQueryExecution .hasNextResult ())
128+ .thenReturn (true ) // First call returns true
129+ .thenReturn (false ); // Subsequent calls return false
130+
131+ // Create a real DatasetHeader with time and s1 columns
132+ List <ColumnHeader > columnHeaders =
133+ ImmutableList .of (
134+ new ColumnHeader ("time" , TSDataType .TIMESTAMP ),
135+ new ColumnHeader ("s1" , TSDataType .INT64 ));
136+ DatasetHeader mockDatasetHeader = new DatasetHeader (columnHeaders , false );
137+ when (mockQueryExecution .getDatasetHeader ()).thenReturn (mockDatasetHeader );
138+
139+ // Create a TSBlock with sample data for getBatchResult
140+ long [] timestamps = {1000L , 2000L , 3000L };
141+ long [] values = {10L , 20L , 30L };
142+ TimeColumn timeColumn = new TimeColumn (3 , timestamps );
143+ LongColumn valueColumn = new LongColumn (3 , Optional .empty (), values );
144+ TsBlock sampleTsBlock = new TsBlock (timeColumn , valueColumn );
145+ when (mockQueryExecution .getBatchResult ()).thenReturn (Optional .of (sampleTsBlock ));
146+
147+ // Mock coordinator methods
148+ when (mockCoordinator .getQueryExecution (Mockito .anyLong ())).thenReturn (mockQueryExecution );
93149 }
94150
95151 private void mockException () {
@@ -100,44 +156,6 @@ private void mockException() {
100156 CteMaterializer .setInstance (cteMaterializer );
101157 }
102158
103- private void mockSubquery () {
104- CteMaterializer cteMaterializer = Mockito .spy (new CteMaterializer ());
105-
106- Mockito .doAnswer (
107- (InvocationOnMock invocation ) -> {
108- Table table = invocation .getArgument (1 );
109- Query query = invocation .getArgument (2 );
110- List <SelectItem > selectItems =
111- ((QuerySpecification ) query .getQueryBody ()).getSelect ().getSelectItems ();
112- List <ColumnSchema > columnsSchemas =
113- selectItems .stream ()
114- .map (
115- selectItem -> {
116- SingleColumn column = ((SingleColumn ) selectItem );
117- String columnName =
118- column .getAlias ().isPresent ()
119- ? column .getAlias ().get ().toString ()
120- : column .getExpression ().toString ();
121- return new ColumnSchema (
122- columnName ,
123- convertType (columnName ),
124- false ,
125- TsTableColumnCategory .FIELD );
126- })
127- .collect (Collectors .toList ());
128-
129- TableSchema tableSchema = new TableSchema (table .getName ().toString (), columnsSchemas );
130- return new CteDataStore (query , tableSchema , ImmutableList .of (0 , 1 ));
131- })
132- .when (cteMaterializer )
133- .fetchCteQueryResult (
134- Mockito .any (MPPQueryContext .class ),
135- Mockito .any (Table .class ),
136- Mockito .any (Query .class ),
137- Mockito .any (With .class ));
138- CteMaterializer .setInstance (cteMaterializer );
139- }
140-
141159 @ Test
142160 public void testSimpleCte () {
143161 String sql = "with cte1 as materialized (SELECT time, s1 FROM table1) select * from cte1" ;
@@ -157,13 +175,13 @@ public void testSimpleCte() {
157175 @ Test
158176 public void testFieldFilterCte () {
159177 String sql =
160- "with cte1 as materialized (SELECT time, s1 as a1 FROM table1) select * from cte1 where a1 > 10" ;
178+ "with cte1 as materialized (SELECT time, s1 FROM table1) select * from cte1 where s1 > 10" ;
161179
162180 LogicalQueryPlan logicalQueryPlan = planTester .createPlan (sql );
163181
164182 Expression filterPredicate =
165- new ComparisonExpression (GREATER_THAN , new SymbolReference ("a1 " ), new LongLiteral ("10" ));
166- PlanMatchPattern cteScan = cteScan ("cte1" , ImmutableList .of ("time" , "a1 " ));
183+ new ComparisonExpression (GREATER_THAN , new SymbolReference ("s1 " ), new LongLiteral ("10" ));
184+ PlanMatchPattern cteScan = cteScan ("cte1" , ImmutableList .of ("time" , "s1 " ));
167185
168186 // Verify full LogicalPlan
169187 /*
@@ -263,6 +281,7 @@ public void testAggCte() {
263281
264282 @ Test
265283 public void testCteQueryException () {
284+ CteMaterializer originalCteMaterializer = CteMaterializer .getInstance ();
266285 mockException ();
267286
268287 String sql = "with cte1 as materialized (SELECT time, s1 FROM table1) select * from cte1" ;
@@ -278,5 +297,43 @@ public void testCteQueryException() {
278297 * └──TableScanNode
279298 */
280299 assertPlan (logicalQueryPlan , output (tableScan ));
300+
301+ // reset original CteMaterializer
302+ CteMaterializer .setInstance (originalCteMaterializer );
303+ }
304+
305+ @ Test
306+ public void testExplainAnalyze () {
307+ String sql =
308+ "explain analyze with cte1 as materialized (SELECT time, s1 FROM table1) select * from cte1" ;
309+
310+ LogicalQueryPlan logicalQueryPlan = planTester .createPlan (sql );
311+
312+ PlanMatchPattern cteScan = cteScan ("cte1" , ImmutableList .of ("time" , "s1" ));
313+
314+ // Verify full LogicalPlan
315+ /*
316+ * └──OutputNode
317+ * └──ExplainAnalyzeNode
318+ * └──CteScanNode
319+ */
320+ assertPlan (logicalQueryPlan , output (explainAnalyze (cteScan )));
321+ }
322+
323+ /** This test primarily ensures code coverage for handleCteExplainResults method. */
324+ @ Test
325+ public void testExplain () {
326+ String sql = "with cte1 as materialized (SELECT time, s1 FROM table1) select * from cte1" ;
327+
328+ LogicalQueryPlan logicalQueryPlan = planTester .createPlan (sql , true );
329+
330+ PlanMatchPattern cteScan = cteScan ("cte1" , ImmutableList .of ("time" , "s1" ));
331+
332+ // Verify full LogicalPlan
333+ /*
334+ * └──OutputNode
335+ * └──CteScanNode
336+ */
337+ assertPlan (logicalQueryPlan , output (cteScan ));
281338 }
282339}
0 commit comments