Skip to content

Commit 749ad55

Browse files
committed
1 parent cbcf0a7 commit 749ad55

File tree

3 files changed

+101
-13
lines changed

3 files changed

+101
-13
lines changed

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

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

12+
import java.util.Objects;
1213
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
1314

1415
public class IntervalExpression extends ASTNodeAccessImpl implements Expression {
1516

1617
private String parameter = null;
1718
private String intervalType = null;
1819
private final boolean intervalKeyword;
20+
private Expression expression = null;
1921

2022
public IntervalExpression() {
2123
this(true);
@@ -41,9 +43,19 @@ public void setIntervalType(String intervalType) {
4143
this.intervalType = intervalType;
4244
}
4345

46+
public Expression getExpression() {
47+
return expression;
48+
}
49+
50+
public void setExpression(Expression expression) {
51+
this.expression = expression;
52+
}
53+
4454
@Override
4555
public String toString() {
46-
return (intervalKeyword ? "INTERVAL " : "") + parameter + (intervalType != null ? " " + intervalType : "");
56+
return (intervalKeyword ? "INTERVAL " : "")
57+
+ Objects.toString(expression, parameter)
58+
+ (intervalType != null ? " " + intervalType : "");
4759
}
4860

4961
@Override

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

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2665,6 +2665,7 @@ Expression PrimaryExpression() #PrimaryExpression:
26652665
ColDataType type = null;
26662666
boolean not = false;
26672667
boolean exclamationMarkNot = false;
2668+
boolean dateExpressionAllowed = true;
26682669
}
26692670
{
26702671
[ <K_NOT> { not=true; } | "!" { not=true; exclamationMarkNot=true; } ]
@@ -2694,7 +2695,7 @@ Expression PrimaryExpression() #PrimaryExpression:
26942695

26952696
| LOOKAHEAD(Function()) retval=Function()
26962697

2697-
| LOOKAHEAD(2) retval = IntervalExpression()
2698+
| LOOKAHEAD(2) retval = IntervalExpression() { dateExpressionAllowed = false; }
26982699

26992700
| token=<S_DOUBLE> { retval = new DoubleValue(token.image); }
27002701

@@ -2730,6 +2731,10 @@ Expression PrimaryExpression() #PrimaryExpression:
27302731
<K_COLLATE> token=<S_IDENTIFIER> { retval = new CollateExpression(retval, token.image); }
27312732
]
27322733

2734+
[
2735+
LOOKAHEAD(2, { dateExpressionAllowed } ) retval = IntervalExpressionWithoutInterval(retval)
2736+
]
2737+
27332738
( "::" type=ColDataType() {
27342739
castExpr = new CastExpression();
27352740
castExpr.setUseCastKeyword(false);
@@ -2830,17 +2835,26 @@ IntervalExpression IntervalExpression() : {
28302835
boolean signed = false;
28312836
}
28322837
{
2833-
(
2834-
{ interval = new IntervalExpression(); }
2835-
<K_INTERVAL> ["-" {signed=true;}] (token=<S_LONG> | token=<S_DOUBLE> | token=<S_CHAR_LITERAL> )
2836-
{ interval.setParameter((signed?"-":"") + token.image); }
2837-
[ LOOKAHEAD(2) (token = <S_IDENTIFIER> | token = <K_DATE_LITERAL>) { interval.setIntervalType(token.image); } ]
2838-
|
2839-
{ interval = new IntervalExpression(false); }
2840-
( token=<S_LONG> | token=<S_DOUBLE> | token=<S_CHAR_LITERAL> | token = <S_IDENTIFIER>)
2841-
{ interval.setParameter((signed?"-":"") + token.image); }
2842-
token = <K_DATE_LITERAL> { interval.setIntervalType(token.image); }
2843-
)
2838+
{ interval = new IntervalExpression(); }
2839+
<K_INTERVAL> ["-" {signed=true;}] (token=<S_LONG> | token=<S_DOUBLE> | token=<S_CHAR_LITERAL> )
2840+
{ interval.setParameter((signed?"-":"") + token.image); }
2841+
[ LOOKAHEAD(2) (token = <S_IDENTIFIER> | token = <K_DATE_LITERAL>) { interval.setIntervalType(token.image); } ]
2842+
{
2843+
return interval;
2844+
}
2845+
}
2846+
2847+
IntervalExpression IntervalExpressionWithoutInterval(Expression expr) : {
2848+
IntervalExpression interval;
2849+
Token token;
2850+
boolean signed = false;
2851+
}
2852+
{
2853+
{
2854+
interval = new IntervalExpression(false);
2855+
interval.setExpression(expr);
2856+
}
2857+
token = <K_DATE_LITERAL> { interval.setIntervalType(token.image); }
28442858
{
28452859
return interval;
28462860
}

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3503,6 +3503,68 @@ public void testIssue699() throws JSQLParserException {
35033503
assertSqlCanBeParsedAndDeparsed(sql);
35043504
}
35053505

3506+
@Test
3507+
public void testDateArithmentic9() throws JSQLParserException {
3508+
assertSqlCanBeParsedAndDeparsed("SELECT CURRENT_DATE + (RAND() * 12 MONTH) AS new_date FROM mytable");
3509+
}
3510+
3511+
@Test
3512+
public void testDateArithmentic10() throws JSQLParserException {
3513+
String sql = "select CURRENT_DATE + CASE WHEN CAST(RAND() * 3 AS INTEGER) = 1 THEN 100 ELSE 0 END DAY AS NEW_DATE from mytable";
3514+
assertSqlCanBeParsedAndDeparsed(sql, true);
3515+
Select select = (Select) CCJSqlParserUtil.parse(sql);
3516+
3517+
}
3518+
3519+
@Test
3520+
public void testDateArithmentic11() throws JSQLParserException {
3521+
String sql = "select CURRENT_DATE + (dayofweek(MY_DUE_DATE) + 5) DAY FROM mytable";
3522+
assertSqlCanBeParsedAndDeparsed(sql, true);
3523+
Select select = (Select) CCJSqlParserUtil.parse(sql);
3524+
final List<SelectItem> list = new ArrayList<>();
3525+
select.getSelectBody().accept(new SelectVisitorAdapter() {
3526+
@Override
3527+
public void visit(PlainSelect plainSelect) {
3528+
list.addAll(plainSelect.getSelectItems());
3529+
}
3530+
});
3531+
3532+
assertEquals(1, list.size());
3533+
assertTrue(list.get(0) instanceof SelectExpressionItem);
3534+
SelectExpressionItem item = (SelectExpressionItem) list.get(0);
3535+
assertTrue(item.getExpression() instanceof Addition);
3536+
Addition add = (Addition) item.getExpression();
3537+
3538+
assertTrue(add.getRightExpression() instanceof IntervalExpression);
3539+
}
3540+
3541+
@Test
3542+
public void testDateArithmentic12() throws JSQLParserException {
3543+
assertSqlCanBeParsedAndDeparsed("select CASE WHEN CAST(RAND() * 3 AS INTEGER) = 1 THEN NULL ELSE CURRENT_DATE + (month_offset MONTH) END FROM mytable", true);
3544+
}
3545+
3546+
@Test
3547+
public void testDateArithmentic13() throws JSQLParserException {
3548+
String sql = "SELECT INTERVAL 5 MONTH MONTH FROM mytable";
3549+
assertSqlCanBeParsedAndDeparsed(sql);
3550+
Select select = (Select) CCJSqlParserUtil.parse(sql);
3551+
final List<SelectItem> list = new ArrayList<>();
3552+
select.getSelectBody().accept(new SelectVisitorAdapter() {
3553+
@Override
3554+
public void visit(PlainSelect plainSelect) {
3555+
list.addAll(plainSelect.getSelectItems());
3556+
}
3557+
});
3558+
3559+
assertEquals(1, list.size());
3560+
assertTrue(list.get(0) instanceof SelectExpressionItem);
3561+
SelectExpressionItem item = (SelectExpressionItem) list.get(0);
3562+
assertTrue(item.getExpression() instanceof IntervalExpression);
3563+
IntervalExpression interval = (IntervalExpression) item.getExpression();
3564+
assertEquals("INTERVAL 5 MONTH", interval.toString());
3565+
assertEquals("MONTH", item.getAlias().getName());
3566+
}
3567+
35063568
@Test
35073569
public void testRawStringExpressionIssue656() throws JSQLParserException {
35083570
for (String c : new String[]{"u", "e", "n", "r", "b", "rb"}) {

0 commit comments

Comments
 (0)