Skip to content

Commit c8a5d7c

Browse files
Implement Oracle Named Function Parameters Func( param1 => arg1, ...) (#1283)
Fixes #1270
1 parent 6933d86 commit c8a5d7c

8 files changed

Lines changed: 206 additions & 1 deletion

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,4 +172,6 @@ public interface ExpressionVisitor {
172172
void visit(JsonAggregateFunction aThis);
173173

174174
void visit(JsonFunction aThis);
175+
176+
void visit(OracleNamedFunctionParameter aThis);
175177
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,10 @@ public void visit(JsonFunction expression) {
613613
}
614614
}
615615

616+
@Override
617+
public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) {
618+
oracleNamedFunctionParameter.getExpression().accept(this);
619+
}
616620
public void visit(ColumnDefinition columnDefinition) {
617621
columnDefinition.accept(this);
618622
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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+
package net.sf.jsqlparser.expression;
11+
12+
import java.util.Objects;
13+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
14+
15+
/**
16+
*
17+
* @author <a href="mailto:andreas@manticore-projects.com">Andreas Reichel</a>
18+
*/
19+
public class OracleNamedFunctionParameter extends ASTNodeAccessImpl implements Expression {
20+
private final String name;
21+
private final Expression expression;
22+
23+
public OracleNamedFunctionParameter(String name, Expression expression) {
24+
this.name = Objects.requireNonNull(name, "The NAME of the OracleNamedFunctionParameter must not be null.");
25+
this.expression = Objects.requireNonNull(expression, "The EXPRESSION of the OracleNamedFunctionParameter must not be null.");
26+
}
27+
28+
public String getName() {
29+
return name;
30+
}
31+
32+
public Expression getExpression() {
33+
return expression;
34+
}
35+
36+
@Override
37+
public void accept(ExpressionVisitor expressionVisitor) {
38+
expressionVisitor.visit(this);
39+
}
40+
41+
public StringBuilder appendTo(StringBuilder builder) {
42+
builder.append(name)
43+
.append(" => ")
44+
.append(expression);
45+
46+
return builder;
47+
}
48+
49+
@Override
50+
public String toString() {
51+
return appendTo(new StringBuilder()).toString();
52+
}
53+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import net.sf.jsqlparser.expression.NumericBind;
4646
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
4747
import net.sf.jsqlparser.expression.OracleHint;
48+
import net.sf.jsqlparser.expression.OracleNamedFunctionParameter;
4849
import net.sf.jsqlparser.expression.Parenthesis;
4950
import net.sf.jsqlparser.expression.RowConstructor;
5051
import net.sf.jsqlparser.expression.RowGetExpression;
@@ -1027,6 +1028,11 @@ public void visit(JsonFunction expression) {
10271028
}
10281029
}
10291030

1031+
@Override
1032+
public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) {
1033+
oracleNamedFunctionParameter.getExpression().accept(this);
1034+
}
1035+
10301036
@Override
10311037
public void visit(RenameTableStatement renameTableStatement) {
10321038
for (Map.Entry<Table, Table> e : renameTableStatement.getTableNames()) {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import net.sf.jsqlparser.expression.NumericBind;
4646
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
4747
import net.sf.jsqlparser.expression.OracleHint;
48+
import net.sf.jsqlparser.expression.OracleNamedFunctionParameter;
4849
import net.sf.jsqlparser.expression.Parenthesis;
4950
import net.sf.jsqlparser.expression.RowConstructor;
5051
import net.sf.jsqlparser.expression.RowGetExpression;
@@ -1017,4 +1018,13 @@ public void visit(JsonAggregateFunction expression) {
10171018
public void visit(JsonFunction expression) {
10181019
expression.append(buffer);
10191020
}
1021+
1022+
@Override
1023+
public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) {
1024+
buffer
1025+
.append(oracleNamedFunctionParameter.getName())
1026+
.append(" => ");
1027+
1028+
oracleNamedFunctionParameter.getExpression().accept(this);
1029+
}
10201030
}

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
@@ -40,6 +40,7 @@
4040
import net.sf.jsqlparser.expression.NumericBind;
4141
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
4242
import net.sf.jsqlparser.expression.OracleHint;
43+
import net.sf.jsqlparser.expression.OracleNamedFunctionParameter;
4344
import net.sf.jsqlparser.expression.Parenthesis;
4445
import net.sf.jsqlparser.expression.RowConstructor;
4546
import net.sf.jsqlparser.expression.RowGetExpression;
@@ -598,4 +599,9 @@ public void visit(JsonFunction expression) {
598599
// no idea what this is good for
599600
}
600601

602+
@Override
603+
public void visit(OracleNamedFunctionParameter oracleNamedFunctionParameter) {
604+
oracleNamedFunctionParameter.getExpression().accept(this);
605+
}
606+
601607
}

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */
298298
| <K_ONLY:"ONLY">
299299
| <K_OPEN:"OPEN">
300300
| <K_OR:"OR">
301+
| <K_ORACLE_NAMED_PARAMETER_ASSIGNMENT: "=>">
301302
| <K_ORDER:"ORDER">
302303
| <K_OUTER:"OUTER">
303304
| <K_OVER:"OVER">
@@ -3184,7 +3185,17 @@ ExpressionList ComplexExpressionList() #ExpressionList:
31843185
Expression expr = null;
31853186
}
31863187
{
3187-
expr=Expression() { expressions.add(expr); } ("," expr=Expression() { expressions.add(expr); })*
3188+
(
3189+
LOOKAHEAD(2) expr=OracleNamedFunctionParameter()
3190+
| expr=Expression()
3191+
) { expressions.add(expr); }
3192+
(
3193+
","
3194+
(
3195+
LOOKAHEAD(2) expr=OracleNamedFunctionParameter()
3196+
| expr=Expression()
3197+
) { expressions.add(expr); }
3198+
)*
31883199
{
31893200
retval.setExpressions(expressions);
31903201
return retval;
@@ -3666,6 +3677,19 @@ JdbcNamedParameter JdbcNamedParameter() : {
36663677
}
36673678
}
36683679

3680+
OracleNamedFunctionParameter OracleNamedFunctionParameter() : {
3681+
String name;
3682+
Expression expression;
3683+
}
3684+
{
3685+
name=RelObjectNameExt2()
3686+
<K_ORACLE_NAMED_PARAMETER_ASSIGNMENT>
3687+
expression=Expression()
3688+
{
3689+
return new OracleNamedFunctionParameter(name, expression);
3690+
}
3691+
}
3692+
36693693
UserVariable UserVariable() : {
36703694
UserVariable var = new UserVariable();
36713695
String varName;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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 java.util.List;
14+
import net.sf.jsqlparser.JSQLParserException;
15+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
16+
import net.sf.jsqlparser.statement.Statement;
17+
import net.sf.jsqlparser.statement.StatementVisitorAdapter;
18+
import net.sf.jsqlparser.test.TestUtils;
19+
import net.sf.jsqlparser.util.TablesNamesFinder;
20+
import net.sf.jsqlparser.util.validation.ValidationTestAsserts;
21+
import net.sf.jsqlparser.util.validation.feature.DatabaseType;
22+
import org.junit.Assert;
23+
import org.junit.Test;
24+
25+
/**
26+
*
27+
* @author <a href="mailto:andreas@manticore-projects.com">Andreas Reichel</a>
28+
*/
29+
public class OracleNamedFunctionParameterTest {
30+
31+
/**
32+
* This test will parse and deparse the statement and assures the functional coverage by
33+
* JSQLParser.
34+
* @throws net.sf.jsqlparser.JSQLParserException
35+
*/
36+
@Test
37+
public void testExpression() throws JSQLParserException {
38+
String sqlStr =
39+
"select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2";
40+
41+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
42+
43+
sqlStr =
44+
"exec dbms_stats.gather_schema_stats(\n" +
45+
" ownname => 'COMMON', \n" +
46+
" estimate_percent => dbms_stats.auto_sample_size, \n" +
47+
" method_opt => 'for all columns size auto', \n" +
48+
" degree => DBMS_STATS.DEFAULT_DEGREE,\n" +
49+
" cascade => DBMS_STATS.AUTO_CASCADE,\n" +
50+
" options => 'GATHER AUTO'\n" +
51+
" )";
52+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
53+
}
54+
55+
/**
56+
* This test will trigger the method {@link ExpressionVisitorAdaptor#visit() Visit Method} in the
57+
* ExpressionVisitorAdaptor needed for the Code Coverage.
58+
* @throws net.sf.jsqlparser.JSQLParserException
59+
*/
60+
@Test
61+
public void testExpressionVisitorAdaptor() throws JSQLParserException {
62+
String sqlStr =
63+
"select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2";
64+
65+
CCJSqlParserUtil.parse(sqlStr).accept(new StatementVisitorAdapter());
66+
67+
// alternatively, for the Expression only
68+
CCJSqlParserUtil.parseExpression("p_1 => r.param1").accept(new ExpressionVisitorAdapter());
69+
}
70+
71+
72+
/**
73+
* This test will trigger the method {@link TableNamesFinder#visit() Visit Method} in the
74+
* TableNamesFinder needed for the Code Coverage.
75+
* @throws net.sf.jsqlparser.JSQLParserException
76+
*/
77+
@Test
78+
public void testTableNamesFinder() throws JSQLParserException {
79+
String sqlStr =
80+
"select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2 from test_table";
81+
82+
Statement statement = CCJSqlParserUtil.parse(sqlStr);
83+
List<String> tables = new TablesNamesFinder().getTableList(statement);
84+
Assert.assertEquals(1, tables.size());
85+
Assert.assertTrue(tables.contains("test_table"));
86+
}
87+
88+
/**
89+
* This test will trigger the method {@link ExpressionValidator#visit() Visit Method} in the
90+
* ExpressionValidator needed for the Code Coverage.
91+
* @throws net.sf.jsqlparser.JSQLParserException
92+
*/
93+
@Test
94+
public void testValidator() throws JSQLParserException {
95+
String sqlStr =
96+
"select r.*, test.numeric_function ( p_1 => r.param1, p_2 => r.param2 ) as resultaat2";
97+
98+
ValidationTestAsserts.validateNoErrors(sqlStr, 1, DatabaseType.ORACLE);
99+
}
100+
}

0 commit comments

Comments
 (0)