Merge branch 'master' into plsql-1934-merge-into
This commit is contained in:
@ -19,6 +19,7 @@ This is a {{ site.pmd.release_type }} release.
|
||||
* [#5053](https://github.com/pmd/pmd/issues/5053): \[apex] CPD fails to parse string literals with escaped characters
|
||||
* plsql
|
||||
* [#1934](https://github.com/pmd/pmd/issues/1934): \[plsql] ParseException with MERGE statement in anonymous block
|
||||
* [#2779](https://github.com/pmd/pmd/issues/2779): \[plsql] Error while parsing statement with (Oracle) DML Error Logging
|
||||
|
||||
### 🚨 API Changes
|
||||
|
||||
|
@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
/**
|
||||
* Add support for MERGE (INTO) statement
|
||||
* Add support Error Logging for INSERT, UPDATE, DELETE
|
||||
*
|
||||
* Andreas Dangel 06/2024
|
||||
*====================================================================
|
||||
@ -2105,7 +2106,7 @@ ASTTableReference TableReference() :
|
||||
{
|
||||
QueryTableExpression()
|
||||
|
||||
[ LOOKAHEAD(2) TableAlias() ]
|
||||
[ LOOKAHEAD(2, {!getToken(1).getImage().equalsIgnoreCase("LOG")}) TableAlias() ]
|
||||
|
||||
{ return jjtThis; }
|
||||
}
|
||||
@ -2476,7 +2477,7 @@ ASTCursorForLoopStatement CursorForLoopStatement() :
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423
|
||||
*/
|
||||
ASTInsertStatement InsertStatement() :
|
||||
{}
|
||||
@ -2489,6 +2490,7 @@ ASTSingleTableInsert SingleTableInsert() :
|
||||
{}
|
||||
{
|
||||
InsertIntoClause() ( ValuesClause() [ ReturningClause() ] | Subquery() )
|
||||
[ ErrorLoggingClause() ]
|
||||
{ return jjtThis; }
|
||||
}
|
||||
|
||||
@ -2641,7 +2643,8 @@ ASTUpdateSetClause UpdateSetClause() :
|
||||
}
|
||||
|
||||
/**
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/UPDATE.html#GUID-027A462D-379D-4E35-8611-410F3AC8FDA5__I2126358
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/UPDATE.html#GUID-027A462D-379D-4E35-8611-410F3AC8FDA5__I2126358
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/DELETE.html#GUID-156845A5-B626-412B-9F95-8869B988ABD7__I2122564
|
||||
*/
|
||||
ASTReturningClause ReturningClause() :
|
||||
{}
|
||||
@ -2651,7 +2654,9 @@ ASTReturningClause ReturningClause() :
|
||||
}
|
||||
|
||||
/**
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/UPDATE.html#GUID-027A462D-379D-4E35-8611-410F3AC8FDA5__BCEEAAGC
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423__BGBDIGAH
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/UPDATE.html#GUID-027A462D-379D-4E35-8611-410F3AC8FDA5__BCEEAAGC
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/DELETE.html#GUID-156845A5-B626-412B-9F95-8869B988ABD7__CEGCHDJF
|
||||
*/
|
||||
ASTErrorLoggingClause ErrorLoggingClause() :
|
||||
{}
|
||||
@ -2664,12 +2669,17 @@ ASTErrorLoggingClause ErrorLoggingClause() :
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/DELETE.html#GUID-156845A5-B626-412B-9F95-8869B988ABD7
|
||||
*/
|
||||
ASTDeleteStatement DeleteStatement() :
|
||||
{}
|
||||
{
|
||||
<DELETE> [ <FROM> ]
|
||||
( TableReference() | <ONLY> "(" TableReference() ")" )
|
||||
[ WhereClause() ]
|
||||
[ ReturningClause() ]
|
||||
[ ErrorLoggingClause() ]
|
||||
{ return jjtThis; }
|
||||
}
|
||||
|
||||
|
@ -46,4 +46,9 @@ class PlsqlTreeDumpTest extends BaseTreeDumpTest {
|
||||
void parseMergeStatement() {
|
||||
doTest("MergeStatementIssue1934");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorLoggingClause() {
|
||||
doTest("ErrorLoggingClause2779");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
--
|
||||
-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
--
|
||||
|
||||
create or replace procedure test as
|
||||
begin
|
||||
|
||||
-- https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423__BCEGDJDJ
|
||||
INSERT INTO raises
|
||||
SELECT employee_id, salary*1.1 FROM employees
|
||||
WHERE commission_pct > .2
|
||||
LOG ERRORS INTO errlog ('my_bad') REJECT LIMIT 10;
|
||||
|
||||
-- https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/UPDATE.html#GUID-027A462D-379D-4E35-8611-410F3AC8FDA5__I2135485
|
||||
UPDATE people_demo1 p SET VALUE(p) =
|
||||
(SELECT VALUE(q) FROM people_demo2 q
|
||||
WHERE p.department_id = q.department_id)
|
||||
WHERE p.department_id = 10
|
||||
LOG ERRORS INTO errlog ('my_bad') REJECT LIMIT 10;
|
||||
|
||||
-- https://github.com/pmd/pmd/issues/2779
|
||||
delete from test_table talias
|
||||
log errors into err$_test_table reject limit unlimited;
|
||||
|
||||
-- without a table alias
|
||||
delete from test_table
|
||||
log errors into err$_test_table reject limit unlimited;
|
||||
end;
|
||||
/
|
@ -0,0 +1,149 @@
|
||||
+- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0]
|
||||
+- Global[@CanonicalImage = null]
|
||||
+- ProgramUnit[@CanonicalImage = null, @MethodName = "test", @Name = "test", @ObjectName = null]
|
||||
+- MethodDeclarator[@CanonicalImage = "TEST", @Image = "test", @ParameterCount = 1]
|
||||
| +- ObjectNameDeclaration[@CanonicalImage = "TEST", @Image = "test"]
|
||||
| +- ID[@CanonicalImage = "TEST", @Image = "test"]
|
||||
+- DeclarativeSection[@CanonicalImage = null]
|
||||
+- Statement[@CanonicalImage = null]
|
||||
| +- UnlabelledStatement[@CanonicalImage = null]
|
||||
| +- InsertStatement[@CanonicalImage = null]
|
||||
| +- SingleTableInsert[@CanonicalImage = null]
|
||||
| +- InsertIntoClause[@CanonicalImage = null]
|
||||
| | +- DMLTableExpressionClause[@CanonicalImage = null]
|
||||
| | +- TableName[@CanonicalImage = "RAISES", @Image = "raises"]
|
||||
| | +- ID[@CanonicalImage = "RAISES", @Image = "raises"]
|
||||
| +- QueryBlock[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false]
|
||||
| | +- SelectList[@CanonicalImage = null]
|
||||
| | | +- SqlExpression[@CanonicalImage = "EMPLOYEE_ID", @Image = "employee_id"]
|
||||
| | | | +- PrimaryPrefix[@CanonicalImage = "EMPLOYEE_ID", @Image = "employee_id", @SelfModifier = false]
|
||||
| | | | +- SimpleExpression[@CanonicalImage = "EMPLOYEE_ID", @Image = "employee_id"]
|
||||
| | | | +- Column[@CanonicalImage = "EMPLOYEE_ID", @Image = "employee_id"]
|
||||
| | | | +- ID[@CanonicalImage = "EMPLOYEE_ID", @Image = "employee_id"]
|
||||
| | | +- SqlExpression[@CanonicalImage = "SALARY * 1.1", @Image = "salary * 1.1"]
|
||||
| | | +- MultiplicativeExpression[@CanonicalImage = "SALARY * 1.1", @Image = "salary * 1.1"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "SALARY", @Image = "salary", @SelfModifier = false]
|
||||
| | | | +- SimpleExpression[@CanonicalImage = "SALARY", @Image = "salary"]
|
||||
| | | | +- Column[@CanonicalImage = "SALARY", @Image = "salary"]
|
||||
| | | | +- ID[@CanonicalImage = "SALARY", @Image = "salary"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "1.1", @Image = "1.1", @SelfModifier = false]
|
||||
| | | +- Literal[@CanonicalImage = "1.1", @Image = "1.1"]
|
||||
| | | +- NumericLiteral[@CanonicalImage = "1.1", @Image = "1.1"]
|
||||
| | +- FromClause[@CanonicalImage = null]
|
||||
| | | +- TableReference[@CanonicalImage = null]
|
||||
| | | +- TableName[@CanonicalImage = "EMPLOYEES", @Image = "employees"]
|
||||
| | | +- ID[@CanonicalImage = "EMPLOYEES", @Image = "employees"]
|
||||
| | +- WhereClause[@CanonicalImage = null]
|
||||
| | +- Condition[@CanonicalImage = null]
|
||||
| | +- CompoundCondition[@CanonicalImage = null, @Type = null]
|
||||
| | +- ComparisonCondition[@CanonicalImage = null, @Operator = ">"]
|
||||
| | +- SqlExpression[@CanonicalImage = "COMMISSION_PCT", @Image = "commission_pct"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "COMMISSION_PCT", @Image = "commission_pct", @SelfModifier = false]
|
||||
| | | +- SimpleExpression[@CanonicalImage = "COMMISSION_PCT", @Image = "commission_pct"]
|
||||
| | | +- Column[@CanonicalImage = "COMMISSION_PCT", @Image = "commission_pct"]
|
||||
| | | +- ID[@CanonicalImage = "COMMISSION_PCT", @Image = "commission_pct"]
|
||||
| | +- SqlExpression[@CanonicalImage = ".2", @Image = ".2"]
|
||||
| | +- PrimaryPrefix[@CanonicalImage = ".2", @Image = ".2", @SelfModifier = false]
|
||||
| | +- Literal[@CanonicalImage = ".2", @Image = ".2"]
|
||||
| | +- NumericLiteral[@CanonicalImage = ".2", @Image = ".2"]
|
||||
| +- ErrorLoggingClause[@CanonicalImage = null]
|
||||
| +- TableName[@CanonicalImage = "ERRLOG", @Image = "errlog"]
|
||||
| | +- ID[@CanonicalImage = "ERRLOG", @Image = "errlog"]
|
||||
| +- SqlExpression[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'"]
|
||||
| | +- PrimaryPrefix[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'", @SelfModifier = false]
|
||||
| | +- Literal[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'"]
|
||||
| | +- StringLiteral[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'", @String = "my_bad"]
|
||||
| +- NumericLiteral[@CanonicalImage = "10", @Image = "10"]
|
||||
+- Statement[@CanonicalImage = null]
|
||||
| +- UnlabelledStatement[@CanonicalImage = null]
|
||||
| +- UpdateStatement[@CanonicalImage = null]
|
||||
| +- DMLTableExpressionClause[@CanonicalImage = null]
|
||||
| | +- TableName[@CanonicalImage = "PEOPLE_DEMO1", @Image = "people_demo1"]
|
||||
| | +- ID[@CanonicalImage = "PEOPLE_DEMO1", @Image = "people_demo1"]
|
||||
| +- TableAlias[@CanonicalImage = "P", @Image = "p"]
|
||||
| | +- ID[@CanonicalImage = "P", @Image = "p"]
|
||||
| +- UpdateSetClause[@CanonicalImage = null]
|
||||
| | +- TableAlias[@CanonicalImage = "P", @Image = "p"]
|
||||
| | | +- ID[@CanonicalImage = "P", @Image = "p"]
|
||||
| | +- QueryBlock[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false]
|
||||
| | +- SelectList[@CanonicalImage = null]
|
||||
| | | +- SqlExpression[@CanonicalImage = "VALUE", @Image = "VALUE"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "VALUE", @Image = "VALUE", @SelfModifier = false]
|
||||
| | | +- FunctionCall[@CanonicalImage = "VALUE", @Image = "VALUE"]
|
||||
| | | +- FunctionName[@CanonicalImage = "VALUE", @Image = "VALUE"]
|
||||
| | | | +- ID[@CanonicalImage = "VALUE", @Image = "VALUE"]
|
||||
| | | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null]
|
||||
| | | +- ArgumentList[@CanonicalImage = null]
|
||||
| | | +- Argument[@CanonicalImage = null]
|
||||
| | | +- Expression[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "Q", @Image = "q", @SelfModifier = false]
|
||||
| | | +- SimpleExpression[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | | +- Column[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | | +- ID[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | +- FromClause[@CanonicalImage = null]
|
||||
| | | +- TableReference[@CanonicalImage = null]
|
||||
| | | +- TableName[@CanonicalImage = "PEOPLE_DEMO2", @Image = "people_demo2"]
|
||||
| | | | +- ID[@CanonicalImage = "PEOPLE_DEMO2", @Image = "people_demo2"]
|
||||
| | | +- TableAlias[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | | +- ID[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | +- WhereClause[@CanonicalImage = null]
|
||||
| | +- Condition[@CanonicalImage = null]
|
||||
| | +- CompoundCondition[@CanonicalImage = null, @Type = null]
|
||||
| | +- ComparisonCondition[@CanonicalImage = null, @Operator = "="]
|
||||
| | +- SqlExpression[@CanonicalImage = "P.DEPARTMENT_ID", @Image = "p.department_id"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "P.DEPARTMENT_ID", @Image = "p.department_id", @SelfModifier = false]
|
||||
| | | +- SimpleExpression[@CanonicalImage = "P.DEPARTMENT_ID", @Image = "p.department_id"]
|
||||
| | | +- TableName[@CanonicalImage = "P", @Image = "p"]
|
||||
| | | | +- ID[@CanonicalImage = "P", @Image = "p"]
|
||||
| | | +- Column[@CanonicalImage = "DEPARTMENT_ID", @Image = "department_id"]
|
||||
| | | +- ID[@CanonicalImage = "DEPARTMENT_ID", @Image = "department_id"]
|
||||
| | +- SqlExpression[@CanonicalImage = "Q.DEPARTMENT_ID", @Image = "q.department_id"]
|
||||
| | +- PrimaryPrefix[@CanonicalImage = "Q.DEPARTMENT_ID", @Image = "q.department_id", @SelfModifier = false]
|
||||
| | +- SimpleExpression[@CanonicalImage = "Q.DEPARTMENT_ID", @Image = "q.department_id"]
|
||||
| | +- TableName[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | | +- ID[@CanonicalImage = "Q", @Image = "q"]
|
||||
| | +- Column[@CanonicalImage = "DEPARTMENT_ID", @Image = "department_id"]
|
||||
| | +- ID[@CanonicalImage = "DEPARTMENT_ID", @Image = "department_id"]
|
||||
| +- WhereClause[@CanonicalImage = null]
|
||||
| | +- Condition[@CanonicalImage = null]
|
||||
| | +- CompoundCondition[@CanonicalImage = null, @Type = null]
|
||||
| | +- ComparisonCondition[@CanonicalImage = null, @Operator = "="]
|
||||
| | +- SqlExpression[@CanonicalImage = "P.DEPARTMENT_ID", @Image = "p.department_id"]
|
||||
| | | +- PrimaryPrefix[@CanonicalImage = "P.DEPARTMENT_ID", @Image = "p.department_id", @SelfModifier = false]
|
||||
| | | +- SimpleExpression[@CanonicalImage = "P.DEPARTMENT_ID", @Image = "p.department_id"]
|
||||
| | | +- TableName[@CanonicalImage = "P", @Image = "p"]
|
||||
| | | | +- ID[@CanonicalImage = "P", @Image = "p"]
|
||||
| | | +- Column[@CanonicalImage = "DEPARTMENT_ID", @Image = "department_id"]
|
||||
| | | +- ID[@CanonicalImage = "DEPARTMENT_ID", @Image = "department_id"]
|
||||
| | +- SqlExpression[@CanonicalImage = "10", @Image = "10"]
|
||||
| | +- PrimaryPrefix[@CanonicalImage = "10", @Image = "10", @SelfModifier = false]
|
||||
| | +- Literal[@CanonicalImage = "10", @Image = "10"]
|
||||
| | +- NumericLiteral[@CanonicalImage = "10", @Image = "10"]
|
||||
| +- ErrorLoggingClause[@CanonicalImage = null]
|
||||
| +- TableName[@CanonicalImage = "ERRLOG", @Image = "errlog"]
|
||||
| | +- ID[@CanonicalImage = "ERRLOG", @Image = "errlog"]
|
||||
| +- SqlExpression[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'"]
|
||||
| | +- PrimaryPrefix[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'", @SelfModifier = false]
|
||||
| | +- Literal[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'"]
|
||||
| | +- StringLiteral[@CanonicalImage = "\'MY_BAD\'", @Image = "\'my_bad\'", @String = "my_bad"]
|
||||
| +- NumericLiteral[@CanonicalImage = "10", @Image = "10"]
|
||||
+- Statement[@CanonicalImage = null]
|
||||
| +- UnlabelledStatement[@CanonicalImage = null]
|
||||
| +- DeleteStatement[@CanonicalImage = null]
|
||||
| +- TableReference[@CanonicalImage = null]
|
||||
| | +- TableName[@CanonicalImage = "TEST_TABLE", @Image = "test_table"]
|
||||
| | | +- ID[@CanonicalImage = "TEST_TABLE", @Image = "test_table"]
|
||||
| | +- TableAlias[@CanonicalImage = "TALIAS", @Image = "talias"]
|
||||
| | +- ID[@CanonicalImage = "TALIAS", @Image = "talias"]
|
||||
| +- ErrorLoggingClause[@CanonicalImage = null]
|
||||
| +- TableName[@CanonicalImage = "ERR$_TEST_TABLE", @Image = "err$_test_table"]
|
||||
| +- ID[@CanonicalImage = "ERR$_TEST_TABLE", @Image = "err$_test_table"]
|
||||
+- Statement[@CanonicalImage = null]
|
||||
+- UnlabelledStatement[@CanonicalImage = null]
|
||||
+- DeleteStatement[@CanonicalImage = null]
|
||||
+- TableReference[@CanonicalImage = null]
|
||||
| +- TableName[@CanonicalImage = "TEST_TABLE", @Image = "test_table"]
|
||||
| +- ID[@CanonicalImage = "TEST_TABLE", @Image = "test_table"]
|
||||
+- ErrorLoggingClause[@CanonicalImage = null]
|
||||
+- TableName[@CanonicalImage = "ERR$_TEST_TABLE", @Image = "err$_test_table"]
|
||||
+- ID[@CanonicalImage = "ERR$_TEST_TABLE", @Image = "err$_test_table"]
|
Reference in New Issue
Block a user