Skip to content

Commit 411a3da

Browse files
feat: Implicit Casts SELECT DOUBLE PRECISION '1'
- fixes #1364 - fixes #1344 Signed-off-by: Andreas Reichel <andreas@manticore-projects.com>
1 parent b4ef763 commit 411a3da

File tree

13 files changed

+379
-72
lines changed

13 files changed

+379
-72
lines changed

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

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public class CastExpression extends ASTNodeAccessImpl implements Expression {
2323
private ColDataType colDataType = null;
2424
private ArrayList<ColumnDefinition> columnDefinitions = new ArrayList<>();
2525

26+
private boolean isImplicitCast = false;
27+
2628
// BigQuery specific FORMAT clause:
2729
// https://cloud.google.com/bigquery/docs/reference/standard-sql/conversion_functions#cast_as_date
2830
private String format = null;
@@ -34,12 +36,35 @@ public CastExpression(String keyword, Expression leftExpression, String dataType
3436
}
3537

3638
// Implicit Cast
39+
public CastExpression(ColDataType colDataType, String value) {
40+
this.keyword = null;
41+
this.isImplicitCast = true;
42+
this.colDataType = colDataType;
43+
this.leftExpression = new StringValue(value);
44+
}
45+
46+
public CastExpression(ColDataType colDataType, Long value) {
47+
this.keyword = null;
48+
this.isImplicitCast = true;
49+
this.colDataType = colDataType;
50+
this.leftExpression = new LongValue(value);
51+
}
52+
53+
public CastExpression(ColDataType colDataType, Double value) {
54+
this.keyword = null;
55+
this.isImplicitCast = true;
56+
this.colDataType = colDataType;
57+
this.leftExpression = new DoubleValue(value);
58+
}
59+
3760
public CastExpression(Expression leftExpression, String dataType) {
3861
this.keyword = null;
3962
this.leftExpression = leftExpression;
4063
this.colDataType = new ColDataType(dataType);
4164
}
4265

66+
67+
4368
public CastExpression(String keyword) {
4469
this.keyword = keyword;
4570
}
@@ -72,6 +97,15 @@ public void setLeftExpression(Expression expression) {
7297
leftExpression = expression;
7398
}
7499

100+
public boolean isImplicitCast() {
101+
return isImplicitCast;
102+
}
103+
104+
public CastExpression setImplicitCast(boolean implicitCast) {
105+
isImplicitCast = implicitCast;
106+
return this;
107+
}
108+
75109
@Override
76110
public void accept(ExpressionVisitor expressionVisitor) {
77111
expressionVisitor.visit(this);
@@ -107,7 +141,9 @@ public String toString() {
107141
String formatStr = format != null && !format.isEmpty()
108142
? " FORMAT " + format
109143
: "";
110-
if (keyword != null && !keyword.isEmpty()) {
144+
if (isImplicitCast) {
145+
return colDataType + " " + leftExpression;
146+
} else if (keyword != null && !keyword.isEmpty()) {
111147
return columnDefinitions.size() > 1
112148
? keyword + "(" + leftExpression + " AS ROW("
113149
+ Select.getStringList(columnDefinitions) + ")" + formatStr + ")"

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*/
1717
public class DoubleValue extends ASTNodeAccessImpl implements Expression {
1818

19-
private double value;
19+
private Double value;
2020
private String stringValue;
2121

2222
public DoubleValue() {
@@ -35,6 +35,11 @@ public DoubleValue(final String value) {
3535
this.stringValue = val;
3636
}
3737

38+
public DoubleValue(final double value) {
39+
this.value = value;
40+
this.stringValue = String.valueOf(value);
41+
}
42+
3843
@Override
3944
public void accept(ExpressionVisitor expressionVisitor) {
4045
expressionVisitor.visit(this);
@@ -44,7 +49,7 @@ public double getValue() {
4449
return value;
4550
}
4651

47-
public void setValue(double d) {
52+
public void setValue(Double d) {
4853
value = d;
4954
}
5055

@@ -53,7 +58,7 @@ public String toString() {
5358
return stringValue;
5459
}
5560

56-
public DoubleValue withValue(double value) {
61+
public DoubleValue withValue(Double value) {
5762
this.setValue(value);
5863
return this;
5964
}

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

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
package net.sf.jsqlparser.expression;
1111

1212
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
13+
import net.sf.jsqlparser.statement.create.table.ColDataType;
1314

1415
public class TranscodingFunction extends ASTNodeAccessImpl implements Expression {
16+
private boolean isTranscodeStyle = true;
17+
private ColDataType colDataType;
1518
private Expression expression;
1619
private String transcodingName;
1720

@@ -20,6 +23,14 @@ public TranscodingFunction(Expression expression, String transcodingName) {
2023
this.transcodingName = transcodingName;
2124
}
2225

26+
public TranscodingFunction(ColDataType colDataType, Expression expression,
27+
String transcodingName) {
28+
this.colDataType = colDataType;
29+
this.expression = expression;
30+
this.transcodingName = transcodingName;
31+
this.isTranscodeStyle = false;
32+
}
33+
2334
public TranscodingFunction() {
2435
this(null, null);
2536
}
@@ -51,17 +62,47 @@ public TranscodingFunction withTranscodingName(String transcodingName) {
5162

5263
}
5364

65+
public ColDataType getColDataType() {
66+
return colDataType;
67+
}
68+
69+
public TranscodingFunction setColDataType(ColDataType colDataType) {
70+
this.colDataType = colDataType;
71+
return this;
72+
}
73+
74+
public boolean isTranscodeStyle() {
75+
return isTranscodeStyle;
76+
}
77+
78+
public TranscodingFunction setTranscodeStyle(boolean transcodeStyle) {
79+
isTranscodeStyle = transcodeStyle;
80+
return this;
81+
}
82+
5483
public void accept(ExpressionVisitor expressionVisitor) {
5584
expressionVisitor.visit(this);
5685
}
5786

5887
public StringBuilder appendTo(StringBuilder builder) {
59-
return builder
60-
.append("CONVERT( ")
61-
.append(expression)
62-
.append(" USING ")
63-
.append(transcodingName)
64-
.append(" )");
88+
if (isTranscodeStyle) {
89+
return builder
90+
.append("CONVERT( ")
91+
.append(expression)
92+
.append(" USING ")
93+
.append(transcodingName)
94+
.append(" )");
95+
} else {
96+
return builder
97+
.append("CONVERT( ")
98+
.append(colDataType)
99+
.append(", ")
100+
.append(expression)
101+
.append(transcodingName != null && !transcodingName.isEmpty()
102+
? ", " + transcodingName
103+
: "")
104+
.append(" )");
105+
}
65106
}
66107

67108
@Override

src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,9 @@ public static void main(String[] args) throws Exception {
215215

216216
public static TreeSet<String> getAllKeywordsUsingRegex(File file) throws IOException {
217217
Pattern tokenBlockPattern = Pattern.compile(
218-
"TOKEN\\s*:\\s*(?:/\\*.*\\*/*)(?:\\r?\\n|\\r)\\{(?:[^\\}\\{]+|\\{(?:[^\\}\\{]+|\\{[^\\}\\{]*\\})*\\})*\\}",
218+
"TOKEN\\s*:\\s*/\\*.*\\*/*(?:\\r?\\n|\\r)\\{(?:[^}{]+|\\{(?:[^}{]+|\\{[^}{]*})*})*}",
219219
Pattern.MULTILINE);
220-
Pattern tokenStringValuePattern = Pattern.compile("\\\"(\\w{2,})\\\"", Pattern.MULTILINE);
220+
Pattern tokenStringValuePattern = Pattern.compile("\"(\\w{2,})\"", Pattern.MULTILINE);
221221

222222
TreeSet<String> allKeywords = new TreeSet<>();
223223

@@ -257,7 +257,7 @@ public static void buildGrammarForRelObjectNameWithoutValue(File file) throws Ex
257257
+ "{ Token tk = null; }\n"
258258
+ "{\n"
259259
// @todo: find a way to avoid those hardcoded compound tokens
260-
+ " ( tk=<S_IDENTIFIER> | tk=<S_QUOTED_IDENTIFIER> | tk=<K_DATE_LITERAL> | tk=<K_DATETIMELITERAL> | tk=<K_STRING_FUNCTION_NAME> | tk=<K_ISOLATION> | tk=<K_TIME_KEY_EXPR> \n"
260+
+ " ( tk=<DATA_TYPE> | tk=<S_IDENTIFIER> | tk=<S_QUOTED_IDENTIFIER> | tk=<K_DATE_LITERAL> | tk=<K_DATETIMELITERAL> | tk=<K_STRING_FUNCTION_NAME> | tk=<K_ISOLATION> | tk=<K_TIME_KEY_EXPR> \n"
261261
+ " ");
262262

263263
for (String keyword : allKeywords) {

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

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ public ColDataType() {
2929
// empty constructor
3030
}
3131

32+
public ColDataType(String dataType, int precision, int scale) {
33+
this.dataType = dataType;
34+
35+
if (precision >= 0) {
36+
this.dataType += " (" + (precision == Integer.MAX_VALUE ? "MAX" : precision);
37+
if (scale >= 0) {
38+
this.dataType += ", " + scale;
39+
}
40+
this.dataType += ")";
41+
}
42+
}
43+
3244
public ColDataType(String dataType) {
3345
this.dataType = dataType;
3446
}
@@ -48,7 +60,7 @@ public void setArgumentsStringList(List<String> list) {
4860
public void setDataType(String string) {
4961
dataType = string;
5062
}
51-
63+
5264
public void setDataType(List<String> list) {
5365
dataType = list.stream().collect(joining("."));
5466
}
@@ -80,8 +92,9 @@ public String toString() {
8092
arraySpec.append("]");
8193
}
8294
return dataType
83-
+ (argumentsStringList != null ? " " + PlainSelect.
84-
getStringList(argumentsStringList, true, true) : "")
95+
+ (argumentsStringList != null
96+
? " " + PlainSelect.getStringList(argumentsStringList, true, true)
97+
: "")
8598
+ arraySpec.toString()
8699
+ (characterSet != null ? " CHARACTER SET " + characterSet : "");
87100
}
@@ -107,13 +120,15 @@ public ColDataType withArrayData(List<Integer> arrayData) {
107120
}
108121

109122
public ColDataType addArgumentsStringList(String... argumentsStringList) {
110-
List<String> collection = Optional.ofNullable(getArgumentsStringList()).orElseGet(ArrayList::new);
123+
List<String> collection =
124+
Optional.ofNullable(getArgumentsStringList()).orElseGet(ArrayList::new);
111125
Collections.addAll(collection, argumentsStringList);
112126
return this.withArgumentsStringList(collection);
113127
}
114128

115129
public ColDataType addArgumentsStringList(Collection<String> argumentsStringList) {
116-
List<String> collection = Optional.ofNullable(getArgumentsStringList()).orElseGet(ArrayList::new);
130+
List<String> collection =
131+
Optional.ofNullable(getArgumentsStringList()).orElseGet(ArrayList::new);
117132
collection.addAll(argumentsStringList);
118133
return this.withArgumentsStringList(collection);
119134
}

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

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,26 @@ public void visit(Select selectBody) {
515515

516516
@Override
517517
public void visit(TranscodingFunction transcodingFunction) {
518-
buffer.append("CONVERT( ");
519-
transcodingFunction.getExpression().accept(this);
520-
buffer.append(" USING ")
521-
.append(transcodingFunction.getTranscodingName())
522-
.append(" )");
518+
if (transcodingFunction.isTranscodeStyle()) {
519+
buffer.append("CONVERT( ");
520+
transcodingFunction.getExpression().accept(this);
521+
buffer.append(" USING ")
522+
.append(transcodingFunction.getTranscodingName())
523+
.append(" )");
524+
} else {
525+
buffer
526+
.append("CONVERT( ")
527+
.append(transcodingFunction.getColDataType())
528+
.append(", ");
529+
transcodingFunction.getExpression().accept(this);
530+
531+
String transCodingName = transcodingFunction.getTranscodingName();
532+
if (transCodingName != null && !transCodingName.isEmpty()) {
533+
buffer.append(", ").append(transCodingName);
534+
}
535+
buffer.append(" )");
536+
}
537+
523538
}
524539

525540
public void visit(TrimFunction trimFunction) {
@@ -739,7 +754,10 @@ public void visit(BitwiseXor bitwiseXor) {
739754

740755
@Override
741756
public void visit(CastExpression cast) {
742-
if (cast.isUseCastKeyword()) {
757+
if (cast.isImplicitCast()) {
758+
buffer.append(cast.getColDataType()).append(" ");
759+
cast.getLeftExpression().accept(this);
760+
} else if (cast.isUseCastKeyword()) {
743761
String formatStr = cast.getFormat() != null && !cast.getFormat().isEmpty()
744762
? " FORMAT " + cast.getFormat()
745763
: "";

0 commit comments

Comments
 (0)