55
66package org .opensearch .sql .legacy .executor .format ;
77
8+ import java .util .Locale ;
89import java .util .Map ;
910import java .util .Objects ;
1011import org .apache .logging .log4j .LogManager ;
2122import org .opensearch .sql .legacy .exception .SqlParseException ;
2223import org .opensearch .sql .legacy .executor .QueryActionElasticExecutor ;
2324import org .opensearch .sql .legacy .executor .RestExecutor ;
25+ import org .opensearch .sql .legacy .metrics .MetricName ;
26+ import org .opensearch .sql .legacy .metrics .Metrics ;
2427import org .opensearch .sql .legacy .pit .PointInTimeHandler ;
2528import org .opensearch .sql .legacy .pit .PointInTimeHandlerImpl ;
2629import org .opensearch .sql .legacy .query .DefaultQueryAction ;
2730import org .opensearch .sql .legacy .query .QueryAction ;
28- import org .opensearch .sql .legacy .query .SqlOpenSearchRequestBuilder ;
2931import org .opensearch .sql .legacy .query .join .BackOffRetryStrategy ;
3032import org .opensearch .transport .client .Client ;
3133
@@ -36,7 +38,7 @@ public class PrettyFormatRestExecutor implements RestExecutor {
3638 private final String format ;
3739
3840 public PrettyFormatRestExecutor (String format ) {
39- this .format = format .toLowerCase ();
41+ this .format = Objects . requireNonNull ( format , "Format cannot be null" ) .toLowerCase (Locale . ROOT );
4042 }
4143
4244 /** Execute the QueryAction and return the REST response using the channel. */
@@ -72,61 +74,98 @@ public String execute(Client client, Map<String, String> params, QueryAction que
7274 Object queryResult = QueryActionElasticExecutor .executeAnyAction (client , queryAction );
7375 protocol = new Protocol (client , queryAction , queryResult , format , Cursor .NULL_CURSOR );
7476 }
77+ } catch (SqlParseException e ) {
78+ LOG .warn ("SQL parsing error: {}" , e .getMessage (), e );
79+ protocol = new Protocol (e );
80+ } catch (OpenSearchException e ) {
81+ LOG .warn ("An error occurred in OpenSearch engine: {}" , e .getDetailedMessage (), e );
82+ protocol = new Protocol (e );
7583 } catch (Exception e ) {
76- if (e instanceof OpenSearchException ) {
77- LOG .warn (
78- "An error occurred in OpenSearch engine: "
79- + ((OpenSearchException ) e ).getDetailedMessage (),
80- e );
81- } else {
82- LOG .warn ("Error happened in pretty formatter" , e );
83- }
84+ LOG .warn ("Error happened in pretty formatter" , e );
8485 protocol = new Protocol (e );
8586 }
8687
8788 return protocol .format ();
8889 }
8990
9091 /**
91- * QueryActionElasticExecutor.executeAnyAction() returns SearchHits inside SearchResponse. In
92- * order to get scroll ID if any, we need to execute DefaultQueryAction ourselves for
93- * SearchResponse .
92+ * Builds protocol for default query execution.
93+ *
94+ * <p>Routes to pagination or non-pagination execution based on fetch_size parameter .
9495 */
9596 private Protocol buildProtocolForDefaultQuery (Client client , DefaultQueryAction queryAction )
9697 throws SqlParseException {
9798
98- PointInTimeHandler pit = null ;
99- SearchResponse response ;
100- SqlOpenSearchRequestBuilder sqlOpenSearchRequestBuilder = queryAction .explain ();
99+ queryAction .explain ();
101100
102- pit = new PointInTimeHandlerImpl (client , queryAction .getSelect ().getIndexArr ());
101+ Integer fetchSize = queryAction .getSqlRequest ().fetchSize ();
102+ if (fetchSize != null && fetchSize > 0 ) {
103+ return buildProtocolWithPagination (client , queryAction , fetchSize );
104+ } else {
105+ return buildProtocolWithoutPagination (client , queryAction );
106+ }
107+ }
108+
109+ /** Executes query with pagination support using Point-in-Time (PIT). */
110+ private Protocol buildProtocolWithPagination (
111+ Client client , DefaultQueryAction queryAction , Integer fetchSize ) {
112+
113+ PointInTimeHandler pit =
114+ new PointInTimeHandlerImpl (client , queryAction .getSelect ().getIndexArr ());
103115 pit .create ();
116+
117+ try {
118+ SearchRequestBuilder searchRequest = queryAction .getRequestBuilder ();
119+ searchRequest .setPointInTime (new PointInTimeBuilder (pit .getPitId ()));
120+ SearchResponse response = searchRequest .get ();
121+
122+ if (shouldCreateCursor (response , queryAction , fetchSize )) {
123+ DefaultCursor cursor = createCursorWithPit (pit , response , queryAction , fetchSize );
124+ return new Protocol (client , queryAction , response .getHits (), format , cursor );
125+ } else {
126+ pit .delete ();
127+ return new Protocol (client , queryAction , response .getHits (), format , Cursor .NULL_CURSOR );
128+ }
129+ } catch (RuntimeException e ) {
130+ try {
131+ pit .delete ();
132+ } catch (RuntimeException deleteException ) {
133+ LOG .error ("Failed to delete PIT" , deleteException );
134+ Metrics .getInstance ().getNumericalMetric (MetricName .FAILED_REQ_COUNT_SYS ).increment ();
135+ }
136+ throw e ;
137+ }
138+ }
139+
140+ private Protocol buildProtocolWithoutPagination (Client client , DefaultQueryAction queryAction ) {
104141 SearchRequestBuilder searchRequest = queryAction .getRequestBuilder ();
105- searchRequest .setPointInTime (new PointInTimeBuilder (pit .getPitId ()));
106- response = searchRequest .get ();
142+ SearchResponse response = searchRequest .get ();
143+ return new Protocol (client , queryAction , response .getHits (), format , Cursor .NULL_CURSOR );
144+ }
107145
108- Protocol protocol ;
109- if (isDefaultCursor (response , queryAction )) {
110- DefaultCursor defaultCursor = new DefaultCursor ();
111- defaultCursor .setLimit (queryAction .getSelect ().getRowCount ());
112- defaultCursor .setFetchSize (queryAction .getSqlRequest ().fetchSize ());
113-
114- defaultCursor .setPitId (pit .getPitId ());
115- defaultCursor .setSearchSourceBuilder (queryAction .getRequestBuilder ().request ().source ());
116- defaultCursor .setSortFields (
146+ private DefaultCursor createCursorWithPit (
147+ PointInTimeHandler pit ,
148+ SearchResponse response ,
149+ DefaultQueryAction queryAction ,
150+ Integer fetchSize ) {
151+ DefaultCursor cursor = new DefaultCursor ();
152+ cursor .setLimit (queryAction .getSelect ().getRowCount ());
153+ cursor .setFetchSize (fetchSize );
154+ cursor .setPitId (pit .getPitId ());
155+ cursor .setSearchSourceBuilder (queryAction .getRequestBuilder ().request ().source ());
156+
157+ if (response .getHits ().getHits ().length > 0 ) {
158+ cursor .setSortFields (
117159 response .getHits ().getAt (response .getHits ().getHits ().length - 1 ).getSortValues ());
118-
119- protocol = new Protocol (client , queryAction , response .getHits (), format , defaultCursor );
120- } else {
121- protocol = new Protocol (client , queryAction , response .getHits (), format , Cursor .NULL_CURSOR );
122160 }
123161
124- return protocol ;
162+ return cursor ;
125163 }
126164
127- protected boolean isDefaultCursor (SearchResponse searchResponse , DefaultQueryAction queryAction ) {
128- return queryAction .getSqlRequest ().fetchSize () != 0
129- && Objects .requireNonNull (searchResponse .getHits ().getTotalHits ()).value ()
130- >= queryAction .getSqlRequest ().fetchSize ();
165+ protected boolean shouldCreateCursor (
166+ SearchResponse searchResponse , DefaultQueryAction queryAction , Integer fetchSize ) {
167+ return fetchSize != null
168+ && searchResponse .getHits () != null
169+ && Objects .requireNonNull (searchResponse .getHits ().getTotalHits ()).value () >= fetchSize ;
131170 }
132171}
0 commit comments