Skip to content

Commit 6b51f26

Browse files
committed
multi value expression for select included
1 parent 898f369 commit 6b51f26

File tree

7 files changed

+222
-18
lines changed

7 files changed

+222
-18
lines changed

src/main/java/net/sf/jsqlparser/expression/operators/relational/MultiExpressionList.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@
1919
package net.sf.jsqlparser.expression.operators.relational;
2020

2121
import java.util.ArrayList;
22+
import java.util.Arrays;
2223
import java.util.Iterator;
2324
import java.util.List;
25+
import net.sf.jsqlparser.expression.Expression;
26+
import net.sf.jsqlparser.statement.select.FromItem;
27+
import net.sf.jsqlparser.statement.select.FromItemVisitor;
2428

2529
/**
2630
* A list of ExpressionList items. e.g. multi values of insert statements. This one allows
2731
* only equally sized ExpressionList.
2832
* @author toben
2933
*/
3034
public class MultiExpressionList implements ItemsList {
31-
3235
List<ExpressionList> exprList;
3336

3437
public MultiExpressionList() {
@@ -53,6 +56,14 @@ public void addExpressionList(ExpressionList el) {
5356
exprList.add(el);
5457
}
5558

59+
public void addExpressionList(List<Expression> list) {
60+
addExpressionList(new ExpressionList(list));
61+
}
62+
63+
public void addExpressionList(Expression expr) {
64+
addExpressionList(new ExpressionList(Arrays.asList(expr)));
65+
}
66+
5667
@Override
5768
public String toString() {
5869
StringBuilder b = new StringBuilder();

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ public interface FromItemVisitor {
3131
public void visit(SubJoin subjoin);
3232

3333
public void visit(LateralSubSelect lateralSubSelect);
34+
35+
public void visit(ValuesList valuesList);
3436
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* Copyright (C) 2013 toben.
3+
*
4+
* This library is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU Lesser General Public
6+
* License as published by the Free Software Foundation; either
7+
* version 2.1 of the License, or (at your option) any later version.
8+
*
9+
* This library is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+
* Lesser General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Lesser General Public
15+
* License along with this library; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17+
* MA 02110-1301 USA
18+
*/
19+
package net.sf.jsqlparser.statement.select;
20+
21+
import java.util.Iterator;
22+
import java.util.List;
23+
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
24+
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
25+
26+
/**
27+
* This is a container for a values item within a select statement. It holds
28+
* some syntactical stuff that differs from values within an insert statement.
29+
*
30+
* @author toben
31+
*/
32+
public class ValuesList implements FromItem {
33+
34+
private String alias;
35+
private MultiExpressionList multiExpressionList;
36+
private boolean noBrackets = false;
37+
private List<String> columnNames;
38+
39+
public ValuesList() {
40+
}
41+
42+
public ValuesList(MultiExpressionList multiExpressionList) {
43+
this.multiExpressionList = multiExpressionList;
44+
}
45+
46+
@Override
47+
public void accept(FromItemVisitor fromItemVisitor) {
48+
fromItemVisitor.visit(this);
49+
}
50+
51+
@Override
52+
public String getAlias() {
53+
return alias;
54+
}
55+
56+
@Override
57+
public void setAlias(String alias) {
58+
this.alias = alias;
59+
}
60+
61+
public MultiExpressionList getMultiExpressionList() {
62+
return multiExpressionList;
63+
}
64+
65+
public void setMultiExpressionList(MultiExpressionList multiExpressionList) {
66+
this.multiExpressionList = multiExpressionList;
67+
}
68+
69+
public boolean isNoBrackets() {
70+
return noBrackets;
71+
}
72+
73+
public void setNoBrackets(boolean noBrackets) {
74+
this.noBrackets = noBrackets;
75+
}
76+
77+
@Override
78+
public String toString() {
79+
StringBuilder b = new StringBuilder();
80+
81+
b.append("(VALUES ");
82+
for (Iterator<ExpressionList> it = getMultiExpressionList().getExprList().iterator(); it.hasNext();) {
83+
b.append(PlainSelect.getStringList(it.next().getExpressions(), true, !isNoBrackets()));
84+
if (it.hasNext()) {
85+
b.append(", ");
86+
}
87+
}
88+
b.append(")");
89+
if (alias != null) {
90+
b.append(" AS ").append(alias);
91+
92+
if (columnNames != null) {
93+
b.append("(");
94+
for (Iterator<String> it = columnNames.iterator(); it.hasNext();) {
95+
b.append(it.next());
96+
if (it.hasNext()) {
97+
b.append(", ");
98+
}
99+
}
100+
b.append(")");
101+
}
102+
}
103+
return b.toString();
104+
}
105+
106+
public List<String> getColumnNames() {
107+
return columnNames;
108+
}
109+
110+
public void setColumnNames(List<String> columnNames) {
111+
this.columnNames = columnNames;
112+
}
113+
}

src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import net.sf.jsqlparser.statement.select.SetOperationList;
6262
import net.sf.jsqlparser.statement.select.SubJoin;
6363
import net.sf.jsqlparser.statement.select.SubSelect;
64+
import net.sf.jsqlparser.statement.select.ValuesList;
6465
import net.sf.jsqlparser.statement.select.WithItem;
6566

6667
/**
@@ -285,7 +286,6 @@ public void visit(TimeValue timeValue) {
285286
*/
286287
@Override
287288
public void visit(CaseExpression caseExpression) {
288-
// TODO Auto-generated method stub
289289
}
290290

291291
/*
@@ -295,7 +295,6 @@ public void visit(CaseExpression caseExpression) {
295295
*/
296296
@Override
297297
public void visit(WhenClause whenClause) {
298-
// TODO Auto-generated method stub
299298
}
300299

301300
@Override
@@ -375,4 +374,8 @@ public void visit(MultiExpressionList multiExprList) {
375374
exprList.accept(this);
376375
}
377376
}
377+
378+
@Override
379+
public void visit(ValuesList valuesList) {
380+
}
378381
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import net.sf.jsqlparser.expression.Expression;
77
import net.sf.jsqlparser.expression.ExpressionVisitor;
8+
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
89
import net.sf.jsqlparser.schema.Column;
910
import net.sf.jsqlparser.schema.Table;
1011
import net.sf.jsqlparser.statement.select.AllColumns;
@@ -25,6 +26,7 @@
2526
import net.sf.jsqlparser.statement.select.SubJoin;
2627
import net.sf.jsqlparser.statement.select.SubSelect;
2728
import net.sf.jsqlparser.statement.select.Top;
29+
import net.sf.jsqlparser.statement.select.ValuesList;
2830
import net.sf.jsqlparser.statement.select.WithItem;
2931

3032
/**
@@ -306,4 +308,9 @@ public void visit(WithItem withItem) {
306308
public void visit(LateralSubSelect lateralSubSelect) {
307309
buffer.append(lateralSubSelect.toString());
308310
}
311+
312+
@Override
313+
public void visit(ValuesList valuesList) {
314+
buffer.append(valuesList.toString());
315+
}
309316
}

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

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ import net.sf.jsqlparser.statement.select.MinusOp;
140140
import net.sf.jsqlparser.statement.select.ExceptOp;
141141
import net.sf.jsqlparser.statement.select.IntersectOp;
142142
import net.sf.jsqlparser.statement.select.WithItem;
143+
import net.sf.jsqlparser.statement.select.ValuesList;
143144
import net.sf.jsqlparser.statement.truncate.Truncate;
144145
import net.sf.jsqlparser.statement.update.Update;
145146

@@ -413,7 +414,7 @@ Insert Insert():
413414
}
414415
primaryExpList = new ArrayList<Expression>();
415416
primaryExpList.add(exp); }
416-
("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { multiExpr.addExpressionList(new ExpressionList(primaryExpList)); } )*
417+
("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { multiExpr.addExpressionList(primaryExpList); } )*
417418

418419
|
419420

@@ -774,28 +775,75 @@ FromItem FromItem():
774775
}
775776
{
776777
(
777-
(
778-
"("
779-
(
780-
LOOKAHEAD(SubJoin())
781-
fromItem=SubJoin()
782-
|
783-
fromItem=SubSelect()
778+
LOOKAHEAD(ValuesList()) fromItem=ValuesList()
779+
|
780+
(
781+
(
782+
(
783+
"("
784+
(
785+
LOOKAHEAD(SubJoin())
786+
fromItem=SubJoin()
787+
|
788+
fromItem=SubSelect()
789+
)
790+
")"
784791
)
785-
")"
792+
|
793+
fromItem=Table()
794+
|
795+
fromItem=LateralSubSelect()
796+
)
797+
798+
[alias=Alias() { fromItem.setAlias(alias); } ]
786799
)
787-
|
788-
fromItem=Table()
789-
|
790-
fromItem=LateralSubSelect()
791800
)
792-
793-
[alias=Alias() { fromItem.setAlias(alias); } ]
794801
{
795802
return fromItem;
796803
}
797804
}
798805

806+
FromItem ValuesList():
807+
{
808+
MultiExpressionList exprList = new MultiExpressionList();
809+
List<Expression> primaryExpList = new ArrayList<Expression>();
810+
ValuesList valuesList = new ValuesList();
811+
Expression exp = null;
812+
List<String> colNames = null;
813+
String colName;
814+
String alias;
815+
}
816+
{
817+
"("
818+
<K_VALUES>
819+
(LOOKAHEAD(3) ("(" exp=SimpleExpression() { primaryExpList.add(exp); }
820+
("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { exprList.addExpressionList(primaryExpList); }
821+
822+
("," "(" exp=SimpleExpression() {
823+
primaryExpList = new ArrayList<Expression>();
824+
primaryExpList.add(exp); }
825+
("," exp=SimpleExpression() { primaryExpList.add(exp); } )* ")" { exprList.addExpressionList(primaryExpList); } )*)
826+
|
827+
( exp=SimpleExpression() { exprList.addExpressionList(exp); valuesList.setNoBrackets(true); }
828+
("," exp=SimpleExpression() { exprList.addExpressionList(exp);} )*
829+
))
830+
")"
831+
832+
[alias=Alias() { valuesList.setAlias(alias); }
833+
834+
[ "("
835+
colName = RelObjectName() { colNames = new ArrayList<String>(); colNames.add(colName); }
836+
( "," colName = RelObjectName() { colNames.add(colName); } )*
837+
")" { valuesList.setColumnNames(colNames); } ]
838+
839+
]
840+
841+
{
842+
valuesList.setMultiExpressionList(exprList);
843+
return valuesList;
844+
}
845+
}
846+
799847
LateralSubSelect LateralSubSelect():
800848
{
801849
LateralSubSelect lateralSubSelect = new LateralSubSelect();

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,26 @@ public void testLateralComplex1() throws IOException, JSQLParserException {
765765
Select select = (Select) parserManager.parse(new StringReader(stmt));
766766
assertEquals("SELECT O.ORDERID, O.CUSTNAME, OL.LINETOTAL, OC.ORDCHGTOTAL, OT.TAXTOTAL FROM ORDERS AS O, LATERAL(SELECT SUM(NETAMT) AS LINETOTAL FROM ORDERLINES AS LINES WHERE LINES.ORDERID = O.ORDERID) AS OL, LATERAL(SELECT SUM(CHGAMT) AS ORDCHGTOTAL FROM ORDERCHARGES AS CHARGES WHERE LINES.ORDERID = O.ORDERID) AS OC, LATERAL(SELECT SUM(TAXAMT) AS TAXTOTAL FROM ORDERTAXES AS TAXES WHERE TAXES.ORDERID = O.ORDERID) AS OT", select.toString());
767767
}
768+
769+
public void testValues() throws JSQLParserException {
770+
String stmt = "SELECT * FROM (VALUES (1, 2), (3, 4)) AS test";
771+
assertSqlCanBeParsedAndDeparsed(stmt);
772+
}
773+
774+
public void testValues2() throws JSQLParserException {
775+
String stmt = "SELECT * FROM (VALUES 1, 2, 3, 4) AS test";
776+
assertSqlCanBeParsedAndDeparsed(stmt);
777+
}
778+
779+
public void testValues3() throws JSQLParserException {
780+
String stmt = "SELECT * FROM (VALUES 1, 2, 3, 4) AS test(a)";
781+
assertSqlCanBeParsedAndDeparsed(stmt);
782+
}
783+
784+
public void testValues4() throws JSQLParserException {
785+
String stmt = "SELECT * FROM (VALUES (1, 2), (3, 4)) AS test(a, b)";
786+
assertSqlCanBeParsedAndDeparsed(stmt);
787+
}
768788

769789
private void assertSqlCanBeParsedAndDeparsed(String statement) throws JSQLParserException {
770790
Statement parsed = parserManager.parse(new StringReader(statement));

0 commit comments

Comments
 (0)