質問

I try to write custom rule in sonar (plsql) by copy xpath rule. The task of this rule is to mark 'rollback to savepoint' statement where savepoint statement is missing.

For 2 savepoint and 3 rollback statements the AST (Abstract Syntax Tree) looks like:

<PROCEDURE_DEFINITION>
  ...
  <SAVEPOINT>
    <IDENTIFIER tokenValue="SAVEPOINT" />
    <IDENTIFIER tokenValue="spA" />
    <SEMICOLON tokenValue=";" />
  </SAVEPOINT>
  ...
  <SAVEPOINT>
    <IDENTIFIER tokenValue="SAVEPOINT" />
    <IDENTIFIER tokenValue="spB" />
    <SEMICOLON tokenValue=";" />
  </SAVEPOINT>
  ...
  <ROLLBACK>
    <IDENTIFIER tokenValue="ROLLBACK" />
    <TO />
    <IDENTIFIER tokenValue="SAVEPOINT" />
    <IDENTIFIER tokenValue="spB" />
    <SEMICOLON tokenValue=";" />
  </ROLLBACK>
  ...
  <ROLLBACK>
    <IDENTIFIER tokenValue="ROLLBACK" />
    <TO />
    <IDENTIFIER tokenValue="SAVEPOINT" />
    <IDENTIFIER tokenValue="spA" />
    <SEMICOLON tokenValue=";" />
  </ROLLBACK>
  ...
  <ROLLBACK>
    <IDENTIFIER tokenValue="ROLLBACK" />
    <TO />
    <IDENTIFIER tokenValue="SAVEPOINT" />
    <IDENTIFIER tokenValue="spX" />
    <SEMICOLON tokenValue=";" />
  </ROLLBACK>
  ...
</PROCEDURE_DEFINITION> 

I search for XPath query that marks last rollback because savepoint spX is missing. But this xpath marks last both rollbacks

//PROCEDURE_DEFINITION//ROLLBACK[
    IDENTIFIER[
        @tokenValue =
            ./ancestor::PROCEDURE_DEFINITION
                //SAVEPOINT/IDENTIFIER[2]/@tokenValue
    ]
]

Any suggestions?

EDIT:
I found this suboptimal solution:

//PROCEDURE_DEFINITION//ROLLBACK
[
  not(
    ./IDENTIFIER[3]/@tokenValue = 
    ancestor::PROCEDURE_DEFINITION//SAVEPOINT/IDENTIFIER[2]/@tokenValue
  )
]

PLSQL is case insensitive. But when i add translate function, i get marked first and last ROLLBACK node. I think all rollback's names will agreed with first savepoint's name?

役に立ちましたか?

解決

First of all, according to the AST you show, it seems to me that this is the PL/SQL code you want to run your XPath query on:

DECLARE
  PROCEDURE foo AS
  BEGIN
    SAVEPOINT spA;
    SAVEPOINT spB;

    ROLLBACK spB; -- Compliant
    ROLLBACK spA; -- Compliant

    ROLLBACK spX; -- Non-Compliant
  END;
BEGIN
  NULL;
END;
/

When I run your first XPath query using the SSLR PL/SQL Toolkit, the rollbacks to 'spB' and 'spA' are selected, but not the one to 'spX'.

Your second XPath query selects all of them.

It seems to me that you only want to select the one to 'spX', as there is no corresponding savepoint.

A trivial change to your first query allows to reverse the selected nodes, by negating the condition using not():

//PROCEDURE_DEFINITION//ROLLBACK[
    not(IDENTIFIER[
        @tokenValue =
            ./ancestor::PROCEDURE_DEFINITION
                //SAVEPOINT/IDENTIFIER[2]/@tokenValue
    ])
]

But I would actually recommend that you drop the PROCEDURE_DEFINITION part of the query, as SAVEPOINT and ROLLBACK statements are also valid within functions or anonymous blocks:

//ROLLBACK[not(IDENTIFIER[@tokenValue = //SAVEPOINT/IDENTIFIER[2]/@tokenValue])]
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top