Skip to content

Commit 43fe8ca

Browse files
author
Jonathan Burnhams
committed
Finished adding pivot support
1 parent a97160a commit 43fe8ca

File tree

7 files changed

+286
-44
lines changed

7 files changed

+286
-44
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2013 JSQLParser
6+
* %%
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation, either version 2.1 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Lesser Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Lesser Public
18+
* License along with this program. If not, see
19+
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
20+
* #L%
21+
*/
22+
package net.sf.jsqlparser.statement.select;
23+
24+
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
25+
26+
public class ExpressionListItem {
27+
28+
private ExpressionList expressionList;
29+
private String alias;
30+
31+
public ExpressionList getExpressionList() {
32+
return expressionList;
33+
}
34+
35+
public void setExpressionList(ExpressionList expressionList) {
36+
this.expressionList = expressionList;
37+
}
38+
39+
public String getAlias() {
40+
return alias;
41+
}
42+
43+
public void setAlias(String string) {
44+
alias = string;
45+
}
46+
47+
@Override
48+
public String toString() {
49+
return expressionList + ((alias != null) ? " AS " + alias : "");
50+
}
51+
}

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,29 @@ public class Pivot {
3131

3232
private List<Column> forColumns;
3333

34-
private List<SelectExpressionItem> inItems;
34+
private List<SelectExpressionItem> singleInItems;
35+
36+
private List<ExpressionListItem> multiInItems;
37+
38+
public void accept(PivotVisitor pivotVisitor) {
39+
pivotVisitor.visit(this);
40+
}
41+
42+
public List<SelectExpressionItem> getSingleInItems() {
43+
return singleInItems;
44+
}
45+
46+
public void setSingleInItems(List<SelectExpressionItem> singleInItems) {
47+
this.singleInItems = singleInItems;
48+
}
49+
50+
public List<ExpressionListItem> getMultiInItems() {
51+
return multiInItems;
52+
}
53+
54+
public void setMultiInItems(List<ExpressionListItem> multiInItems) {
55+
this.multiInItems = multiInItems;
56+
}
3557

3658
public List<FunctionItem> getFunctionItems() {
3759
return functionItems;
@@ -49,19 +71,15 @@ public void setForColumns(List<Column> forColumns) {
4971
this.forColumns = forColumns;
5072
}
5173

52-
public List<SelectExpressionItem> getInItems() {
53-
return inItems;
54-
}
55-
56-
public void setInItems(List<SelectExpressionItem> inItems) {
57-
this.inItems = inItems;
74+
public List<?> getInItems() {
75+
return singleInItems == null ? multiInItems : singleInItems;
5876
}
5977

6078
@Override
6179
public String toString() {
6280
return "PIVOT (" +
6381
PlainSelect.getStringList(functionItems) +
64-
" FOR " + PlainSelect.getStringList(forColumns, true, forColumns.size() > 1) +
65-
" IN " + PlainSelect.getStringList(inItems, true, true) + ")";
82+
" FOR " + PlainSelect.getStringList(forColumns, true, forColumns != null && forColumns.size() > 1) +
83+
" IN " + PlainSelect.getStringList(getInItems(), true, true) + ")";
6684
}
6785
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2013 JSQLParser
6+
* %%
7+
* This program is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Lesser General Public License as
9+
* published by the Free Software Foundation, either version 2.1 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Lesser Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Lesser Public
18+
* License along with this program. If not, see
19+
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
20+
* #L%
21+
*/
22+
package net.sf.jsqlparser.statement.select;
23+
24+
public interface PivotVisitor {
25+
26+
void visit(Pivot pivot);
27+
28+
void visit(PivotXml pivot);
29+
30+
}

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,43 @@
2121
*/
2222
package net.sf.jsqlparser.statement.select;
2323

24+
import net.sf.jsqlparser.schema.Column;
25+
26+
import java.util.List;
27+
2428
public class PivotXml extends Pivot {
2529

30+
private SelectBody inSelect;
31+
private boolean inAny = false;
32+
33+
public void accept(PivotVisitor pivotVisitor) {
34+
pivotVisitor.visit(this);
35+
}
36+
37+
public SelectBody getInSelect() {
38+
return inSelect;
39+
}
40+
41+
public void setInSelect(SelectBody inSelect) {
42+
this.inSelect = inSelect;
43+
}
44+
45+
public boolean isInAny() {
46+
return inAny;
47+
}
48+
49+
public void setInAny(boolean inAny) {
50+
this.inAny = inAny;
51+
}
52+
53+
@Override
54+
public String toString() {
55+
List<Column> forColumns = getForColumns();
56+
String in = inAny ? "ANY" : inSelect == null ? PlainSelect.getStringList(getInItems()) : inSelect.toString();
57+
return "PIVOT XML (" +
58+
PlainSelect.getStringList(getFunctionItems()) +
59+
" FOR " + PlainSelect.getStringList(forColumns, true, forColumns != null && forColumns.size() > 1) +
60+
" IN (" + in + "))";
61+
}
62+
2663
}

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

100644100755
Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,20 @@
2121
*/
2222
package net.sf.jsqlparser.util.deparser;
2323

24-
import java.util.Iterator;
25-
import java.util.List;
26-
2724
import net.sf.jsqlparser.expression.Expression;
2825
import net.sf.jsqlparser.expression.ExpressionVisitor;
2926
import net.sf.jsqlparser.schema.Column;
3027
import net.sf.jsqlparser.schema.Table;
31-
import net.sf.jsqlparser.statement.select.AllColumns;
32-
import net.sf.jsqlparser.statement.select.AllTableColumns;
33-
import net.sf.jsqlparser.statement.select.FromItem;
34-
import net.sf.jsqlparser.statement.select.FromItemVisitor;
35-
import net.sf.jsqlparser.statement.select.Join;
36-
import net.sf.jsqlparser.statement.select.LateralSubSelect;
37-
import net.sf.jsqlparser.statement.select.Limit;
38-
import net.sf.jsqlparser.statement.select.OrderByElement;
39-
import net.sf.jsqlparser.statement.select.OrderByVisitor;
40-
import net.sf.jsqlparser.statement.select.PlainSelect;
41-
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
42-
import net.sf.jsqlparser.statement.select.SelectItem;
43-
import net.sf.jsqlparser.statement.select.SelectItemVisitor;
44-
import net.sf.jsqlparser.statement.select.SelectVisitor;
45-
import net.sf.jsqlparser.statement.select.SetOperationList;
46-
import net.sf.jsqlparser.statement.select.SubJoin;
47-
import net.sf.jsqlparser.statement.select.SubSelect;
48-
import net.sf.jsqlparser.statement.select.Top;
49-
import net.sf.jsqlparser.statement.select.ValuesList;
50-
import net.sf.jsqlparser.statement.select.WithItem;
28+
import net.sf.jsqlparser.statement.select.*;
29+
30+
import java.util.Iterator;
31+
import java.util.List;
5132

5233
/**
5334
* A class to de-parse (that is, tranform from JSqlParser hierarchy into a
5435
* string) a {@link net.sf.jsqlparser.statement.select.Select}
5536
*/
56-
public class SelectDeParser implements SelectVisitor, OrderByVisitor, SelectItemVisitor, FromItemVisitor {
37+
public class SelectDeParser implements SelectVisitor, OrderByVisitor, SelectItemVisitor, FromItemVisitor, PivotVisitor {
5738

5839
private StringBuilder buffer;
5940
private ExpressionVisitor expressionVisitor;
@@ -190,12 +171,46 @@ public void visit(SubSelect subSelect) {
190171
@Override
191172
public void visit(Table tableName) {
192173
buffer.append(tableName.getWholeTableName());
174+
Pivot pivot = tableName.getPivot();
175+
if (pivot != null) {
176+
pivot.accept(this);
177+
}
193178
String alias = tableName.getAlias();
194179
if (alias != null && !alias.isEmpty()) {
195180
buffer.append(" AS ").append(alias);
196181
}
197182
}
198183

184+
@Override
185+
public void visit(Pivot pivot) {
186+
List<Column> forColumns = pivot.getForColumns();
187+
buffer.append(" PIVOT (")
188+
.append(PlainSelect.getStringList(pivot.getFunctionItems()))
189+
.append(" FOR ")
190+
.append(PlainSelect.getStringList(forColumns, true, forColumns != null && forColumns.size() > 1))
191+
.append(" IN ")
192+
.append(PlainSelect.getStringList(pivot.getInItems(), true, true))
193+
.append(")");
194+
}
195+
196+
@Override
197+
public void visit(PivotXml pivot) {
198+
List<Column> forColumns = pivot.getForColumns();
199+
buffer.append(" PIVOT XML (")
200+
.append(PlainSelect.getStringList(pivot.getFunctionItems()))
201+
.append(" FOR ")
202+
.append(PlainSelect.getStringList(forColumns, true, forColumns != null && forColumns.size() > 1))
203+
.append(" IN (");
204+
if (pivot.isInAny()) {
205+
buffer.append("ANY");
206+
} else if (pivot.getInSelect() != null) {
207+
buffer.append(pivot.getInSelect());
208+
} else {
209+
buffer.append(PlainSelect.getStringList(pivot.getInItems()));
210+
}
211+
buffer.append("))");
212+
}
213+
199214
public void deparseOrderBy(List<OrderByElement> orderByElements) {
200215
buffer.append(" ORDER BY ");
201216
for (Iterator<OrderByElement> iter = orderByElements.iterator(); iter.hasNext();) {

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

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ import net.sf.jsqlparser.statement.select.PlainSelect;
132132
import net.sf.jsqlparser.statement.select.Pivot;
133133
import net.sf.jsqlparser.statement.select.PivotXml;
134134
import net.sf.jsqlparser.statement.select.FunctionItem;
135+
import net.sf.jsqlparser.statement.select.ExpressionListItem;
135136
import net.sf.jsqlparser.statement.select.Select;
136137
import net.sf.jsqlparser.statement.select.SelectBody;
137138
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
@@ -805,11 +806,11 @@ List<FunctionItem> PivotFunctionItems():
805806
}
806807
{
807808
item = FunctionItem() {functionItems.add(item);}
808-
("," item = FunctionItem() {functionItems.add(item);} )*
809+
( "," item = FunctionItem() {functionItems.add(item);} )*
809810
{ return functionItems; }
810811
}
811812

812-
List<SelectExpressionItem> PivotInItems():
813+
List<SelectExpressionItem> PivotSingleInItems():
813814
{
814815
List<SelectExpressionItem> retval = new ArrayList<SelectExpressionItem>();
815816
SelectExpressionItem item;
@@ -820,31 +821,86 @@ List<SelectExpressionItem> PivotInItems():
820821
{ return retval; }
821822
}
822823

824+
825+
ExpressionListItem ExpressionListItem():
826+
{
827+
ExpressionListItem expressionListItem = null;
828+
ExpressionList expressionList = null;
829+
String alias = null;
830+
}
831+
{
832+
"("
833+
expressionList=SimpleExpressionList() { expressionListItem = new ExpressionListItem(); expressionListItem.setExpressionList(expressionList); }
834+
")"
835+
[alias=Alias() { expressionListItem.setAlias(alias); }]
836+
{ return expressionListItem; }
837+
}
838+
839+
840+
List<ExpressionListItem> PivotMultiInItems():
841+
{
842+
List<ExpressionListItem> retval = new ArrayList<ExpressionListItem>();
843+
ExpressionListItem item;
844+
}
845+
{
846+
item = ExpressionListItem() {retval.add(item);}
847+
("," item = ExpressionListItem() {retval.add(item);} )*
848+
{ return retval; }
849+
}
850+
823851
Pivot Pivot():
824852
{
825853
Pivot retval = new Pivot();
826854
List<FunctionItem> functionItems;
827855
List<Column> forColumns;
828-
List<SelectExpressionItem> inItems;
856+
List<SelectExpressionItem> singleInItems = null;
857+
List<ExpressionListItem> multiInItems = null;
829858
}
830859
{
831860
<K_PIVOT> "(" functionItems = PivotFunctionItems() <K_FOR>
832-
(forColumns = PivotForColumn() | forColumns = PivotForColumns())
833-
<K_IN> "(" inItems = PivotInItems() ")"
861+
( forColumns = PivotForColumn() | forColumns = PivotForColumns() )
862+
<K_IN> "("
863+
(LOOKAHEAD(3) singleInItems = PivotSingleInItems() | multiInItems = PivotMultiInItems() )
864+
")"
834865
")"
835866
{
836867
retval.setFunctionItems(functionItems);
837868
retval.setForColumns(forColumns);
838-
retval.setInItems(inItems);
869+
retval.setSingleInItems(singleInItems);
870+
retval.setMultiInItems(multiInItems);
839871
return retval;
840872
}
841873
}
842874

843875
PivotXml PivotXml():
844-
{ PivotXml retval = new PivotXml(); }
845876
{
846-
<K_PIVOT> <K_XML>
847-
{ return retval; }
877+
PivotXml retval = new PivotXml();
878+
List<FunctionItem> functionItems;
879+
List<Column> forColumns;
880+
List<SelectExpressionItem> singleInItems = null;
881+
List<ExpressionListItem> multiInItems = null;
882+
SelectBody inSelect = null;
883+
}
884+
{
885+
<K_PIVOT> <K_XML> "(" functionItems = PivotFunctionItems() <K_FOR>
886+
( forColumns = PivotForColumn() | forColumns = PivotForColumns() )
887+
<K_IN> "("
888+
(
889+
<K_ANY> { retval.setInAny(true); } |
890+
LOOKAHEAD(1) inSelect = SelectBody() |
891+
LOOKAHEAD(2) singleInItems = PivotSingleInItems() |
892+
multiInItems = PivotMultiInItems()
893+
)
894+
")"
895+
")"
896+
{
897+
retval.setFunctionItems(functionItems);
898+
retval.setForColumns(forColumns);
899+
retval.setSingleInItems(singleInItems);
900+
retval.setMultiInItems(multiInItems);
901+
retval.setInSelect(inSelect);
902+
return retval;
903+
}
848904
}
849905

850906
void IntoClause():
@@ -880,7 +936,7 @@ FromItem FromItem():
880936
|
881937
fromItem=LateralSubSelect()
882938
)
883-
[LOOKAHEAD(2) pivot=PivotXml()|pivot=Pivot() { fromItem.setPivot(pivot); } ]
939+
[(LOOKAHEAD(2) pivot=PivotXml()|pivot=Pivot()) { fromItem.setPivot(pivot); } ]
884940
[alias=Alias() { fromItem.setAlias(alias); } ]
885941
)
886942
)

0 commit comments

Comments
 (0)