Skip to content

Commit 4fdfa78

Browse files
feat: DateUnitExpression for parsing HOUR, DAY, MONTH etc. in Date Functions not as column
Signed-off-by: Andreas Reichel <[email protected]>
1 parent d8019ca commit 4fdfa78

File tree

10 files changed

+135
-13
lines changed

10 files changed

+135
-13
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ jobs:
3939
runs-on: ${{ matrix.os }}
4040
strategy:
4141
matrix:
42-
os: [ ubuntu-latest, windows-latest, macos-latest ]
42+
# currently Windows does not work w/ code page related issues
43+
# os: [ ubuntu-latest, windows-latest, macos-latest ]
44+
os: [ ubuntu-latest, macos-latest ]
4345
steps:
4446
- uses: actions/checkout@main
4547
with:
@@ -57,7 +59,7 @@ jobs:
5759
gradle_publish:
5860
name: Gradle Publish
5961
needs: [ gradle_check, maven_verify ] # ✅ Run only after both succeed
60-
if: github.ref == 'refs/heads/master' && github.repository == 'YOUR-ORG/YOUR-REPO' # ✅ Only for master branch of main repo
62+
if: github.ref == 'refs/heads/master' && github.repository == 'JSQLParser/JSqlParser' # ✅ Only for master branch of main repo
6163
runs-on: ubuntu-latest
6264
steps:
6365
- uses: actions/checkout@main
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2019 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.expression;
11+
12+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
13+
14+
import java.util.Objects;
15+
16+
public class DateUnitExpression extends ASTNodeAccessImpl implements Expression {
17+
18+
private final DateUnit type;
19+
20+
public DateUnitExpression(DateUnit type) {
21+
this.type = Objects.requireNonNull(type);
22+
}
23+
24+
public DateUnitExpression(String DateUnitStr) {
25+
this.type = Objects.requireNonNull(DateUnit.from(DateUnitStr));
26+
}
27+
28+
public DateUnit getType() {
29+
return type;
30+
}
31+
32+
33+
@Override
34+
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
35+
return expressionVisitor.visit(this, context);
36+
}
37+
38+
@Override
39+
public String toString() {
40+
return type.toString();
41+
}
42+
43+
public enum DateUnit {
44+
CENTURY, DECADE, YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND;
45+
46+
public static DateUnit from(String UnitStr) {
47+
return Enum.valueOf(DateUnit.class, UnitStr.toUpperCase());
48+
}
49+
}
50+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,4 +779,6 @@ default void visit(Inverse inverse) {
779779
<S> T visit(CosineSimilarity cosineSimilarity, S context);
780780

781781
<S> T visit(FromQuery fromQuery, S context);
782+
783+
<S> T visit(DateUnitExpression dateUnitExpression, S context);
782784
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,4 +840,9 @@ public <S> T visit(FromQuery fromQuery, S context) {
840840
return null;
841841
}
842842

843+
@Override
844+
public <S> T visit(DateUnitExpression dateUnitExpression, S context) {
845+
return null;
846+
}
847+
843848
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,11 @@ public <S> Void visit(FromQuery fromQuery, S context) {
829829
return null;
830830
}
831831

832+
@Override
833+
public <S> Void visit(DateUnitExpression dateUnitExpression, S context) {
834+
return null;
835+
}
836+
832837
/**
833838
* Initializes table names collector. Important is the usage of Column instances to find table
834839
* names. This is only allowed for expression parsing, where a better place for tablenames could

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import net.sf.jsqlparser.expression.ConnectByRootOperator;
2424
import net.sf.jsqlparser.expression.ConnectByPriorOperator;
2525
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
26+
import net.sf.jsqlparser.expression.DateUnitExpression;
2627
import net.sf.jsqlparser.expression.DateValue;
2728
import net.sf.jsqlparser.expression.DoubleValue;
2829
import net.sf.jsqlparser.expression.Expression;
@@ -1829,4 +1830,9 @@ public <S> StringBuilder visit(CosineSimilarity cosineSimilarity, S context) {
18291830
public <S> StringBuilder visit(FromQuery fromQuery, S context) {
18301831
return null;
18311832
}
1833+
1834+
@Override
1835+
public <S> StringBuilder visit(DateUnitExpression dateUnitExpression, S context) {
1836+
return builder.append(dateUnitExpression.toString());
1837+
}
18321838
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import net.sf.jsqlparser.expression.ConnectByRootOperator;
2323
import net.sf.jsqlparser.expression.ConnectByPriorOperator;
2424
import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
25+
import net.sf.jsqlparser.expression.DateUnitExpression;
2526
import net.sf.jsqlparser.expression.DateValue;
2627
import net.sf.jsqlparser.expression.DoubleValue;
2728
import net.sf.jsqlparser.expression.Expression;
@@ -1314,4 +1315,9 @@ public <S> Void visit(FromQuery fromQuery, S context) {
13141315
return null;
13151316
}
13161317

1318+
@Override
1319+
public <S> Void visit(DateUnitExpression dateUnitExpression, S context) {
1320+
return null;
1321+
}
1322+
13171323
}

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

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6559,9 +6559,11 @@ Expression PrimaryExpression() #PrimaryExpression:
65596559

65606560
| LOOKAHEAD(3, { !interrupted}) retval = FullTextSearch()
65616561

6562-
| LOOKAHEAD(2, {!interrupted}) retval=CastExpression()
6562+
| LOOKAHEAD(2, {!interrupted}) retval= CastExpression()
65636563

6564-
| LOOKAHEAD(16) retval=Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ]
6564+
| LOOKAHEAD(16) retval = Function() [ LOOKAHEAD(2) retval = AnalyticExpression( (Function) retval ) ]
6565+
6566+
| LOOKAHEAD(2) retval = DateUnitExpression()
65656567

65666568
| LOOKAHEAD(2, {!interrupted}) retval = IntervalExpression() { dateExpressionAllowed = false; }
65676569

@@ -6804,10 +6806,25 @@ NumericBind NumericBind() : {
68046806
DateTimeLiteralExpression DateTimeLiteralExpression() : {
68056807
DateTimeLiteralExpression expr = new DateTimeLiteralExpression();
68066808
Token t;
6807-
} {
6808-
t=<K_DATETIMELITERAL> { expr.setType(DateTimeLiteralExpression.DateTime.from(t.image)); }
6809+
}
6810+
{
6811+
t=<K_DATETIMELITERAL>
6812+
{
6813+
expr.setType(DateTimeLiteralExpression.DateTime.from(t.image));
6814+
}
68096815

6810-
( t=<S_CHAR_LITERAL> | t=<S_QUOTED_IDENTIFIER> ) { expr.setValue(t.image); return expr; }
6816+
( t=<S_CHAR_LITERAL> | t=<S_QUOTED_IDENTIFIER> )
6817+
{
6818+
expr.setValue(t.image);
6819+
return expr;
6820+
}
6821+
}
6822+
6823+
DateUnitExpression DateUnitExpression() : {
6824+
Token t;
6825+
}
6826+
{
6827+
t=<K_DATE_LITERAL> { return new DateUnitExpression( t.image ); }
68116828
}
68126829

68136830
RangeExpression RangeExpression(Expression startExpression):
@@ -6892,7 +6909,7 @@ StructType StructType() #StruckType:
68926909
LOOKAHEAD(4) (
68936910
tk1=<K_STRUCT> { keyword = tk1.image; }
68946911
"<" parameters = StructParameters() ">"
6895-
"(" { System.out.println("found arguments!"); } arguments = SelectItemsList() ")"
6912+
"(" arguments = SelectItemsList() ")"
68966913
)
68976914
|
68986915
(
@@ -6916,10 +6933,6 @@ StructType StructType() #StruckType:
69166933
LOOKAHEAD(2) "::" <K_STRUCT> "(" parameters = StructParameters() ")"
69176934
)*
69186935
)
6919-
6920-
// don't parse this as an Struct, but rather use an Expressionlist
6921-
// |
6922-
// arguments = StructArguments()
69236936
)
69246937
{
69256938
type = new StructType(dialect, keyword, parameters, arguments);
@@ -7703,7 +7716,7 @@ Function SpecialStringFunctionWithNamedParameters() :
77037716

77047717
"("
77057718
(
7706-
LOOKAHEAD(6, { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst()
7719+
LOOKAHEAD( NamedExpressionListExprFirst() , { getAsBoolean(Feature.allowComplexParsing) }) namedExpressionList = NamedExpressionListExprFirst()
77077720
|
77087721
expressionList=ExpressionList()
77097722
)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package net.sf.jsqlparser.expression;
2+
3+
import net.sf.jsqlparser.JSQLParserException;
4+
import net.sf.jsqlparser.statement.select.PlainSelect;
5+
import net.sf.jsqlparser.test.TestUtils;
6+
import org.assertj.core.api.Assertions;
7+
import org.junit.jupiter.api.Test;
8+
9+
10+
class DateUnitExpressionTest {
11+
12+
@Test
13+
void testParsing() throws JSQLParserException {
14+
String sqlStr = "SELECT Last_Day( DATE '2024-12-31', month ) as month";
15+
16+
PlainSelect select = (PlainSelect) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
17+
18+
Function f = select.getSelectItem(0).getExpression(Function.class);
19+
Assertions.assertThat(f.getParameters().get(1)).isInstanceOf(DateUnitExpression.class);
20+
}
21+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6422,4 +6422,16 @@ void testSQL2016CorrespondingBy() throws JSQLParserException {
64226422

64236423
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
64246424
}
6425+
6426+
@Test
6427+
void testIssue2332SubStrCTE() throws JSQLParserException {
6428+
String sqlStr =
6429+
"create table t as\n" +
6430+
" with\n" +
6431+
" _ as (select f(id = '') from v)\n" +
6432+
" select\n" +
6433+
" substring (f (u.id))\n" +
6434+
" from u ;";
6435+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
6436+
}
64256437
}

0 commit comments

Comments
 (0)