Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plsql] Parse error for operator in TRIM function call #5522

Closed
Ferada opened this issue Feb 13, 2025 · 4 comments · Fixed by #5527
Closed

[plsql] Parse error for operator in TRIM function call #5522

Ferada opened this issue Feb 13, 2025 · 4 comments · Fixed by #5527
Labels
a:bug PMD crashes or fails to analyse a file. in:grammar About the grammar of a lexer or parser, eg, a parse/lex exception
Milestone

Comments

@Ferada
Copy link

Ferada commented Feb 13, 2025

Affects PMD Version:

PMD 7.9.0 (10b47319e42bb817df69d29196ceca8fdb94b461, 2024-12-27T12:29:08Z)
Java version: 21.0.6, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64

Description:

A function call in a function definition fails to parse when there's a + operator as one, or the, argument. Presumably happens with any other operators as well.

The full example is https://github.com/Qualtagh/OracleDBUtils/blob/master/p_utils.9.sql#241.

Exception Stacktrace:

% pmd ast-dump --language=plsql -i <<EOF
function distinguishXML() return text is
begin
  return trim(x + y);
end;
/
EOF
Reading from stdin...
net.sourceforge.pmd.lang.ast.ParseException: Parse exception in file 'stdin' at line 3, column 17: Encountered "+".
Was expecting one of:
    ")" ...
    "||" ...
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.generateParseException(PLSQLParserImpl.java)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.jj_consume_token(PLSQLParserImpl.java)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.TrimExpression(PLSQLParserImpl.java:43175)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.FunctionCall(PLSQLParserImpl.java:15346)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.PrimaryPrefix(PLSQLParserImpl.java:46183)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.PrimaryExpression(PLSQLParserImpl.java:46123)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.IsOfTypeCondition(PLSQLParserImpl.java:45365)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.IsNullCondition(PLSQLParserImpl.java:44859)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.UnaryExpressionNotPlusMinus(PLSQLParserImpl.java:44422)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.UnaryExpression(PLSQLParserImpl.java:44252)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.MultiplicativeExpression(PLSQLParserImpl.java:43811)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.AdditiveExpression(PLSQLParserImpl.java:43697)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.RelationalExpression(PLSQLParserImpl.java:43457)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.EqualityExpression(PLSQLParserImpl.java:43387)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.ConditionalAndExpression(PLSQLParserImpl.java:43339)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.ConditionalOrExpression(PLSQLParserImpl.java:43291)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.Expression(PLSQLParserImpl.java:42378)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.ReturnStatement(PLSQLParserImpl.java:37798)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.UnlabelledStatement(PLSQLParserImpl.java:25003)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.Statement(PLSQLParserImpl.java:25818)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.ProgramUnit(PLSQLParserImpl.java:7823)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.Global(PLSQLParserImpl.java:871)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParserImpl.Input(PLSQLParserImpl.java:139)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.parseImpl(PLSQLParser.java:86)
        at net.sourceforge.pmd.lang.plsql.ast.PLSQLParser.parseImpl(PLSQLParser.java:21)
        at net.sourceforge.pmd.lang.ast.impl.javacc.JjtreeParserAdapter.parse(JjtreeParserAdapter.java:36)
        at net.sourceforge.pmd.util.treeexport.TreeExporter.run(TreeExporter.java:84)
        at net.sourceforge.pmd.util.treeexport.TreeExporter.export(TreeExporter.java:59)
        at net.sourceforge.pmd.cli.commands.internal.TreeExportCommand.execute(TreeExportCommand.java:111)
        at net.sourceforge.pmd.cli.commands.internal.AbstractPmdSubcommand.call(AbstractPmdSubcommand.java:30)
        at net.sourceforge.pmd.cli.commands.internal.AbstractPmdSubcommand.call(AbstractPmdSubcommand.java:16)
        at picocli.CommandLine.executeUserObject(CommandLine.java:2045)
        at picocli.CommandLine.access$1500(CommandLine.java:148)
        at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2465)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2457)
        at picocli.CommandLine$RunLast.handle(CommandLine.java:2419)
        at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2277)
        at picocli.CommandLine$RunLast.execute(CommandLine.java:2421)
        at picocli.CommandLine.execute(CommandLine.java:2174)
        at net.sourceforge.pmd.cli.PmdCli.main(PmdCli.java:24)

Code Sample demonstrating the issue:

function distinguishXML() return text is
begin
  return trim(x + y);
end;
/

Similarly, select trim(x + y) from foo; also fails with the same error, which looks like the same situation to me and should be valid?

Running PMD through: CLI

% java -version
openjdk version "21.0.6" 2025-01-21
OpenJDK Runtime Environment (build 21.0.6+7-Ubuntu-124.04.1)
OpenJDK 64-Bit Server VM (build 21.0.6+7-Ubuntu-124.04.1, mixed mode, sharing)
@Ferada Ferada added the a:bug PMD crashes or fails to analyse a file. label Feb 13, 2025
@adangel
Copy link
Member

adangel commented Feb 14, 2025

Hi @Ferada , thanks for reporting!

the current parser interprets TRIM as this TRIM function.

It seems, there is another TRIM function in PL/SQL, which is called TRIM Collection Method.

Is this correct?

I'll try to adjust the grammar to allow an arbitrary expression as a function argument. Unfortunately, the TRIM Collection Method is not clearly specified: in TRIM(n) n could be a literal or an expression.

Btw. I guess nt.TRIM; -- Trim last element would also fail, as the grammar currently expects parenthesis for function calls. Ok, just checked: There is no parsing error, but it is not parsed as a function call...

@adangel adangel changed the title [plsql] parse error for operator in function call [plsql] parse error for operator in TRIM function call Feb 14, 2025
adangel added a commit to adangel/pmd that referenced this issue Feb 14, 2025
@Ferada
Copy link
Author

Ferada commented Feb 19, 2025

It seems, there is another TRIM function in PL/SQL, which is called TRIM Collection Method.

Is this correct?

That looks like it to me. Which also makes my examples above wrong, because they'd be using the function call where no arbitrary expression is valid. So this issue should only apply to the collection method after all, didn't realise there's a difference.

I'll try to adjust the grammar to allow an arbitrary expression as a function argument. Unfortunately, the TRIM Collection Method is not clearly specified: in TRIM(n) n could be a literal or an expression.

Which makes sense, you'd want to be able to specify a fixed number or an expression?

Btw. I guess nt.TRIM; -- Trim last element would also fail, as the grammar currently expects parenthesis for function calls. Ok, just checked: There is no parsing error, but it is not parsed as a function call...

Yeah, sounds correct. What a pain that that's a function call.

@adangel adangel changed the title [plsql] parse error for operator in TRIM function call [plsql] Parse error for operator in TRIM function call Feb 20, 2025
@adangel
Copy link
Member

adangel commented Feb 20, 2025

Which also makes my examples above wrong

yes, the collection method calls must be qualified (https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/qualified-names-and-dot-notation.html), so the example should be more like:

function distinguishXML() return text is
begin
  collection_name.trim(x + y);
  return 'done';
end;
/

@adangel adangel modified the milestones: 7.11.0, 7.12.0 Feb 21, 2025
@adangel
Copy link
Member

adangel commented Feb 21, 2025

I tested it again now with the real thing (via docker from https://github.com/gvenzl/oci-oracle-free): a numeric expression seems to be valid for TRIM, e.g. this works fine in sqlplus:

docker exec -i oracle-test sqlplus -S system/changeit <<EOF
create or replace package p_utils is
function distinguishXML(x in number, y in number) return varchar;
end;
/
create or replace package body p_utils is
function distinguishXML(x in number, y in number) return varchar is
begin
  return trim(x + y);
end;

end;
/
SHOW ERRORS
SET SERVEROUTPUT ON
DECLARE
    BEGIN
        DBMS_OUTPUT.PUT_LINE(p_utils.distinguishXML(1, 2));
    END;
/
EOF

similarly, the following expressions in a select are all valid:

select 'X' || trim(leading 1 from '  test  ') || 'X' as col1,
       'X' || trim(leading ' ' from '  test  ') || 'X' as col2,
       'X' || trim(both ' ' from '  test  ') || 'X' as col3,
       'X' || trim(leading from '  test  ') || 'X' as col4,
       trim(1+2) as col5;

So, I'm going to adjust the grammar to allow this. Note, we currently require "from dual" for these selects, but this seems to be not needed anymore since Oracle 23 (see https://oracle-sql-features.github.io/guide/latest/versions/23.2/sql/select-without-from.html ).

adangel added a commit to adangel/pmd that referenced this issue Feb 24, 2025
adangel added a commit to adangel/pmd that referenced this issue Feb 24, 2025
adangel added a commit that referenced this issue Feb 25, 2025
Merge pull request #5527 from adangel:issue-5522-plsql-trim-function
@adangel adangel added the in:grammar About the grammar of a lexer or parser, eg, a parse/lex exception label Feb 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:bug PMD crashes or fails to analyse a file. in:grammar About the grammar of a lexer or parser, eg, a parse/lex exception
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants