2929import net .sf .jsqlparser .statement .select .OrderByElement ;
3030import net .sf .jsqlparser .statement .select .PlainSelect ;
3131import net .sf .jsqlparser .statement .select .Select ;
32+ import net .sf .jsqlparser .statement .select .SelectBody ;
3233import net .sf .jsqlparser .statement .select .SelectExpressionItem ;
3334import net .sf .jsqlparser .statement .select .SelectItem ;
35+ import net .sf .jsqlparser .statement .select .SetOperationList ;
36+ import net .sf .jsqlparser .statement .select .WithItem ;
3437import net .sf .jsqlparser .statement .update .Update ;
38+ import net .sf .jsqlparser .statement .values .ValuesStatement ;
3539
3640import java .util .ArrayList ;
3741import java .util .Collections ;
@@ -107,6 +111,14 @@ public String applySorting(Sort sort, @Nullable String alias) {
107111 }
108112
109113 Select selectStatement = parseSelectStatement (queryString );
114+
115+ if (selectStatement .getSelectBody () instanceof SetOperationList ) {
116+ SetOperationList setOperationList = (SetOperationList ) selectStatement .getSelectBody ();
117+ return applySortingToSetOperationList (setOperationList , sort );
118+ } else if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
119+ return queryString ;
120+ }
121+
110122 PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
111123
112124 final Set <String > joinAliases = getJoinAliases (selectBody );
@@ -127,6 +139,33 @@ public String applySorting(Sort sort, @Nullable String alias) {
127139
128140 }
129141
142+ /**
143+ * Returns the {@link SetOperationList} as a string query with {@link Sort}s applied in the right order.
144+ *
145+ * @param setOperationListStatement
146+ * @param sort
147+ * @return
148+ */
149+ private String applySortingToSetOperationList (SetOperationList setOperationListStatement , Sort sort ) {
150+
151+ // special case: ValuesStatements are detected as nested OperationListStatements
152+ if (setOperationListStatement .getSelects ().stream ().anyMatch (ValuesStatement .class ::isInstance )) {
153+ return setOperationListStatement .toString ();
154+ }
155+
156+ // if (CollectionUtils.isEmpty(setOperationListStatement.getOrderByElements())) {
157+ if (setOperationListStatement .getOrderByElements () == null ) {
158+ setOperationListStatement .setOrderByElements (new ArrayList <>());
159+ }
160+
161+ List <OrderByElement > orderByElements = sort .stream () //
162+ .map (order -> getOrderClause (Collections .emptySet (), Collections .emptySet (), null , order )) //
163+ .collect (Collectors .toList ());
164+ setOperationListStatement .getOrderByElements ().addAll (orderByElements );
165+
166+ return setOperationListStatement .toString ();
167+ }
168+
130169 /**
131170 * Returns the aliases used inside the selection part in the query.
132171 *
@@ -175,7 +214,13 @@ private Set<String> getJoinAliases(String query) {
175214 return new HashSet <>();
176215 }
177216
178- return getJoinAliases ((PlainSelect ) parseSelectStatement (query ).getSelectBody ());
217+ Select selectStatement = parseSelectStatement (query );
218+ if (selectStatement .getSelectBody () instanceof PlainSelect ) {
219+ PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
220+ return getJoinAliases (selectBody );
221+ }
222+
223+ return new HashSet <>();
179224 }
180225
181226 /**
@@ -259,6 +304,17 @@ private String detectAlias(String query) {
259304 }
260305
261306 Select selectStatement = parseSelectStatement (query );
307+
308+ /*
309+ For all the other types ({@link ValuesStatement} and {@link SetOperationList}) it does not make sense to provide
310+ alias since:
311+ * ValuesStatement has no alias
312+ * SetOperation can have multiple alias for each operation item
313+ */
314+ if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
315+ return null ;
316+ }
317+
262318 PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
263319 return detectAlias (selectBody );
264320 }
@@ -273,6 +329,10 @@ private String detectAlias(String query) {
273329 @ Nullable
274330 private static String detectAlias (PlainSelect selectBody ) {
275331
332+ if (selectBody .getFromItem () == null ) {
333+ return null ;
334+ }
335+
276336 Alias alias = selectBody .getFromItem ().getAlias ();
277337 return alias == null ? null : alias .getName ();
278338 }
@@ -287,6 +347,14 @@ public String createCountQueryFor(@Nullable String countProjection) {
287347 Assert .hasText (this .query .getQueryString (), "OriginalQuery must not be null or empty!" );
288348
289349 Select selectStatement = parseSelectStatement (this .query .getQueryString ());
350+
351+ /*
352+ We only support count queries for {@link PlainSelect}.
353+ */
354+ if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
355+ return this .query .getQueryString ();
356+ }
357+
290358 PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
291359
292360 // remove order by
@@ -322,8 +390,15 @@ public String createCountQueryFor(@Nullable String countProjection) {
322390 Function jSqlCount = getJSqlCount (Collections .singletonList (countProp ), distinct );
323391 selectBody .setSelectItems (Collections .singletonList (new SelectExpressionItem (jSqlCount )));
324392
325- return selectBody .toString ();
393+ if (CollectionUtils .isEmpty (selectStatement .getWithItemsList ())) {
394+ return selectBody .toString ();
395+ }
326396
397+ String withStatements = selectStatement .getWithItemsList ().stream () //
398+ .map (WithItem ::toString ) //
399+ .collect (Collectors .joining ("," ));
400+
401+ return "with " + withStatements + "\n " + selectBody ;
327402 }
328403
329404 @ Override
@@ -336,9 +411,24 @@ public String getProjection() {
336411 Assert .hasText (query .getQueryString (), "Query must not be null or empty!" );
337412
338413 Select selectStatement = parseSelectStatement (query .getQueryString ());
339- PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
340414
341- return selectBody .getSelectItems () //
415+ if (selectStatement .getSelectBody () instanceof ValuesStatement ) {
416+ return "" ;
417+ }
418+
419+ SelectBody selectBody = selectStatement .getSelectBody ();
420+
421+ if (selectStatement .getSelectBody () instanceof SetOperationList ) {
422+ SetOperationList setOperationList = (SetOperationList ) selectStatement .getSelectBody ();
423+ // using the first one since for setoperations the projection has to be the same
424+ selectBody = setOperationList .getSelects ().get (0 );
425+
426+ if (!(selectBody instanceof PlainSelect )) {
427+ return "" ;
428+ }
429+ }
430+
431+ return ((PlainSelect ) selectBody ).getSelectItems () //
342432 .stream () //
343433 .map (Object ::toString ) //
344434 .collect (Collectors .joining (", " )).trim ();
0 commit comments