pmd / pmd

An extensible multilanguage static code analyzer.
https://pmd.github.io
Other
4.9k stars 1.5k forks source link

[plsql] Parsing exception with XMLTYPE and XMLQUERY function in SELECT #4441

Open hgodinez89 opened 1 year ago

hgodinez89 commented 1 year ago

Affects PMD Version:

This error was testing in the following versions:

Description:

Trying to analyze pl/sql code with XMLQUERY function in SELECT, PMD raises an exception error that indicates "Error while parsing".

Exception Stacktrace:

net.sourceforge.pmd.PMDException: Error while parsing C:\testfolder\example_code.sql
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCodeWithoutCache(SourceCodeProcessor.java:124)
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCode(SourceCodeProcessor.java:100)
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCode(SourceCodeProcessor.java:62)
    at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:85)
    at net.sourceforge.pmd.processor.PmdRunnable.call(PmdRunnable.java:29)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at java.base/java.lang.Thread.run(Thread.java:832)
Caused by: net.sourceforge.pmd.lang.plsql.ast.ParseException: Encountered "  "l_tagname "" at line 19, column 28.
Was expecting one of:
    "\'" ...
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.generateParseException(PLSQLParser.java)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.jj_consume_token(PLSQLParser.java)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.StringLiteral(PLSQLParser.java:43899)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.FunctionCall(PLSQLParser.java:14792)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.PrimaryPrefix(PLSQLParser.java:42999)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.PrimaryExpression(PLSQLParser.java:42939)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.IsOfTypeCondition(PLSQLParser.java:42165)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.IsNullCondition(PLSQLParser.java:41651)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.UnaryExpressionNotPlusMinus(PLSQLParser.java:41213)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.UnaryExpression(PLSQLParser.java:41043)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.MultiplicativeExpression(PLSQLParser.java:40595)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.AdditiveExpression(PLSQLParser.java:40481)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.RelationalExpression(PLSQLParser.java:40241)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.EqualityExpression(PLSQLParser.java:40171)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.ConditionalAndExpression(PLSQLParser.java:40123)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.ConditionalOrExpression(PLSQLParser.java:40075)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.Expression(PLSQLParser.java:39234)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.FunctionCall(PLSQLParser.java:14786)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.PrimaryPrefix(PLSQLParser.java:42999)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.PrimaryExpression(PLSQLParser.java:42939)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.IsOfTypeCondition(PLSQLParser.java:42165)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.IsNullCondition(PLSQLParser.java:41651)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.UnaryExpressionNotPlusMinus(PLSQLParser.java:41213)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.UnaryExpression(PLSQLParser.java:41043)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.MultiplicativeExpression(PLSQLParser.java:40595)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.AdditiveExpression(PLSQLParser.java:40481)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.SqlExpression(PLSQLParser.java:13477)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.SelectListEntry(PLSQLParser.java:21897)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.SelectList(PLSQLParser.java:21846)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.SelectStatement(PLSQLParser.java:28344)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.UnlabelledStatement(PLSQLParser.java:23769)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.Statement(PLSQLParser.java:24671)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.TypeMethod(PLSQLParser.java:49886)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.MethodDeclaration(PLSQLParser.java:7692)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.DeclarativeUnit(PLSQLParser.java:2745)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.DeclarativeSection(PLSQLParser.java:3154)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.PackageBody(PLSQLParser.java:1915)
    at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.Input(PLSQLParser.java:135)
    at net.sourceforge.pmd.lang.plsql.PLSQLParser.parse(PLSQLParser.java:61)
    at net.sourceforge.pmd.lang.AbstractParser.doParse(AbstractParser.java:44)
    at net.sourceforge.pmd.SourceCodeProcessor.parse(SourceCodeProcessor.java:136)
    at net.sourceforge.pmd.SourceCodeProcessor.processSource(SourceCodeProcessor.java:200)
    at net.sourceforge.pmd.SourceCodeProcessor.processSourceCodeWithoutCache(SourceCodeProcessor.java:118)
    ... 10 more

Code Sample demonstrating the issue:

DECLARE
   --
   l_xml XMLTYPE := XMLTYPE('<Catalog>
   <Book>
      <Author>Steven Feuerstein</Author>
      <Title>Oracle PLSQL Languaje Pocket Reference</Title>
      <Genre>Programming</Genre>
      <Price>18.25</Price>
      <PublishDate>2015-09-04</PublishDate>
      <Description>A guide to Oracle PLSQL Language Fundamentals.</Description>
   </Book>
</Catalog>');
   --
   l_tagname VARCHAR2(100) := '$p//Author';
   l_result  VARCHAR2(4000);
   --
BEGIN
   --
   SELECT XMLCAST(XMLQUERY(l_tagname PASSING l_xml AS "p" RETURNING CONTENT) AS VARCHAR2(4000))
     INTO l_result
     FROM DUAL;
   --
   DBMS_OUTPUT.put_line(l_result);
   --
END;

Steps to reproduce:

  1. Put the code above ("Code Sample demonstrating the issue" section) in example_code.sql
  2. Execute PMD analyzer from CLI.
  3. See the error showed in the "Exception Stacktrace" section.

Running PMD through: [CLI]

adangel commented 8 months ago

The issue is still reproducible under PMD 7.0.0.

XMLTYPE is not supported when declaring vars. The XMLTYPE has several possible constructors, see https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/XMLTYPE.html#GUID-59081026-A42A-4352-B5EA-A6E433A51F5E They all take the xmlData as the first parameter, which might be a string literal, as in the example here.

XMLQUERY support is only implemented on string literals (via #1685) and not identifiers, as in this example. Doc: https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/XMLQUERY.html#GUID-9E8D3220-2CF5-4C63-BDC2-0526D57B9CDB and https://docs.oracle.com/en/database/oracle/oracle-database/23/adxdb/xquery-and-XML-DB.html#GUID-39CDBF4D-258D-4CFE-AEBF-06ECD660C08D

XQuery_string is a complete XQuery expression, possibly including a prolog, as a literal string.

Apparently, the "literal string" can also be a variable... like in this example "l_tagname"...