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,14 @@ 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 ) {
116
+ SetOperationList setOperationList = (SetOperationList ) selectStatement .getSelectBody ();
117
+ return applySortingToSetOperationList (setOperationList , sort );
118
+ } else if (!(selectStatement .getSelectBody () instanceof PlainSelect )) {
119
+ return queryString ;
120
+ }
121
+
110
122
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
111
123
112
124
final Set <String > joinAliases = getJoinAliases (selectBody );
@@ -127,6 +139,33 @@ public String applySorting(Sort sort, @Nullable String alias) {
127
139
128
140
}
129
141
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
+
130
169
/**
131
170
* Returns the aliases used inside the selection part in the query.
132
171
*
@@ -175,7 +214,13 @@ private Set<String> getJoinAliases(String query) {
175
214
return new HashSet <>();
176
215
}
177
216
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 <>();
179
224
}
180
225
181
226
/**
@@ -259,6 +304,17 @@ private String detectAlias(String query) {
259
304
}
260
305
261
306
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
+
262
318
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
263
319
return detectAlias (selectBody );
264
320
}
@@ -273,6 +329,10 @@ private String detectAlias(String query) {
273
329
@ Nullable
274
330
private static String detectAlias (PlainSelect selectBody ) {
275
331
332
+ if (selectBody .getFromItem () == null ) {
333
+ return null ;
334
+ }
335
+
276
336
Alias alias = selectBody .getFromItem ().getAlias ();
277
337
return alias == null ? null : alias .getName ();
278
338
}
@@ -287,6 +347,14 @@ public String createCountQueryFor(@Nullable String countProjection) {
287
347
Assert .hasText (this .query .getQueryString (), "OriginalQuery must not be null or empty!" );
288
348
289
349
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
+
290
358
PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
291
359
292
360
// remove order by
@@ -322,8 +390,15 @@ public String createCountQueryFor(@Nullable String countProjection) {
322
390
Function jSqlCount = getJSqlCount (Collections .singletonList (countProp ), distinct );
323
391
selectBody .setSelectItems (Collections .singletonList (new SelectExpressionItem (jSqlCount )));
324
392
325
- return selectBody .toString ();
393
+ if (CollectionUtils .isEmpty (selectStatement .getWithItemsList ())) {
394
+ return selectBody .toString ();
395
+ }
326
396
397
+ String withStatements = selectStatement .getWithItemsList ().stream () //
398
+ .map (WithItem ::toString ) //
399
+ .collect (Collectors .joining ("," ));
400
+
401
+ return "with " + withStatements + "\n " + selectBody ;
327
402
}
328
403
329
404
@ Override
@@ -336,9 +411,24 @@ public String getProjection() {
336
411
Assert .hasText (query .getQueryString (), "Query must not be null or empty!" );
337
412
338
413
Select selectStatement = parseSelectStatement (query .getQueryString ());
339
- PlainSelect selectBody = (PlainSelect ) selectStatement .getSelectBody ();
340
414
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 () //
342
432
.stream () //
343
433
.map (Object ::toString ) //
344
434
.collect (Collectors .joining (", " )).trim ();
0 commit comments