55
66package org .opensearch .sql .executor ;
77
8- import java .security .AccessController ;
9- import java .security .PrivilegedAction ;
108import java .util .List ;
119import java .util .Optional ;
1210import javax .annotation .Nullable ;
3937import org .opensearch .sql .calcite .CalciteRelNodeVisitor ;
4038import org .opensearch .sql .calcite .OpenSearchSchema ;
4139import org .opensearch .sql .calcite .SysLimit ;
42- import org .opensearch .sql .calcite .plan .LogicalPaginationLimit ;
4340import org .opensearch .sql .calcite .plan .LogicalSystemLimit ;
4441import org .opensearch .sql .calcite .plan .LogicalSystemLimit .SystemLimitType ;
4542import org .opensearch .sql .common .response .ResponseListener ;
@@ -118,6 +115,36 @@ public void explain(
118115 }
119116 }
120117
118+ /**
119+ * Explain with pagination support.
120+ *
121+ * @param plan the unresolved plan
122+ * @param queryType the query type
123+ * @param listener the response listener
124+ * @param format the explain format
125+ * @param pageSize page size for pagination
126+ * @param offset pagination offset (0-based)
127+ */
128+ public void explain (
129+ UnresolvedPlan plan ,
130+ QueryType queryType ,
131+ ResponseListener <ExecutionEngine .ExplainResponse > listener ,
132+ Explain .ExplainFormat format ,
133+ int pageSize ,
134+ int offset ) {
135+ if (shouldUseCalcite (queryType )) {
136+ explainWithCalcite (plan , queryType , listener , format , pageSize , offset );
137+ } else {
138+ // For legacy path (SQL), wrap with Paginate when pagination is enabled
139+ if (pageSize > 0 ) {
140+ explainWithLegacy (
141+ new Paginate (pageSize , plan ), queryType , listener , format , Optional .empty ());
142+ } else {
143+ explainWithLegacy (plan , queryType , listener , format , Optional .empty ());
144+ }
145+ }
146+ }
147+
121148 public void executeWithCalcite (
122149 UnresolvedPlan plan ,
123150 QueryType queryType ,
@@ -143,26 +170,21 @@ public void executeWithCalcite(
143170 CalcitePlanContext .run (
144171 () -> {
145172 try {
146- AccessController .doPrivileged (
147- (PrivilegedAction <Void >)
148- () -> {
149- CalcitePlanContext context =
150- CalcitePlanContext .create (
151- buildFrameworkConfig (), SysLimit .fromSettings (settings ), queryType );
173+ CalcitePlanContext context =
174+ CalcitePlanContext .create (
175+ buildFrameworkConfig (), SysLimit .fromSettings (settings ), queryType );
152176
153- // Set pagination parameters if enabled
154- if (pageSize > 0 ) {
155- context .setPaginationSize (pageSize );
156- context .setPaginationOffset (offset );
157- }
177+ // Set pagination parameters if enabled
178+ if (pageSize > 0 ) {
179+ context .setPaginationSize (pageSize );
180+ context .setPaginationOffset (offset );
181+ }
158182
159- RelNode relNode = analyze (plan , context );
160- relNode = mergeAdjacentFilters (relNode );
161- RelNode optimized = optimize (relNode , context );
162- RelNode calcitePlan = convertToCalcitePlan (optimized );
163- executionEngine .execute (calcitePlan , context , listener );
164- return null ;
165- });
183+ RelNode relNode = analyze (plan , context );
184+ relNode = mergeAdjacentFilters (relNode );
185+ RelNode optimized = optimize (relNode , context );
186+ RelNode calcitePlan = convertToCalcitePlan (optimized );
187+ executionEngine .execute (calcitePlan , context , listener );
166188 } catch (Throwable t ) {
167189 if (isCalciteFallbackAllowed (t ) && !(t instanceof NonFallbackCalciteException )) {
168190 log .warn ("Fallback to V2 query engine since got exception" , t );
@@ -191,12 +213,39 @@ public void explainWithCalcite(
191213 QueryType queryType ,
192214 ResponseListener <ExecutionEngine .ExplainResponse > listener ,
193215 Explain .ExplainFormat format ) {
216+ explainWithCalcite (plan , queryType , listener , format , 0 , 0 );
217+ }
218+
219+ /**
220+ * Explain with Calcite engine and pagination support.
221+ *
222+ * @param plan the unresolved plan
223+ * @param queryType the query type
224+ * @param listener the response listener
225+ * @param format the explain format
226+ * @param pageSize page size (0 = no pagination)
227+ * @param offset pagination offset (0-based)
228+ */
229+ public void explainWithCalcite (
230+ UnresolvedPlan plan ,
231+ QueryType queryType ,
232+ ResponseListener <ExecutionEngine .ExplainResponse > listener ,
233+ Explain .ExplainFormat format ,
234+ int pageSize ,
235+ int offset ) {
194236 CalcitePlanContext .run (
195237 () -> {
196238 try {
197239 CalcitePlanContext context =
198240 CalcitePlanContext .create (
199241 buildFrameworkConfig (), SysLimit .fromSettings (settings ), queryType );
242+
243+ // Set pagination parameters if enabled
244+ if (pageSize > 0 ) {
245+ context .setPaginationSize (pageSize );
246+ context .setPaginationOffset (offset );
247+ }
248+
200249 context .run (
201250 () -> {
202251 RelNode relNode = analyze (plan , context );
@@ -344,9 +393,8 @@ public PhysicalPlan plan(LogicalPlan plan) {
344393 public RelNode optimize (RelNode plan , CalcitePlanContext context ) {
345394 if (context .isPaginationEnabled ()) {
346395 // Apply pagination LIMIT/OFFSET on top of user's complete query result
347- // Using LogicalPaginationLimit to preserve input's collation and ensure
348- // pagination is applied as post-processing, not merged with user's head/sort
349- return LogicalPaginationLimit .create (
396+ return LogicalSystemLimit .create (
397+ SystemLimitType .PAGINATION ,
350398 plan ,
351399 context .relBuilder .literal (context .getPaginationOffset ()),
352400 context .relBuilder .literal (context .getPaginationSize ()));
0 commit comments