[plsql] Add SimpleExpressionNode, allow expressions with REGEXP_LIKE
This commit is contained in:
1 parent
984928ad52
commit
808c03f532
8 files changed
+104
-29
No files matched your search
@@ -1305,6 +1305,8 @@ void Condition2() #void :
|
||||
(
|
||||
// a IS OF Type condition that starts with a function...
|
||||
LOOKAHEAD(FunctionCall() <IS> [<NOT>] <OF>) IsOfTypeCondition()
|
||||
|
|
||||
LOOKAHEAD(<REGEXP_LIKE>) RegexpLikeCondition()
|
||||
|
|
||||
LOOKAHEAD(9) MultisetCondition()
|
||||
|
|
||||
@@ -1315,8 +1317,6 @@ void Condition2() #void :
|
||||
LOOKAHEAD(9) InCondition()
|
||||
|
|
||||
LOOKAHEAD(9) LikeCondition()
|
||||
|
|
||||
LOOKAHEAD(9) RegexpLikeCondition()
|
||||
|
|
||||
LOOKAHEAD(4) BetweenCondition()
|
||||
|
|
||||
@@ -1355,8 +1355,8 @@ ASTRegexpLikeCondition RegexpLikeCondition() :
|
||||
}
|
||||
{
|
||||
<REGEXP_LIKE> "("
|
||||
ID() ","
|
||||
StringLiteral()
|
||||
SqlExpression() ","
|
||||
SqlExpression()
|
||||
[ "," ( matchParam = <CHARACTER_LITERAL> | matchParam = <STRING_LITERAL> ) {jjtThis.setMatchParam(matchParam.toString());} ]
|
||||
")"
|
||||
{ return jjtThis; }
|
||||
@@ -1473,26 +1473,51 @@ ASTExpressionList ExpressionList() :
|
||||
* @see https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/About-SQL-Expressions.html
|
||||
*/
|
||||
ASTSqlExpression SqlExpression() :
|
||||
{}
|
||||
{ PLSQLNode simpleNode = null; }
|
||||
{
|
||||
[ LOOKAHEAD(2) <PRIOR> ]
|
||||
// SimpleExpression
|
||||
(
|
||||
LOOKAHEAD(3) AdditiveExpression() // this can be a literal or a simple expression, but no conditional
|
||||
|
|
||||
LOOKAHEAD(5) SchemaName() "." TableName() "." Column()
|
||||
|
|
||||
LOOKAHEAD(3) TableName() "." Column()
|
||||
|
|
||||
LOOKAHEAD(2) Column()
|
||||
|
|
||||
LOOKAHEAD(2) <ROWNUM>
|
||||
|
|
||||
LOOKAHEAD(2) "(" SelectStatement() ")" // see "Scalar Subquery Expressions"
|
||||
// AdditiveExpression includes literals and simple expressions, but no conditional
|
||||
( simpleNode = AdditiveExpression() ) { jjtThis.setImage(simpleNode.getImage()); }
|
||||
)
|
||||
{ return jjtThis; }
|
||||
}
|
||||
|
||||
/**
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Simple-Expressions.html
|
||||
*/
|
||||
ASTSimpleExpression SimpleExpression() :
|
||||
{ StringBuilder sb = new StringBuilder(); }
|
||||
{
|
||||
(
|
||||
LOOKAHEAD(2) <ROWNUM> { sb.append(token.image); }
|
||||
|
|
||||
StringLiteral() { sb.append(token.image); }
|
||||
|
|
||||
NumericLiteral() { sb.append(token.image); }
|
||||
|
|
||||
LOOKAHEAD(2) NullLiteral() { sb.append(token.image); }
|
||||
|
|
||||
// sequence
|
||||
LOOKAHEAD(4) ID() "." ( <CURRVAL> | <NEXTVAL> )
|
||||
|
|
||||
LOOKAHEAD(6)
|
||||
SchemaName() { sb.append(token.image); } "." { sb.append(token.image); }
|
||||
TableName() { sb.append(token.image); } "." { sb.append(token.image); }
|
||||
Column() { sb.append(token.image); }
|
||||
|
|
||||
LOOKAHEAD(4)
|
||||
TableName() { sb.append(token.image); } "." { sb.append(token.image); }
|
||||
Column() { sb.append(token.image); }
|
||||
|
|
||||
LOOKAHEAD(2)
|
||||
Column() { sb.append(token.image); }
|
||||
)
|
||||
{
|
||||
jjtThis.setImage(sb.toString());
|
||||
return jjtThis;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in function call or a user defined function call.
|
||||
* See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Functions.html#GUID-D079EFD3-C683-441F-977E-2C9503089982
|
||||
@@ -2938,6 +2963,7 @@ ASTUnaryExpression UnaryExpression(boolean isUnarySign) #UnaryExpression(>1) :
|
||||
(
|
||||
( ("+" ) { sb.append(isUnarySign ? " +" : " + "); }
|
||||
| ("-" ) { sb.append(isUnarySign ? " -" : " - "); }
|
||||
| (<PRIOR>) { sb.append(" PRIOR "); }
|
||||
)
|
||||
(simpleNode = UnaryExpression(false) ) { sb.append(simpleNode.getImage()); }
|
||||
|
|
||||
@@ -3039,12 +3065,13 @@ ASTPrimaryPrefix PrimaryPrefix() :
|
||||
(
|
||||
// Note: AnalyticClause and WithinClause are only allowed for specific functions, but this grammar allows it for all functions.
|
||||
LOOKAHEAD(FunctionName() "(") simpleNode = FunctionCall() [ AnalyticClause() ] [ WithinClause() ]
|
||||
| LOOKAHEAD(Literal()) simpleNode = Literal() { sb.append(simpleNode.getImage()) ; }
|
||||
| LOOKAHEAD(MultiSetCondition()) simpleNode = MultiSetCondition()
|
||||
| LOOKAHEAD(TrimExpression()) simpleNode = TrimExpression() //SRT 20110613.3
|
||||
| LOOKAHEAD(CaseExpression()) ( simpleNode =CaseExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110520
|
||||
| LOOKAHEAD(ObjectExpression() ) ( simpleNode = ObjectExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110604
|
||||
//| LOOKAHEAD(LikeExpression()) ( simpleNode = LikeExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110604
|
||||
| LOOKAHEAD(SimpleExpression()) ( simpleNode = SimpleExpression() ) { sb.append(simpleNode.getImage()); }
|
||||
| LOOKAHEAD(Literal()) ( simpleNode = Literal() ) { sb.append(simpleNode.getImage()) ; }
|
||||
| ( simpleNode =Name() ) { sb.append(simpleNode.getImage()) ; }
|
||||
| SelectStatement()
|
||||
| LOOKAHEAD("(" <SELECT>) "(" SelectStatement() ")"
|
||||
@@ -3069,20 +3096,20 @@ ASTPrimarySuffix PrimarySuffix() :
|
||||
{ PLSQLNode suffixNode = null ; PLSQLNode arguments = null; StringBuilder sb = new StringBuilder() ; }
|
||||
{
|
||||
(
|
||||
(".") {sb.append(".");} (suffixNode = QualifiedID() ) { sb.append(suffixNode.toString()) ; }
|
||||
(".") {sb.append(".");} (suffixNode = QualifiedID() ) { sb.append(suffixNode.getImage()) ; }
|
||||
//Bug 3535118 - Method call may include dblink
|
||||
//String dblink = null;
|
||||
//["@" dblink = qualifiedName() {sb.append("@"); sb.append(dblink); } ]
|
||||
| //Possible dblink
|
||||
("@") {sb.append("@");} (suffixNode = QualifiedID() ) { sb.append(suffixNode.toString()) ; }
|
||||
("@") {sb.append("@");} (suffixNode = QualifiedID() ) { sb.append(suffixNode.getImage()) ; }
|
||||
| //Possible Date Time Expression - Bug 3553725
|
||||
( <AT> {sb.append(" "); sb.append(token.image.toUpperCase());}
|
||||
( <LOCAL> {sb.append(" "); sb.append(token.image.toUpperCase());}
|
||||
| ( <TIME> <ZONE> {sb.append(" TIME ZONE");}
|
||||
( <DBTIMEZONE> {sb.append(" "); sb.append(token.image.toUpperCase());}
|
||||
| <SESSIONTIMEZONE> {sb.append(" "); sb.append(token.image.toUpperCase());}
|
||||
| suffixNode = StringLiteral() {sb.append(" "); sb.append(suffixNode.toString());}
|
||||
| suffixNode = Expression() {sb.append(" "); sb.append(suffixNode.toString());}
|
||||
| suffixNode = StringLiteral() {sb.append(" "); sb.append(suffixNode.getImage());}
|
||||
| suffixNode = Expression() {sb.append(" "); sb.append(suffixNode.getImage());}
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -6031,7 +6058,6 @@ ASTID ID(): {}
|
||||
| <DATE> //RESERVED WORD
|
||||
| <DECLARE> //SYNTAX
|
||||
| <DECIMAL> //RESERVED WORD
|
||||
//| <_DEFAULT> //RESERVED WORD
|
||||
| <DELETE> //RESERVED WORD
|
||||
| <DESC> //RESERVED WORD
|
||||
//| <DISTINCT> //RESERVED WORD
|
||||
|
||||
+4
-4
@@ -29,12 +29,12 @@ public class ASTRegexpLikeCondition extends net.sourceforge.pmd.lang.plsql.ast.A
|
||||
return this.matchParam;
|
||||
}
|
||||
|
||||
public ASTID getSourceChar() {
|
||||
return (ASTID) jjtGetChild(0);
|
||||
public ASTSqlExpression getSourceChar() {
|
||||
return (ASTSqlExpression) jjtGetChild(0);
|
||||
}
|
||||
|
||||
public ASTStringLiteral getPattern() {
|
||||
return (ASTStringLiteral) jjtGetChild(1);
|
||||
public ASTSqlExpression getPattern() {
|
||||
return (ASTSqlExpression) jjtGetChild(1);
|
||||
}
|
||||
}
|
||||
/* JavaCC - OriginalChecksum=afb8806a0c67f95b736d6e8bc46def15 (do not edit this line) */
|
||||
+5
@@ -1061,4 +1061,9 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor {
|
||||
public Object visit(ASTErrorLoggingClause node, Object data) {
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSimpleExpression node, Object data) {
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
}
|
||||
@@ -1155,6 +1155,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSimpleExpression node, Object data) {
|
||||
return visit((PLSQLNode) node, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Treat all Executable Code
|
||||
*/
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package net.sourceforge.pmd.lang.plsql.ast;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Assert;
|
||||
@@ -22,6 +23,22 @@ public class SelectExpressionsTest extends AbstractPLSQLParserTst {
|
||||
Assert.assertNotNull(input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseSelectSimpleExpression() throws Exception {
|
||||
String code = IOUtils.toString(this.getClass().getResourceAsStream("SelectSimpleExpression.pls"),
|
||||
StandardCharsets.UTF_8);
|
||||
ASTInput input = parsePLSQL(code);
|
||||
Assert.assertNotNull(input);
|
||||
|
||||
List<ASTSimpleExpression> simpleExpressions = input.findDescendantsOfType(ASTSimpleExpression.class);
|
||||
Assert.assertEquals(1, simpleExpressions.size());
|
||||
ASTSimpleExpression exp = simpleExpressions.get(0);
|
||||
Assert.assertEquals("e.first_name", exp.getImage());
|
||||
Assert.assertEquals(2, exp.jjtGetNumChildren());
|
||||
Assert.assertEquals(ASTTableName.class, exp.jjtGetChild(0).getClass());
|
||||
Assert.assertEquals(ASTColumn.class, exp.jjtGetChild(1).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseSelectCount() throws Exception {
|
||||
String code = IOUtils.toString(this.getClass().getResourceAsStream("SelectCount.pls"),
|
||||
|
||||
@@ -92,7 +92,7 @@ public class WhereClauseTest extends AbstractPLSQLParserTst {
|
||||
StandardCharsets.UTF_8);
|
||||
ASTInput input = parsePLSQL(code);
|
||||
List<ASTRegexpLikeCondition> regexps = input.findDescendantsOfType(ASTRegexpLikeCondition.class);
|
||||
Assert.assertEquals(2, regexps.size());
|
||||
Assert.assertEquals(3, regexps.size());
|
||||
Assert.assertEquals("last_name", regexps.get(1).getSourceChar().getImage());
|
||||
Assert.assertEquals("'([aeiou])\\1'", regexps.get(1).getPattern().getImage());
|
||||
Assert.assertEquals("'i'", regexps.get(1).getMatchParam());
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
--
|
||||
-- Expressions in the SelectList
|
||||
--
|
||||
|
||||
BEGIN
|
||||
|
||||
SELECT e.first_name
|
||||
INTO test
|
||||
FROM employees e;
|
||||
|
||||
END;
|
||||
/
|
||||
+10
@@ -16,5 +16,15 @@ INTO test
|
||||
FROM employees
|
||||
WHERE REGEXP_LIKE (last_name, '([aeiou])\1', 'i')
|
||||
ORDER BY last_name;
|
||||
|
||||
SELECT e.first_name || ',' || e.last_name
|
||||
INTO test
|
||||
FROM employees e
|
||||
WHERE REGEXP_LIKE(
|
||||
e.last_name || ',' || e.first_name,
|
||||
NVL(:search, e.last_name || ',' || e.first_name),
|
||||
'i')
|
||||
AND NVL(:selected, 0) = 0;
|
||||
|
||||
END;
|
||||
/
|
||||
Reference in new issue
Block a user