diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index b8f8783555..dad9ba1d1f 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -16,6 +16,9 @@ This is a {{ site.pmd.release_type }} release. ### Fixed Issues +* plsql + * [#3487](https://github.com/pmd/pmd/issues/3487): \[plsql] Parsing exception OPEN ref_cursor_name FOR statement + ### API Changes ### External Contributions diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 280b2d6752..f6ceeaa92e 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -27,6 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** + * Add support for Select statement within OPEN FOR Statements + * + * Andreas Dangel 09/2021 + *==================================================================== * Add support for XMLROOT, improve ExtractExpression to support xml * * Piotr Szymanski 03/2020 @@ -84,7 +88,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Andreas Dangel 07/2018 *==================================================================== - * Added ASTIsOfTypeCondition node, added support for USING IN|OUT|IN_OUT + * Added ASTIsOfTypeCondition node, added support for USING IN|OUT|IN OUT * See PMD Bug #1520 * * Andreas Dangel 11/2016 @@ -2741,13 +2745,17 @@ ASTCloseStatement CloseStatement() : { jjtThis.setImage(cursor.getImage()) ; return jjtThis ; } } +/* + * See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-statement.html#GUID-FB5A9CC3-655F-4AF4-8105-14CB39F2FEA8 + * and https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96 + */ ASTOpenStatement OpenStatement() : {} { - [Expression()] - //[LOOKAHEAD(functionCall()) functionCall() | QualifiedName()] - [ Expression() [ ( | | )? Expression() ("," ( | | )? Expression())*]] - { return jjtThis ; } + [Expression()] + [ ( SelectStatement() | Expression() ) [ UsingClause() ] ] + + { return jjtThis ; } } /* @@ -2768,12 +2776,18 @@ ASTEmbeddedSqlStatement EmbeddedSqlStatement() : { StringExpression() [ Name() ("," Name())* ] - [ [ [ ] | ] Expression() ("," [ [ ] | ] Expression())* ] + [ UsingClause() ] [ ( | ) Expression() ("," Expression())*] ";" // PIPELINED FUNCTION OUTPUT { return jjtThis ; } } +void UsingClause() #void : +{} +{ + [ [ ] | ] Expression() ("," [ [ ] | ] Expression())* +} + ASTPipelineStatement PipelineStatement() : {} { @@ -4900,7 +4914,6 @@ TOKEN [IGNORE_CASE]: | | | - | | | | diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PlsqlTreeDumpTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PlsqlTreeDumpTest.java index 41367994a6..089c16f76a 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PlsqlTreeDumpTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/PlsqlTreeDumpTest.java @@ -32,4 +32,8 @@ public class PlsqlTreeDumpTest extends BaseTreeDumpTest { doTest("ParsingExclusion"); } + @Test + public void parseOpenForStatement() { + doTest("OpenForStatement"); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.pls new file mode 100644 index 0000000000..331498fb09 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.pls @@ -0,0 +1,62 @@ +-- +-- See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96 +-- https://github.com/pmd/pmd/issues/3487 +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_ref_cursor IS REF CURSOR; + -- + l_ref_cursor t_ref_cursor; + -- +BEGIN + -- + OPEN l_ref_cursor FOR + SELECT * + FROM DUAL; + -- +END EXAMPLE_PROCEDURE; + +-- +-- Example 6-26 Fetching Data with Cursor Variables +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/static-sql.html#GUID-AA5A2016-1B76-4961-9AFB-EB052F0D0FB2 +-- +DECLARE + cv SYS_REFCURSOR; -- cursor variable + + v_lastname employees.last_name%TYPE; -- variable for last_name + v_jobid employees.job_id%TYPE; -- variable for job_id + + query_2 VARCHAR2(200) := + 'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'; + + v_employees employees%ROWTYPE; -- record variable row of table + +BEGIN + OPEN cv FOR + SELECT last_name, job_id FROM employees + WHERE REGEXP_LIKE (job_id, 'S[HT]_CLERK') + ORDER BY last_name; + + LOOP -- Fetches 2 columns into variables + FETCH cv INTO v_lastname, v_jobid; + EXIT WHEN cv%NOTFOUND; + DBMS_OUTPUT.PUT_LINE( RPAD(v_lastname, 25, ' ') || v_jobid ); + END LOOP; + + DBMS_OUTPUT.PUT_LINE( '-------------------------------------' ); + + OPEN cv FOR query_2; + + LOOP -- Fetches entire row into the v_employees record + FETCH cv INTO v_employees; + EXIT WHEN cv%NOTFOUND; + DBMS_OUTPUT.PUT_LINE( RPAD(v_employees.last_name, 25, ' ') || + v_employees.job_id ); + END LOOP; + + CLOSE cv; +END; +/ diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt new file mode 100644 index 0000000000..9697ba6fb1 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/OpenForStatement.txt @@ -0,0 +1,373 @@ ++- Input[@CanonicalImage = null, @ExcludedLinesCount = 0, @ExcludedRangesCount = 0, @Sourcecode = "-- +-- See https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96 +-- https://github.com/pmd/pmd/issues/3487 +-- + +CREATE OR REPLACE PROCEDURE EXAMPLE_PROCEDURE IS + -- + TYPE t_ref_cursor IS REF CURSOR; + -- + l_ref_cursor t_ref_cursor; + -- +BEGIN + -- + OPEN l_ref_cursor FOR + SELECT * + FROM DUAL; + -- +END EXAMPLE_PROCEDURE; + +-- +-- Example 6-26 Fetching Data with Cursor Variables +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/static-sql.html#GUID-AA5A2016-1B76-4961-9AFB-EB052F0D0FB2 +-- +DECLARE + cv SYS_REFCURSOR; -- cursor variable + + v_lastname employees.last_name%TYPE; -- variable for last_name + v_jobid employees.job_id%TYPE; -- variable for job_id + + query_2 VARCHAR2(200) := + 'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'; + + v_employees employees%ROWTYPE; -- record variable row of table + +BEGIN + OPEN cv FOR + SELECT last_name, job_id FROM employees + WHERE REGEXP_LIKE (job_id, 'S[HT]_CLERK') + ORDER BY last_name; + + LOOP -- Fetches 2 columns into variables + FETCH cv INTO v_lastname, v_jobid; + EXIT WHEN cv%NOTFOUND; + DBMS_OUTPUT.PUT_LINE( RPAD(v_lastname, 25, ' ') || v_jobid ); + END LOOP; + + DBMS_OUTPUT.PUT_LINE( '-------------------------------------' ); + + OPEN cv FOR query_2; + + LOOP -- Fetches entire row into the v_employees record + FETCH cv INTO v_employees; + EXIT WHEN cv%NOTFOUND; + DBMS_OUTPUT.PUT_LINE( RPAD(v_employees.last_name, 25, ' ') || + v_employees.job_id ); + END LOOP; + + CLOSE cv; +END; +/ +"] + +- Global[@CanonicalImage = null] + | +- ProgramUnit[@CanonicalImage = null, @MethodName = "EXAMPLE_PROCEDURE", @Name = "EXAMPLE_PROCEDURE", @ObjectName = null] + | +- MethodDeclarator[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE", @ParameterCount = 1] + | | +- ObjectNameDeclaration[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + | | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + | +- DeclarativeSection[@CanonicalImage = null] + | | +- DeclarativeUnit[@CanonicalImage = null] + | | | +- SubTypeDefinition[@CanonicalImage = "T_REF_CURSOR", @Image = "t_ref_cursor"] + | | | +- QualifiedID[@CanonicalImage = "T_REF_CURSOR", @Image = "t_ref_cursor"] + | | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "L_REF_CURSOR T_REF_CURSOR", @Image = "l_ref_cursor t_ref_cursor"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor"] + | | | +- ID[@CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor"] + | | +- Datatype[@CanonicalImage = "T_REF_CURSOR", @Image = "t_ref_cursor", @TypeImage = "t_ref_cursor"] + | | +- QualifiedName[@CanonicalImage = "T_REF_CURSOR", @Image = "t_ref_cursor"] + | | +- UnqualifiedID[@CanonicalImage = "T_REF_CURSOR", @Image = "t_ref_cursor"] + | +- Statement[@CanonicalImage = null] + | | +- UnlabelledStatement[@CanonicalImage = null] + | | +- OpenStatement[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor"] + | | | +- PrimaryPrefix[@CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor", @SelfModifier = false] + | | | +- SimpleExpression[@CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor"] + | | | +- Column[@CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor"] + | | | +- ID[@CanonicalImage = "L_REF_CURSOR", @Image = "l_ref_cursor"] + | | +- SelectStatement[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false] + | | +- SelectList[@CanonicalImage = null] + | | +- FromClause[@CanonicalImage = null] + | | +- TableReference[@CanonicalImage = null] + | | +- TableName[@CanonicalImage = "DUAL", @Image = "DUAL"] + | | +- ID[@CanonicalImage = "DUAL", @Image = "DUAL"] + | +- ID[@CanonicalImage = "EXAMPLE_PROCEDURE", @Image = "EXAMPLE_PROCEDURE"] + +- Global[@CanonicalImage = null] + +- Block[@CanonicalImage = null] + +- DeclarativeSection[@CanonicalImage = null] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "CV SYS_REFCURSOR", @Image = "cv SYS_REFCURSOR"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "CV", @Image = "cv"] + | | | +- ID[@CanonicalImage = "CV", @Image = "cv"] + | | +- Datatype[@CanonicalImage = "SYS_REFCURSOR", @Image = "SYS_REFCURSOR", @TypeImage = "SYS_REFCURSOR"] + | | +- ScalarDataTypeName[@CanonicalImage = "SYS_REFCURSOR", @Image = "SYS_REFCURSOR"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "V_LASTNAME EMPLOYEES.LAST_NAME%TYPE", @Image = "v_lastname employees.last_name%TYPE"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- ID[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | +- Datatype[@CanonicalImage = "EMPLOYEES.LAST_NAME%TYPE", @Image = "employees.last_name%TYPE", @TypeImage = "employees.last_name%TYPE"] + | | +- QualifiedName[@CanonicalImage = "EMPLOYEES.LAST_NAME", @Image = "employees.last_name"] + | | +- UnqualifiedID[@CanonicalImage = "EMPLOYEES", @Image = "employees"] + | | +- QualifiedID[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "V_JOBID EMPLOYEES.JOB_ID%TYPE", @Image = "v_jobid employees.job_id%TYPE"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | | | +- ID[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | | +- Datatype[@CanonicalImage = "EMPLOYEES.JOB_ID%TYPE", @Image = "employees.job_id%TYPE", @TypeImage = "employees.job_id%TYPE"] + | | +- QualifiedName[@CanonicalImage = "EMPLOYEES.JOB_ID", @Image = "employees.job_id"] + | | +- UnqualifiedID[@CanonicalImage = "EMPLOYEES", @Image = "employees"] + | | +- QualifiedID[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | +- DeclarativeUnit[@CanonicalImage = null] + | | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | | +- VariableOrConstantDeclarator[@CanonicalImage = "QUERY_2 VARCHAR2(200) := 'SELECT * FROM EMPLOYEES + WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY JOB_ID'", @Image = "query_2 VARCHAR2(200) := 'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'"] + | | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "QUERY_2", @Image = "query_2"] + | | | +- ID[@CanonicalImage = "QUERY_2", @Image = "query_2"] + | | +- Datatype[@CanonicalImage = "VARCHAR2(200)", @Image = "VARCHAR2(200)", @TypeImage = "VARCHAR2(200)"] + | | | +- ScalarDataTypeName[@CanonicalImage = "VARCHAR2(200)", @Image = "VARCHAR2(200)"] + | | | +- NumericLiteral[@CanonicalImage = "200", @Image = "200"] + | | +- VariableOrConstantInitializer[@CanonicalImage = "'SELECT * FROM EMPLOYEES + WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'"] + | | +- Expression[@CanonicalImage = "'SELECT * FROM EMPLOYEES + WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'"] + | | +- PrimaryPrefix[@CanonicalImage = "'SELECT * FROM EMPLOYEES + WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'SELECT * FROM EMPLOYEES + WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'"] + | | +- StringLiteral[@CanonicalImage = "'SELECT * FROM EMPLOYEES + WHERE REGEXP_LIKE (JOB_ID, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY JOB_ID'", @Image = "'SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id'", @String = "SELECT * FROM employees + WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') + ORDER BY job_id"] + | +- DeclarativeUnit[@CanonicalImage = null] + | +- VariableOrConstantDeclaration[@CanonicalImage = null] + | +- VariableOrConstantDeclarator[@CanonicalImage = "V_EMPLOYEES EMPLOYEES%ROWTYPE", @Image = "v_employees employees%ROWTYPE"] + | +- VariableOrConstantDeclaratorId[@Array = false, @ArrayDepth = 0, @CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | +- ID[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | +- Datatype[@CanonicalImage = "EMPLOYEES%ROWTYPE", @Image = "employees%ROWTYPE", @TypeImage = "employees%ROWTYPE"] + | +- QualifiedName[@CanonicalImage = "EMPLOYEES", @Image = "employees"] + | +- UnqualifiedID[@CanonicalImage = "EMPLOYEES", @Image = "employees"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- OpenStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "CV", @Image = "cv"] + | | +- PrimaryPrefix[@CanonicalImage = "CV", @Image = "cv", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "CV", @Image = "cv"] + | | +- Column[@CanonicalImage = "CV", @Image = "cv"] + | | +- ID[@CanonicalImage = "CV", @Image = "cv"] + | +- SelectStatement[@All = false, @CanonicalImage = null, @Distinct = false, @Unique = false] + | +- SelectList[@CanonicalImage = null] + | | +- SqlExpression[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | | | +- PrimaryPrefix[@CanonicalImage = "LAST_NAME", @Image = "last_name", @SelfModifier = false] + | | | +- SimpleExpression[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | | | +- Column[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | | | +- ID[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | | +- SqlExpression[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | +- PrimaryPrefix[@CanonicalImage = "JOB_ID", @Image = "job_id", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | +- Column[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | +- ID[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | +- 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] + | | +- RegexpLikeCondition[@CanonicalImage = null, @MatchParam = null] + | | +- SqlExpression[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | | +- PrimaryPrefix[@CanonicalImage = "JOB_ID", @Image = "job_id", @SelfModifier = false] + | | | +- SimpleExpression[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | | +- Column[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | | +- ID[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | | +- SqlExpression[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'"] + | | +- PrimaryPrefix[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'"] + | | +- StringLiteral[@CanonicalImage = "'S[HT]_CLERK'", @Image = "'S[HT]_CLERK'", @String = "S[HT]_CLERK"] + | +- OrderByClause[@CanonicalImage = null] + | +- SqlExpression[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | +- PrimaryPrefix[@CanonicalImage = "LAST_NAME", @Image = "last_name", @SelfModifier = false] + | +- SimpleExpression[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | +- Column[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | +- ID[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- LoopStatement[@CanonicalImage = null] + | +- Statement[@CanonicalImage = null] + | | +- UnlabelledStatement[@CanonicalImage = null] + | | +- FetchStatement[@BulkCollect = false, @CanonicalImage = null, @Limit = false] + | | +- QualifiedName[@CanonicalImage = "CV", @Image = "cv"] + | | | +- UnqualifiedID[@CanonicalImage = "CV", @Image = "cv"] + | | +- Expression[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- PrimaryPrefix[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname", @SelfModifier = false] + | | | +- SimpleExpression[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- Column[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- ID[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | +- Expression[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | | +- PrimaryPrefix[@CanonicalImage = "V_JOBID", @Image = "v_jobid", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | | +- Column[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | | +- ID[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | +- Statement[@CanonicalImage = null] + | | +- UnlabelledStatement[@CanonicalImage = null] + | | +- ExitStatement[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "CV%NOTFOUND", @Image = "cv%NOTFOUND"] + | | +- PrimaryPrefix[@CanonicalImage = "CV%NOTFOUND", @Image = "cv%NOTFOUND", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "CV%NOTFOUND", @Image = "cv%NOTFOUND"] + | | +- Column[@CanonicalImage = "CV", @Image = "cv"] + | | +- ID[@CanonicalImage = "CV", @Image = "cv"] + | +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | +- PrimaryPrefix[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE", @SelfModifier = false] + | +- FunctionCall[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | +- FunctionName[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | | +- ID[@CanonicalImage = "DBMS_OUTPUT", @Image = "DBMS_OUTPUT"] + | | +- ID[@CanonicalImage = "PUT_LINE", @Image = "PUT_LINE"] + | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | +- ArgumentList[@CanonicalImage = null] + | +- Argument[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "RPAD || V_JOBID", @Image = "RPAD || v_jobid"] + | +- AdditiveExpression[@CanonicalImage = "RPAD || V_JOBID", @Image = "RPAD || v_jobid"] + | +- PrimaryPrefix[@CanonicalImage = "RPAD", @Image = "RPAD", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "RPAD", @Image = "RPAD"] + | | +- FunctionName[@CanonicalImage = "RPAD", @Image = "RPAD"] + | | | +- ID[@CanonicalImage = "RPAD", @Image = "RPAD"] + | | +- Arguments[@ArgumentCount = 3, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | | +- Expression[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- PrimaryPrefix[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname", @SelfModifier = false] + | | | +- SimpleExpression[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- Column[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | | +- ID[@CanonicalImage = "V_LASTNAME", @Image = "v_lastname"] + | | +- Argument[@CanonicalImage = null] + | | | +- Expression[@CanonicalImage = "25", @Image = "25"] + | | | +- PrimaryPrefix[@CanonicalImage = "25", @Image = "25", @SelfModifier = false] + | | | +- Literal[@CanonicalImage = "25", @Image = "25"] + | | | +- NumericLiteral[@CanonicalImage = "25", @Image = "25"] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "' '", @Image = "' '"] + | | +- PrimaryPrefix[@CanonicalImage = "' '", @Image = "' '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "' '", @Image = "' '"] + | +- PrimaryPrefix[@CanonicalImage = "V_JOBID", @Image = "v_jobid", @SelfModifier = false] + | +- SimpleExpression[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | +- Column[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + | +- ID[@CanonicalImage = "V_JOBID", @Image = "v_jobid"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | +- PrimaryPrefix[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE", @SelfModifier = false] + | +- FunctionCall[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | +- FunctionName[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | | +- ID[@CanonicalImage = "DBMS_OUTPUT", @Image = "DBMS_OUTPUT"] + | | +- ID[@CanonicalImage = "PUT_LINE", @Image = "PUT_LINE"] + | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | +- ArgumentList[@CanonicalImage = null] + | +- Argument[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'"] + | +- PrimaryPrefix[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'", @SelfModifier = false] + | +- Literal[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'"] + | +- StringLiteral[@CanonicalImage = "'-------------------------------------'", @Image = "'-------------------------------------'", @String = "-------------------------------------"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- OpenStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "CV", @Image = "cv"] + | | +- PrimaryPrefix[@CanonicalImage = "CV", @Image = "cv", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "CV", @Image = "cv"] + | | +- Column[@CanonicalImage = "CV", @Image = "cv"] + | | +- ID[@CanonicalImage = "CV", @Image = "cv"] + | +- Expression[@CanonicalImage = "QUERY_2", @Image = "query_2"] + | +- PrimaryPrefix[@CanonicalImage = "QUERY_2", @Image = "query_2", @SelfModifier = false] + | +- SimpleExpression[@CanonicalImage = "QUERY_2", @Image = "query_2"] + | +- Column[@CanonicalImage = "QUERY_2", @Image = "query_2"] + | +- ID[@CanonicalImage = "QUERY_2", @Image = "query_2"] + +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- LoopStatement[@CanonicalImage = null] + | +- Statement[@CanonicalImage = null] + | | +- UnlabelledStatement[@CanonicalImage = null] + | | +- FetchStatement[@BulkCollect = false, @CanonicalImage = null, @Limit = false] + | | +- QualifiedName[@CanonicalImage = "CV", @Image = "cv"] + | | | +- UnqualifiedID[@CanonicalImage = "CV", @Image = "cv"] + | | +- Expression[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | +- PrimaryPrefix[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | +- Column[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | +- ID[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | +- Statement[@CanonicalImage = null] + | | +- UnlabelledStatement[@CanonicalImage = null] + | | +- ExitStatement[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "CV%NOTFOUND", @Image = "cv%NOTFOUND"] + | | +- PrimaryPrefix[@CanonicalImage = "CV%NOTFOUND", @Image = "cv%NOTFOUND", @SelfModifier = false] + | | +- SimpleExpression[@CanonicalImage = "CV%NOTFOUND", @Image = "cv%NOTFOUND"] + | | +- Column[@CanonicalImage = "CV", @Image = "cv"] + | | +- ID[@CanonicalImage = "CV", @Image = "cv"] + | +- Statement[@CanonicalImage = null] + | +- UnlabelledStatement[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | +- PrimaryPrefix[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE", @SelfModifier = false] + | +- FunctionCall[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | +- FunctionName[@CanonicalImage = "DBMS_OUTPUT.PUT_LINE", @Image = "DBMS_OUTPUT.PUT_LINE"] + | | +- ID[@CanonicalImage = "DBMS_OUTPUT", @Image = "DBMS_OUTPUT"] + | | +- ID[@CanonicalImage = "PUT_LINE", @Image = "PUT_LINE"] + | +- Arguments[@ArgumentCount = 1, @CanonicalImage = null] + | +- ArgumentList[@CanonicalImage = null] + | +- Argument[@CanonicalImage = null] + | +- Expression[@CanonicalImage = "RPAD || V_EMPLOYEES.JOB_ID", @Image = "RPAD || v_employees.job_id"] + | +- AdditiveExpression[@CanonicalImage = "RPAD || V_EMPLOYEES.JOB_ID", @Image = "RPAD || v_employees.job_id"] + | +- PrimaryPrefix[@CanonicalImage = "RPAD", @Image = "RPAD", @SelfModifier = false] + | | +- FunctionCall[@CanonicalImage = "RPAD", @Image = "RPAD"] + | | +- FunctionName[@CanonicalImage = "RPAD", @Image = "RPAD"] + | | | +- ID[@CanonicalImage = "RPAD", @Image = "RPAD"] + | | +- Arguments[@ArgumentCount = 3, @CanonicalImage = null] + | | +- ArgumentList[@CanonicalImage = null] + | | +- Argument[@CanonicalImage = null] + | | | +- Expression[@CanonicalImage = "V_EMPLOYEES.LAST_NAME", @Image = "v_employees.last_name"] + | | | +- PrimaryPrefix[@CanonicalImage = "V_EMPLOYEES.LAST_NAME", @Image = "v_employees.last_name", @SelfModifier = false] + | | | +- SimpleExpression[@CanonicalImage = "V_EMPLOYEES.LAST_NAME", @Image = "v_employees.last_name"] + | | | +- TableName[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | | | +- ID[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | | +- Column[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | | | +- ID[@CanonicalImage = "LAST_NAME", @Image = "last_name"] + | | +- Argument[@CanonicalImage = null] + | | | +- Expression[@CanonicalImage = "25", @Image = "25"] + | | | +- PrimaryPrefix[@CanonicalImage = "25", @Image = "25", @SelfModifier = false] + | | | +- Literal[@CanonicalImage = "25", @Image = "25"] + | | | +- NumericLiteral[@CanonicalImage = "25", @Image = "25"] + | | +- Argument[@CanonicalImage = null] + | | +- Expression[@CanonicalImage = "' '", @Image = "' '"] + | | +- PrimaryPrefix[@CanonicalImage = "' '", @Image = "' '", @SelfModifier = false] + | | +- Literal[@CanonicalImage = "' '", @Image = "' '"] + | +- PrimaryPrefix[@CanonicalImage = "V_EMPLOYEES.JOB_ID", @Image = "v_employees.job_id", @SelfModifier = false] + | +- SimpleExpression[@CanonicalImage = "V_EMPLOYEES.JOB_ID", @Image = "v_employees.job_id"] + | +- TableName[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | | +- ID[@CanonicalImage = "V_EMPLOYEES", @Image = "v_employees"] + | +- Column[@CanonicalImage = "JOB_ID", @Image = "job_id"] + | +- ID[@CanonicalImage = "JOB_ID", @Image = "job_id"] + +- Statement[@CanonicalImage = null] + +- UnlabelledStatement[@CanonicalImage = null] + +- CloseStatement[@CanonicalImage = "CV", @Image = "cv"] + +- QualifiedName[@CanonicalImage = "CV", @Image = "cv"] + +- UnqualifiedID[@CanonicalImage = "CV", @Image = "cv"] diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls index 3eaf1734f7..57f419eb5e 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/Using.pls @@ -12,5 +12,5 @@ BEGIN open cursor for 'query' USING variable; open cursor for 'query' USING IN variable; open cursor for 'query' USING OUT variable, IN othervariable; - open cursor for 'query' USING IN_OUT variable; + open cursor for 'query' USING IN OUT variable; END;