[plsql] Parsing exception OPEN ref_cursor_name FOR statement
Fixes #3487
This commit is contained in:
@ -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
|
||||
|
@ -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() :
|
||||
{}
|
||||
{
|
||||
<OPEN> [Expression()]
|
||||
//[LOOKAHEAD(functionCall()) functionCall() | QualifiedName()]
|
||||
[<FOR> Expression() [<USING> (<IN> | <OUT> | <IN_OUT>)? Expression() ("," (<IN> | <OUT> | <IN_OUT>)? Expression())*]]
|
||||
{ return jjtThis ; }
|
||||
<OPEN> [Expression()]
|
||||
[<FOR> ( SelectStatement() | Expression() ) [ UsingClause() ] ]
|
||||
|
||||
{ return jjtThis ; }
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2768,12 +2776,18 @@ ASTEmbeddedSqlStatement EmbeddedSqlStatement() :
|
||||
{
|
||||
<EXECUTE> <IMMEDIATE> StringExpression()
|
||||
[ <INTO> Name() ("," Name())* ]
|
||||
[ <USING> [ <IN> [ <OUT> ] | <OUT> ] Expression() ("," [ <IN> [ <OUT> ] | <OUT> ] Expression())* ]
|
||||
[ UsingClause() ]
|
||||
[ ( <RETURN> | <RETURNING> ) <INTO> Expression() ("," Expression())*] ";"
|
||||
// PIPELINED FUNCTION OUTPUT
|
||||
{ return jjtThis ; }
|
||||
}
|
||||
|
||||
void UsingClause() #void :
|
||||
{}
|
||||
{
|
||||
<USING> [ <IN> [ <OUT> ] | <OUT> ] Expression() ("," [ <IN> [ <OUT> ] | <OUT> ] Expression())*
|
||||
}
|
||||
|
||||
ASTPipelineStatement PipelineStatement() :
|
||||
{}
|
||||
{
|
||||
@ -4900,7 +4914,6 @@ TOKEN [IGNORE_CASE]:
|
||||
<HOUR: "HOUR"> |
|
||||
<IMMEDIATE: "IMMEDIATE"> |
|
||||
<INNER: "INNER"> |
|
||||
<IN_OUT: "IN_OUT"> |
|
||||
<INDICES: "INDICES"> |
|
||||
<INCLUDING: "INCLUDING"> |
|
||||
<INDEXTYPE: "INDEXTYPE"> |
|
||||
|
@ -32,4 +32,8 @@ public class PlsqlTreeDumpTest extends BaseTreeDumpTest {
|
||||
doTest("ParsingExclusion");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseOpenForStatement() {
|
||||
doTest("OpenForStatement");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
/
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
Reference in New Issue
Block a user