29
29
import net .sf .jsqlparser .statement .select .OrderByElement ;
30
30
import net .sf .jsqlparser .statement .select .PlainSelect ;
31
31
import net .sf .jsqlparser .statement .select .Select ;
32
+ import net .sf .jsqlparser .statement .select .SelectBody ;
32
33
import net .sf .jsqlparser .statement .select .SelectExpressionItem ;
33
34
import net .sf .jsqlparser .statement .select .SelectItem ;
35
+ import net .sf .jsqlparser .statement .select .SetOperationList ;
36
+ import net .sf .jsqlparser .statement .select .WithItem ;
34
37
import net .sf .jsqlparser .statement .update .Update ;
38
+ import net .sf .jsqlparser .statement .values .ValuesStatement ;
35
39
36
40
import java .util .ArrayList ;
37
41
import java .util .Collections ;
@@ -107,6 +111,13 @@ public String applySorting(Sort sort, @Nullable String alias) {
107
111
}
108
112
109
113
Select selectStatement = parseSelectStatement (queryString );
114
+
115
+ if (selectStatement .getSelectBody ()instanceof SetOperationList setOperationList ) {
116
+ return applySortingToSetOperationList (setOperationList , sort );
117
+ } else if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
118
+ return queryString ;
119
+ }
120
+
110
121
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
111
122
112
123
final Set <String > joinAliases = getJoinAliases (selectBody );
@@ -115,7 +126,7 @@ public String applySorting(Sort sort, @Nullable String alias) {
115
126
116
127
List <OrderByElement > orderByElements = sort .stream () //
117
128
.map (order -> getOrderClause (joinAliases , selectionAliases , alias , order )) //
118
- .collect ( Collectors . toList () );
129
+ .toList ();
119
130
120
131
if (CollectionUtils .isEmpty (selectBody .getOrderByElements ())) {
121
132
selectBody .setOrderByElements (new ArrayList <>());
@@ -127,6 +138,33 @@ public String applySorting(Sort sort, @Nullable String alias) {
127
138
128
139
}
129
140
141
+ /**
142
+ * Returns the {@link SetOperationList} as a string query with {@link Sort}s applied in the right order.
143
+ *
144
+ * @param setOperationListStatement
145
+ * @param sort
146
+ * @return
147
+ */
148
+ private String applySortingToSetOperationList (SetOperationList setOperationListStatement , Sort sort ) {
149
+
150
+ // special case: ValuesStatements are detected as nested OperationListStatements
151
+ if (setOperationListStatement .getSelects ().stream ().anyMatch (ValuesStatement .class ::isInstance )) {
152
+ return setOperationListStatement .toString ();
153
+ }
154
+
155
+ // if (CollectionUtils.isEmpty(setOperationListStatement.getOrderByElements())) {
156
+ if (setOperationListStatement .getOrderByElements () == null ) {
157
+ setOperationListStatement .setOrderByElements (new ArrayList <>());
158
+ }
159
+
160
+ List <OrderByElement > orderByElements = sort .stream () //
161
+ .map (order -> getOrderClause (Collections .emptySet (), Collections .emptySet (), null , order )) //
162
+ .toList ();
163
+ setOperationListStatement .getOrderByElements ().addAll (orderByElements );
164
+
165
+ return setOperationListStatement .toString ();
166
+ }
167
+
130
168
/**
131
169
* Returns the aliases used inside the selection part in the query.
132
170
*
@@ -175,7 +213,12 @@ private Set<String> getJoinAliases(String query) {
175
213
return new HashSet <>();
176
214
}
177
215
178
- return getJoinAliases ((PlainSelect ) parseSelectStatement (query ).getSelectBody ());
216
+ Select selectStatement = parseSelectStatement (query );
217
+ if (selectStatement .getSelectBody ()instanceof PlainSelect selectBody ) {
218
+ return getJoinAliases (selectBody );
219
+ }
220
+
221
+ return new HashSet <>();
179
222
}
180
223
181
224
/**
@@ -259,6 +302,17 @@ private String detectAlias(String query) {
259
302
}
260
303
261
304
Select selectStatement = parseSelectStatement (query );
305
+
306
+ /*
307
+ For all the other types ({@link ValuesStatement} and {@link SetOperationList}) it does not make sense to provide
308
+ alias since:
309
+ * ValuesStatement has no alias
310
+ * SetOperation can have multiple alias for each operation item
311
+ */
312
+ if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
313
+ return null ;
314
+ }
315
+
262
316
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
263
317
return detectAlias (selectBody );
264
318
}
@@ -273,6 +327,10 @@ private String detectAlias(String query) {
273
327
@ Nullable
274
328
private static String detectAlias (PlainSelect selectBody ) {
275
329
330
+ if (selectBody .getFromItem () == null ) {
331
+ return null ;
332
+ }
333
+
276
334
Alias alias = selectBody .getFromItem ().getAlias ();
277
335
return alias == null ? null : alias .getName ();
278
336
}
@@ -287,6 +345,14 @@ public String createCountQueryFor(@Nullable String countProjection) {
287
345
Assert .hasText (this .query .getQueryString (), "OriginalQuery must not be null or empty" );
288
346
289
347
Select selectStatement = parseSelectStatement (this .query .getQueryString ());
348
+
349
+ /*
350
+ We only support count queries for {@link PlainSelect}.
351
+ */
352
+ if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
353
+ return this .query .getQueryString ();
354
+ }
355
+
290
356
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
291
357
292
358
// remove order by
@@ -322,8 +388,15 @@ public String createCountQueryFor(@Nullable String countProjection) {
322
388
Function jSqlCount = getJSqlCount (Collections .singletonList (countProp ), distinct );
323
389
selectBody .setSelectItems (Collections .singletonList (new SelectExpressionItem (jSqlCount )));
324
390
325
- return selectBody .toString ();
391
+ if (CollectionUtils .isEmpty (selectStatement .getWithItemsList ())) {
392
+ return selectBody .toString ();
393
+ }
326
394
395
+ String withStatements = selectStatement .getWithItemsList ().stream () //
396
+ .map (WithItem ::toString ) //
397
+ .collect (Collectors .joining ("," ));
398
+
399
+ return "with " + withStatements + "\n " + selectBody ;
327
400
}
328
401
329
402
@ Override
@@ -336,9 +409,23 @@ public String getProjection() {
336
409
Assert .hasText (query .getQueryString (), "Query must not be null or empty" );
337
410
338
411
Select selectStatement = parseSelectStatement (query .getQueryString ());
339
- PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
340
412
341
- return selectBody .getSelectItems () //
413
+ if (selectStatement .getSelectBody () instanceof ValuesStatement ) {
414
+ return "" ;
415
+ }
416
+
417
+ SelectBody selectBody = selectStatement .getSelectBody ();
418
+
419
+ if (selectStatement .getSelectBody ()instanceof SetOperationList setOperationList ) {
420
+ // using the first one since for setoperations the projection has to be the same
421
+ selectBody = setOperationList .getSelects ().get (0 );
422
+
423
+ if (!(selectBody instanceof PlainSelect )) {
424
+ return "" ;
425
+ }
426
+ }
427
+
428
+ return ((PlainSelect ) selectBody ).getSelectItems () //
342
429
.stream () //
343
430
.map (Object ::toString ) //
344
431
.collect (Collectors .joining (", " )).trim ();
0 commit comments