Skip to content

Commit c9b58b2

Browse files
committed
fixes #119
1 parent a3fc1f2 commit c9b58b2

File tree

5 files changed

+87
-64
lines changed

5 files changed

+87
-64
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ Also I would like to know about needed examples or documentation stuff.
3434

3535
## Extensions in the latest SNAPSHOT version 0.9.3
3636

37+
* support for with recursive
38+
39+
```sql
40+
WITH RECURSIVE data as (SELECT ...) ...
41+
```
42+
3743
* support for oracles old join syntax improved
3844

3945
```sql

src/main/java/net/sf/jsqlparser/statement/select/WithItem.java

Lines changed: 57 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,60 +28,69 @@
2828
*/
2929
public class WithItem implements SelectBody {
3030

31-
private String name;
32-
private List<SelectItem> withItemList;
33-
private SelectBody selectBody;
31+
private String name;
32+
private List<SelectItem> withItemList;
33+
private SelectBody selectBody;
34+
private boolean recursive;
3435

35-
/**
36-
* The name of this WITH item (for example, "myWITH" in "WITH myWITH AS
37-
* (SELECT A,B,C))"
38-
*
39-
* @return the name of this WITH
40-
*/
41-
public String getName() {
42-
return name;
43-
}
36+
/**
37+
* The name of this WITH item (for example, "myWITH" in "WITH myWITH AS
38+
* (SELECT A,B,C))"
39+
*
40+
* @return the name of this WITH
41+
*/
42+
public String getName() {
43+
return name;
44+
}
4445

45-
public void setName(String name) {
46-
this.name = name;
47-
}
46+
public void setName(String name) {
47+
this.name = name;
48+
}
4849

49-
/**
50-
* The {@link SelectBody} of this WITH item is the part after the "AS"
51-
* keyword
52-
*
53-
* @return {@link SelectBody} of this WITH item
54-
*/
55-
public SelectBody getSelectBody() {
56-
return selectBody;
57-
}
50+
public boolean isRecursive() {
51+
return recursive;
52+
}
5853

59-
public void setSelectBody(SelectBody selectBody) {
60-
this.selectBody = selectBody;
61-
}
54+
public void setRecursive(boolean recursive) {
55+
this.recursive = recursive;
56+
}
6257

63-
/**
64-
* The {@link SelectItem}s in this WITH (for example the A,B,C in "WITH
65-
* mywith (A,B,C) AS ...")
66-
*
67-
* @return a list of {@link SelectItem}s
68-
*/
69-
public List<SelectItem> getWithItemList() {
70-
return withItemList;
71-
}
58+
/**
59+
* The {@link SelectBody} of this WITH item is the part after the "AS"
60+
* keyword
61+
*
62+
* @return {@link SelectBody} of this WITH item
63+
*/
64+
public SelectBody getSelectBody() {
65+
return selectBody;
66+
}
7267

73-
public void setWithItemList(List<SelectItem> withItemList) {
74-
this.withItemList = withItemList;
75-
}
68+
public void setSelectBody(SelectBody selectBody) {
69+
this.selectBody = selectBody;
70+
}
7671

77-
@Override
78-
public String toString() {
79-
return name + ((withItemList != null) ? " " + PlainSelect.getStringList(withItemList, true, true) : "")
80-
+ " AS (" + selectBody + ")";
81-
}
72+
/**
73+
* The {@link SelectItem}s in this WITH (for example the A,B,C in "WITH
74+
* mywith (A,B,C) AS ...")
75+
*
76+
* @return a list of {@link SelectItem}s
77+
*/
78+
public List<SelectItem> getWithItemList() {
79+
return withItemList;
80+
}
8281

83-
@Override
84-
public void accept(SelectVisitor visitor) {
85-
visitor.visit(this);
86-
}
82+
public void setWithItemList(List<SelectItem> withItemList) {
83+
this.withItemList = withItemList;
84+
}
85+
86+
@Override
87+
public String toString() {
88+
return (recursive ? "RECURSIVE " : "") + name + ((withItemList != null) ? " " + PlainSelect.getStringList(withItemList, true, true) : "")
89+
+ " AS (" + selectBody + ")";
90+
}
91+
92+
@Override
93+
public void accept(SelectVisitor visitor) {
94+
visitor.visit(this);
95+
}
8796
}

src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -288,33 +288,33 @@ public void deparseLimit(Limit limit) {
288288

289289
public void deparseOffset(Offset offset) {
290290
// OFFSET offset
291-
// or OFFSET offset (ROW | ROWS)
291+
// or OFFSET offset (ROW | ROWS)
292292
if (offset.isOffsetJdbcParameter()) {
293293
buffer.append(" OFFSET ?");
294294
} else if (offset.getOffset() != 0) {
295295
buffer.append(" OFFSET ");
296296
buffer.append(offset.getOffset());
297297
}
298298
if (offset.getOffsetParam() != null) {
299-
buffer.append(" ").append(offset.getOffsetParam());
299+
buffer.append(" ").append(offset.getOffsetParam());
300300
}
301301

302302
}
303303

304304
public void deparseFetch(Fetch fetch) {
305305
// FETCH (FIRST | NEXT) row_count (ROW | ROWS) ONLY
306-
buffer.append(" FETCH ");
307-
if (fetch.isFetchParamFirst()) {
308-
buffer.append("FIRST ");
309-
} else {
310-
buffer.append("NEXT ");
311-
}
312-
if (fetch.isFetchJdbcParameter()) {
313-
buffer.append("?");
314-
} else {
315-
buffer.append(fetch.getRowCount());
316-
}
317-
buffer.append(" ").append(fetch.getFetchParam()).append(" ONLY");
306+
buffer.append(" FETCH ");
307+
if (fetch.isFetchParamFirst()) {
308+
buffer.append("FIRST ");
309+
} else {
310+
buffer.append("NEXT ");
311+
}
312+
if (fetch.isFetchJdbcParameter()) {
313+
buffer.append("?");
314+
} else {
315+
buffer.append(fetch.getRowCount());
316+
}
317+
buffer.append(" ").append(fetch.getFetchParam()).append(" ONLY");
318318

319319
}
320320

@@ -421,8 +421,11 @@ public void visit(SetOperationList list) {
421421

422422
@Override
423423
public void visit(WithItem withItem) {
424+
if (withItem.isRecursive()) {
425+
buffer.append("RECURSIVE ");
426+
}
424427
buffer.append(withItem.getName());
425-
if (withItem.getWithItemList()!=null) {
428+
if (withItem.getWithItemList() != null) {
426429
buffer.append(" ").append(PlainSelect.getStringList(withItem.getWithItemList(), true, true));
427430
}
428431
buffer.append(" AS (");

src/main/javacc/net/sf/jsqlparser/parser/JSqlParserCC.jj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
208208
| <K_UNIQUE:"UNIQUE">
209209
| <K_WITHIN:"WITHIN">
210210
| <K_IF:"IF">
211+
| <K_RECURSIVE:"RECURSIVE">
211212
}
212213

213214
TOKEN : /* Numeric Constants */
@@ -699,7 +700,7 @@ WithItem WithItem():
699700
SelectBody selectBody = null;
700701
}
701702
{
702-
name=RelObjectName() { with.setName(name); }
703+
[ <K_RECURSIVE> { with.setRecursive(true); } ] name=RelObjectName() { with.setName(name); }
703704
[ "(" selectItems=SelectItemsList() ")" { with.setWithItemList(selectItems); } ]
704705
<K_AS>
705706
"(" selectBody = SelectBody() { with.setSelectBody(selectBody); } ")"

src/test/java/net/sf/jsqlparser/test/select/SelectTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,10 @@ public void testWith() throws JSQLParserException {
891891
+ "WHERE THIS_EMP.JOB = 'SALESREP' AND THIS_EMP.WORKDEPT = DINFO.DEPTNO";
892892
assertSqlCanBeParsedAndDeparsed(statement);
893893
}
894+
895+
public void testWithRecursive() throws JSQLParserException {
896+
assertSqlCanBeParsedAndDeparsed("WITH RECURSIVE t (n) AS ((SELECT 1) UNION ALL (SELECT n + 1 FROM t WHERE n < 100)) SELECT sum(n) FROM t");
897+
}
894898

895899
public void testSelectAliasInQuotes() throws JSQLParserException {
896900
String statement = "SELECT mycolumn AS \"My Column Name\" FROM mytable";

0 commit comments

Comments
 (0)