Skip to content

Commit d662484

Browse files
committed
Merge origin/master
2 parents 48a1133 + e6c91b6 commit d662484

File tree

13 files changed

+232
-33
lines changed

13 files changed

+232
-33
lines changed

src/main/java/net/sf/jsqlparser/expression/CastExpression.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,30 @@ public class CastExpression extends ASTNodeAccessImpl implements Expression {
1616

1717
private Expression leftExpression;
1818
private ColDataType type;
19+
private RowConstructor rowConstructor;
1920
private boolean useCastKeyword = true;
21+
22+
public RowConstructor getRowConstructor() {
23+
return rowConstructor;
24+
}
25+
26+
public void setRowConstructor(RowConstructor rowConstructor) {
27+
this.rowConstructor = rowConstructor;
28+
this.type = null;
29+
}
30+
31+
public CastExpression withRowConstructor(RowConstructor rowConstructor) {
32+
setRowConstructor(rowConstructor);
33+
return this;
34+
}
2035

2136
public ColDataType getType() {
2237
return type;
2338
}
2439

2540
public void setType(ColDataType type) {
2641
this.type = type;
42+
this.rowConstructor = null;
2743
}
2844

2945
public Expression getLeftExpression() {
@@ -50,7 +66,9 @@ public void setUseCastKeyword(boolean useCastKeyword) {
5066
@Override
5167
public String toString() {
5268
if (useCastKeyword) {
53-
return "CAST(" + leftExpression + " AS " + type.toString() + ")";
69+
return rowConstructor!=null
70+
? "CAST(" + leftExpression + " AS " + rowConstructor.toString() + ")"
71+
: "CAST(" + leftExpression + " AS " + type.toString() + ")";
5472
} else {
5573
return leftExpression + "::" + type.toString();
5674
}

src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import net.sf.jsqlparser.expression.operators.conditional.XorExpression;
1616
import net.sf.jsqlparser.expression.operators.relational.*;
1717
import net.sf.jsqlparser.schema.Column;
18+
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
1819
import net.sf.jsqlparser.statement.select.AllColumns;
1920
import net.sf.jsqlparser.statement.select.AllTableColumns;
2021
import net.sf.jsqlparser.statement.select.ExpressionListItem;
@@ -503,8 +504,14 @@ public void visit(SelectExpressionItem selectExpressionItem) {
503504

504505
@Override
505506
public void visit(RowConstructor rowConstructor) {
506-
for (Expression expr : rowConstructor.getExprList().getExpressions()) {
507-
expr.accept(this);
507+
if (rowConstructor.getColumnDefinitions().isEmpty()) {
508+
for (Expression expression: rowConstructor.getExprList().getExpressions()) {
509+
expression.accept(this);
510+
}
511+
} else {
512+
for (ColumnDefinition columnDefinition : rowConstructor.getColumnDefinitions()) {
513+
columnDefinition.accept(this);
514+
}
508515
}
509516
}
510517

@@ -605,4 +612,8 @@ public void visit(JsonFunction expression) {
605612
expr.getExpression().accept(this);
606613
}
607614
}
615+
616+
public void visit(ColumnDefinition columnDefinition) {
617+
columnDefinition.accept(this);
618+
}
608619
}

src/main/java/net/sf/jsqlparser/expression/RowConstructor.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,26 @@
99
*/
1010
package net.sf.jsqlparser.expression;
1111

12+
import java.util.ArrayList;
1213
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
1314
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
15+
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
1416

1517
public class RowConstructor extends ASTNodeAccessImpl implements Expression {
16-
1718
private ExpressionList exprList;
19+
private ArrayList<ColumnDefinition> columnDefinitions = new ArrayList<>();
1820
private String name = null;
1921

2022
public RowConstructor() {
2123
}
24+
25+
public ArrayList<ColumnDefinition> getColumnDefinitions() {
26+
return columnDefinitions;
27+
}
28+
29+
public boolean addColumnDefinition(ColumnDefinition columnDefinition) {
30+
return columnDefinitions.add(columnDefinition);
31+
}
2232

2333
public ExpressionList getExprList() {
2434
return exprList;
@@ -43,6 +53,17 @@ public void accept(ExpressionVisitor expressionVisitor) {
4353

4454
@Override
4555
public String toString() {
56+
if (columnDefinitions.size()>0) {
57+
StringBuilder builder = new StringBuilder(name != null ? name : "");
58+
builder.append("(");
59+
int i = 0;
60+
for (ColumnDefinition columnDefinition:columnDefinitions) {
61+
builder.append(i>0 ? ", " : "").append(columnDefinition.toString());
62+
i++;
63+
}
64+
builder.append(")");
65+
return builder.toString();
66+
}
4667
return (name != null ? name : "") + exprList.toString();
4768
}
4869

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,16 @@
1717
import java.util.Optional;
1818
import net.sf.jsqlparser.expression.Expression;
1919
import net.sf.jsqlparser.expression.ExpressionVisitor;
20+
import net.sf.jsqlparser.expression.JdbcNamedParameter;
21+
import net.sf.jsqlparser.expression.JdbcParameter;
2022
import net.sf.jsqlparser.expression.StringValue;
2123
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
2224
import net.sf.jsqlparser.schema.Column;
2325

2426
public class FullTextSearch extends ASTNodeAccessImpl implements Expression {
2527

2628
private List<Column> _matchColumns;
27-
private StringValue _againstValue;
29+
private Expression _againstValue;
2830
private String _searchModifier;
2931

3032
public FullTextSearch() {
@@ -42,8 +44,16 @@ public List<Column> getMatchColumns() {
4244
public void setAgainstValue(StringValue val) {
4345
this._againstValue = val;
4446
}
47+
48+
public void setAgainstValue(JdbcNamedParameter val) {
49+
this._againstValue = val;
50+
}
51+
52+
public void setAgainstValue(JdbcParameter val) {
53+
this._againstValue = val;
54+
}
4555

46-
public StringValue getAgainstValue() {
56+
public Expression getAgainstValue() {
4757
return this._againstValue;
4858
}
4959

src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.Collections;
1515
import java.util.List;
1616
import java.util.Optional;
17+
import net.sf.jsqlparser.expression.ExpressionVisitorAdapter;
1718
import net.sf.jsqlparser.statement.select.PlainSelect;
1819

1920
/**
@@ -99,4 +100,8 @@ public ColumnDefinition addColumnSpecs(Collection<String> columnSpecs) {
99100
collection.addAll(columnSpecs);
100101
return this.withColumnSpecs(collection);
101102
}
103+
104+
public void accept(ExpressionVisitorAdapter expressionVisitor) {
105+
expressionVisitor.visit(this);
106+
}
102107
}

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax;
102102
import net.sf.jsqlparser.schema.Column;
103103
import net.sf.jsqlparser.schema.Table;
104+
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
104105
import net.sf.jsqlparser.statement.select.OrderByElement;
105106
import net.sf.jsqlparser.statement.select.PlainSelect;
106107
import net.sf.jsqlparser.statement.select.SelectVisitor;
@@ -668,7 +669,7 @@ public void visit(CastExpression cast) {
668669
buffer.append("CAST(");
669670
cast.getLeftExpression().accept(this);
670671
buffer.append(" AS ");
671-
buffer.append(cast.getType());
672+
buffer.append( cast.getRowConstructor()!=null ? cast.getRowConstructor() : cast.getType() );
672673
buffer.append(")");
673674
} else {
674675
cast.getLeftExpression().accept(this);
@@ -872,14 +873,25 @@ public void visit(RowConstructor rowConstructor) {
872873
buffer.append(rowConstructor.getName());
873874
}
874875
buffer.append("(");
875-
boolean first = true;
876-
for (Expression expr : rowConstructor.getExprList().getExpressions()) {
877-
if (first) {
878-
first = false;
879-
} else {
880-
buffer.append(", ");
876+
877+
if (rowConstructor.getColumnDefinitions().size()>0) {
878+
buffer.append("(");
879+
int i = 0;
880+
for (ColumnDefinition columnDefinition:rowConstructor.getColumnDefinitions()) {
881+
buffer.append(i>0 ? ", " : "").append(columnDefinition.toString());
882+
i++;
883+
}
884+
buffer.append(")");
885+
} else {
886+
boolean first = true;
887+
for (Expression expr : rowConstructor.getExprList().getExpressions()) {
888+
if (first) {
889+
first = false;
890+
} else {
891+
buffer.append(", ");
892+
}
893+
expr.accept(this);
881894
}
882-
expr.accept(this);
883895
}
884896
buffer.append(")");
885897
}

src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax;
9696
import net.sf.jsqlparser.parser.feature.Feature;
9797
import net.sf.jsqlparser.schema.Column;
98+
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
9899
import net.sf.jsqlparser.statement.select.SubSelect;
99100
import net.sf.jsqlparser.util.validation.ValidationCapability;
100101
import net.sf.jsqlparser.util.validation.metadata.NamedObject;
@@ -499,7 +500,13 @@ public void visit(ValueListExpression valueList) {
499500

500501
@Override
501502
public void visit(RowConstructor rowConstructor) {
502-
validateOptionalExpressionList(rowConstructor.getExprList());
503+
if (rowConstructor.getColumnDefinitions().isEmpty()) {
504+
validateOptionalExpressionList(rowConstructor.getExprList());
505+
} else {
506+
for (ColumnDefinition columnDefinition: rowConstructor.getColumnDefinitions()) {
507+
validateName(NamedObject.column, columnDefinition.getColumnName());
508+
}
509+
}
503510
}
504511

505512
@Override

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3169,7 +3169,8 @@ ExpressionList SimpleExpressionList(boolean outerBrackets) #ExpressionList:
31693169
Expression expr = null;
31703170
}
31713171
{
3172-
expr=SimpleExpression() { expressions.add(expr); } ("," expr=SimpleExpression() { expressions.add(expr); })*
3172+
expr=SimpleExpression() { expressions.add(expr); }
3173+
( LOOKAHEAD(2) "," expr=SimpleExpression() { expressions.add(expr); } )*
31733174
{
31743175
retval.setExpressions(expressions);
31753176
return retval;
@@ -3552,6 +3553,8 @@ Expression PrimaryExpression() #PrimaryExpression:
35523553

35533554
| LOOKAHEAD(2) retval=CastExpression()
35543555

3556+
//| LOOKAHEAD(2) retval=RowConstructor()
3557+
35553558
// support timestamp expressions
35563559
| (token=<K_TIME_KEY_EXPR> | token=<K_CURRENT>) { retval = new TimeKeyExpression(token.image); }
35573560

@@ -4096,15 +4099,23 @@ CastExpression CastExpression():
40964099
{
40974100
CastExpression retval = new CastExpression();
40984101
ColDataType type = null;
4102+
RowConstructor rowConstructor = null;
40994103
Expression expression = null;
41004104
boolean useCastKeyword;
41014105
}
41024106
{
4103-
<K_CAST> "(" expression=SimpleExpression() <K_AS> type=ColDataType() ")" { retval.setUseCastKeyword(true); }
4107+
<K_CAST>
4108+
"("
4109+
expression=SimpleExpression()
4110+
<K_AS> { retval.setUseCastKeyword(true); }
4111+
(
4112+
LOOKAHEAD(3) rowConstructor = RowConstructor() { retval.setRowConstructor(rowConstructor); }
4113+
| type=ColDataType() { retval.setType(type); }
4114+
)
4115+
")"
41044116

41054117
{
41064118
retval.setLeftExpression(expression);
4107-
retval.setType(type);
41084119
return retval;
41094120
}
41104121
}
@@ -4168,16 +4179,20 @@ WhenClause WhenThenSearchCondition():
41684179
}*/
41694180

41704181
RowConstructor RowConstructor(): {
4171-
ExpressionList list = null;
41724182
RowConstructor rowConstructor = new RowConstructor();
4183+
ColumnDefinition columnDefinition = null;
41734184
} {
41744185
[ <K_ROW> { rowConstructor.setName("ROW");} ]
41754186
"("
4176-
list = SimpleExpressionList(true)
4177-
")"
4187+
columnDefinition = ColumnDefinition() { rowConstructor.addColumnDefinition(columnDefinition); }
4188+
(
4189+
","
4190+
columnDefinition = ColumnDefinition() { rowConstructor.addColumnDefinition(columnDefinition); }
4191+
)*
4192+
")"
4193+
41784194

41794195
{
4180-
rowConstructor.setExprList(list);
41814196
return rowConstructor;
41824197
}
41834198
}
@@ -4232,22 +4247,31 @@ FullTextSearch FullTextSearch() : {
42324247
Column col;
42334248
Token searchModifier;
42344249
Token againstValue;
4250+
JdbcParameter jdbcParameter;
4251+
JdbcNamedParameter jdbcNamedParameter;
42354252
FullTextSearch fs = new FullTextSearch();
42364253
List<Column> matchedColumns = new ArrayList<Column>();
42374254
List<Expression> expList = new ArrayList<Expression>();
42384255
}
42394256
{
42404257
<K_MATCH> "(" col=Column() { matchedColumns.add(col); } ("," col=Column() { matchedColumns.add(col); } )* ")" <K_AGAINST>
4241-
"(" againstValue=<S_CHAR_LITERAL> { fs.setAgainstValue(new StringValue(againstValue.image)); }
4242-
[
4243-
(
4244-
searchModifier="IN NATURAL LANGUAGE MODE"
4245-
| searchModifier="IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION"
4246-
| searchModifier="IN BOOLEAN MODE"
4247-
| searchModifier="WITH QUERY EXPANSION"
4248-
)
4249-
{ fs.setSearchModifier(searchModifier.image); }
4250-
]
4258+
"("
4259+
(
4260+
againstValue=<S_CHAR_LITERAL> { fs.setAgainstValue(new StringValue(againstValue.image)); }
4261+
|
4262+
jdbcParameter=SimpleJdbcParameter() { fs.setAgainstValue( jdbcParameter ); }
4263+
|
4264+
jdbcNamedParameter=SimpleJdbcNamedParameter() { fs.setAgainstValue( jdbcNamedParameter ); }
4265+
)
4266+
[
4267+
(
4268+
searchModifier="IN NATURAL LANGUAGE MODE"
4269+
| searchModifier="IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION"
4270+
| searchModifier="IN BOOLEAN MODE"
4271+
| searchModifier="WITH QUERY EXPANSION"
4272+
)
4273+
{ fs.setSearchModifier(searchModifier.image); }
4274+
]
42514275
")"
42524276
{
42534277
fs.setMatchColumns(matchedColumns);
@@ -4541,7 +4565,7 @@ ColumnDefinition ColumnDefinition(): {
45414565

45424566
colDataType = ColDataType()
45434567

4544-
( parameter=CreateParameter() { columnSpecs.addAll(parameter); } )*
4568+
( LOOKAHEAD(2) parameter=CreateParameter() { columnSpecs.addAll(parameter); } )*
45454569

45464570
{
45474571
coldef = new ColumnDefinition();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2021 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
11+
package net.sf.jsqlparser.expression;
12+
13+
import net.sf.jsqlparser.JSQLParserException;
14+
import net.sf.jsqlparser.test.TestUtils;
15+
import org.junit.Test;
16+
17+
/**
18+
*
19+
* @author <a href="mailto:andreas@manticore-projects.com">Andreas Reichel</a>
20+
*/
21+
public class CastExpressionTest {
22+
@Test
23+
public void testCastToRowConstructorIssue1267() throws JSQLParserException {
24+
TestUtils.assertExpressionCanBeParsedAndDeparsed("CAST(ROW(dataid, value, calcMark) AS ROW(datapointid CHAR, value CHAR, calcMark CHAR))", true);
25+
TestUtils.assertExpressionCanBeParsedAndDeparsed("CAST(ROW(dataid, value, calcMark) AS testcol)", true);
26+
}
27+
}

0 commit comments

Comments
 (0)