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])]
Related
The #Value='1' Does not seem to be evaluating in this expression below as it returns both nodes of SEventData instead of only one that has a #Value of '1'. What am I missing?
Source:
<CData>
<SData SKey="006" >
<SEventData SEventOID="UNS" SEventRepeatKey="2">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED" ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="0" />
</ItemGroupData>
</FData>
</SEventData>
<SEventData SEventOID="UNS" SEventRepeatKey="3">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED" ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="1" />
</ItemGroupData>
</FData>
</SEventData>
</SData>
</CData>
with expression
//CData[.//SData[#SKey='006']/SEventData/FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1']]//SEventData
returns both instead of one
Element='<SEventData SEventOID="UNS" SEventRepeatKey="2">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED"
ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="0"/>
</ItemGroupData>
</FData>
</SEventData>'
Element='<SEventData SEventOID="UNS" SEventRepeatKey="3">
<FData FOID="REQUIRED" FRepeatKey="1">
<ItemGroupData ItemGroupOID="REQUIRED"
ItemGroupRepeatKey="0"
TransactionType="Upsert">
<ItemData ItemOID="REQ" Value="1"/>
</ItemGroupData>
</FData>
</SEventData>'
You can use this XPath in order to locate what you are looking for:
//SEventData[.//FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1']]
Your current XPath expression returns the root node //CData containing in it the following condition: .//SData[#SKey='006']/SEventData/FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1'].
So yes, //CData has inside it the condition as above and when you trying to locate //SEventData inside that //CData it returns you both //SEventData nodes.
What you should do here is to locate //SEventData node itself based on your condition as I wrote at the beginning:
//SEventData[.//FData/ItemGroupData/ItemData[#ItemOID='REQ' and #Value='1']]
I'm trying to get the value of SERepeatKey if ItemOID REQUIRED.REQ_V has a value of "1".
In the below case I want to return the value 2.
Is this possible with this XML? If so how?
With this I was able to do it if there was only 1 "Data" node but now with 2 I am at a loss. In XPath tester I get the below error message.
string(ODM/Data/SData[#SKey='003-003' and SiteRef[#LOID='SE 003']]/SEData[#SEOID='UNSCHEDULED']/#SERepeatKey)
"Unable to perform XPath operation. A sequence of more than one item is not allowed as the first argument of string() (#SERepeatKey, #SERepeatKey)"
<ODM>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="1">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="0" />
</IGData>
</FData>
</SEData>
</SData>
</Data>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="2">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="1" />
</IGData>
</FData>
</SEData>
</SData>
</Data>
<Data SOID="(DEV)" MetaDataVersionOID="" >
<SData SKey="003-003" >
<SiteRef LOID="SE 003"/>
<SEData SEOID="UNSCHEDULED" SERepeatKey="3">
<FData FOID="REQUIRED" FormRepeatKey="1">
<IGData IGOID="REQUIRED" IGRepeatKey="0" TransactionType="Upsert">
<IData ItemOID="REQUIRED.REQ_V" Value="1" />
</IGData>
</FData>
</SEData>
</SData>
This XPath should do what you are looking for:
//Data[.//IData[#ItemOID='REQUIRED.REQ_V' and #Value='1']]//SEData/#SERepeatKey
According to the presented XML looks like you can even omit #ItemOID='REQUIRED.REQ_V' and make this expression simpler
//Data[.//IData[#Value='1']]//SEData/#SERepeatKey
I am getting difficulties while invoking database thru bpel, it is not returning any output, but while testing execute in sqlplus, it is returning value. kindly please your advise and suggestion on this .. thank you
thru sqlpus :
SQL> SELECT DRSHEET_CNOTE_NO, CITY_NAME, MRSHEET_DATE, POD_STATUS FROM TABLE(RUNSHEET_A('123'));
DRSHEET_CNOTE_NO CITY_NAME MRSHEET_D POD_STATUS
---------------- -------------------- --------- ------------------------------
123 TANGERANG 06-JUL-15 MISSING
thru bpel :
<?xml version="1.0" encoding="UTF-8"?><messages>
<Invoke1_dbRunsheet_A_InputVariable>
<part xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="dbRunsheet_AInput_msg">
<dbRunsheet_AInput xmlns="http://xmlns.oracle.com/pcbpel/adapter/db/dbRunsheet_A">
<cnoteno>123</cnoteno>
</dbRunsheet_AInput>
</part>
</Invoke1_dbRunsheet_A_InputVariable>
<Invoke1_dbRunsheet_A_OutputVariable>
<part xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="dbRunsheet_AOutputCollection">
<dbRunsheet_AOutputCollection xmlns="http://xmlns.oracle.com/pcbpel/adapter/db/dbRunsheet_A"/>
</part>
</Invoke1_dbRunsheet_A_OutputVariable>
</messages>
dbadapter configuration:
<adapter-config name="dbRunsheet_A" adapter="db" wsdlLocation="../WSDLs/dbRunsheet_A.wsdl"
xmlns="http://platform.integration.oracle/blocks/adapter/fw/metadata">
<connection-factory UIConnectionName="JNE-DB" location="eis/DB/jne"/>
<endpoint-interaction portType="dbRunsheet_A_ptt" operation="dbRunsheet_A">
<interaction-spec className="oracle.tip.adapter.db.DBPureSQLInteractionSpec">
<property name="SqlString" value="SELECT DRSHEET_CNOTE_NO, CITY_NAME, MRSHEET_DATE,
POD_STATUS FROM TABLE(RUNSHEET_A(#cnoteno))"/>
<property name="GetActiveUnitOfWork" value="false"/>
</interaction-spec>
</endpoint-interaction>
</adapter-config>
Use SCHEMA_NAME.TABLE_NAME in the query.
No matter what I have tried, I was unsuccessful in getting the Advanced Find feature of MS CRM 2015 online to show me Active Accounts that are of type Branch that have as their parent have an Account type again of Branch.
I have checked and re-checked the data but perhaps there is something wrong with my query in the Advanced Find feature.
Or there is a bug to it.
I have run this query in SQL as well, we have a BigData db that holds our CRM data and there it reveals the correct results (of course).
Here is my query so that you can see:
--BRANCH OF A BRANCH
select [dbo].[fn_getDescFromCRMguid](a.[Parentaccountid]) as [ParentAccountName],
--[fn_getDescFromCRMguid] udf is just a look-up for descriptions and names
( select left(a3.[etf_accountlevel],6)
from [Stg_CRMAccount] a3
where a3.[accountid] = left(a.[parentaccountid],36)
) as [ParentAccountLevel],
[dbo].[fn_getDescFromCRMguid](isnull(a.[owninguser], a.[owningteam])) as [OwningEntity],
a.*
from [Stg_CRMAccount] a
where a.[statuscode] = 'Active::1'
and a.[etf_accountlevel] like 'Branch%'
and a.[Parentaccountid] is not null
and exists (
select 0
from [Stg_CRMAccount] a2
where a2.[statuscode] = 'Active::1'
and a2.[etf_accountlevel] like 'Branch%'
and left(a.[Parentaccountid],36) = a2.[accountid]
)
order by a.[Parentaccountid],
a.[name],
a.[address1_city];
I am also attaching the screenshot of my Advanced Find query and please feel free to comment or let me know of any useful thoughts.
I hope some person has any idea about this because to me it is puzzling.
I have navigated into the resulting Accounts from this and then into their parent Account and it was not a Branch.
Despite the clear (at least to me) specification of the Where clause under the use of the related Entity - Account, using the relation Parent Account.
The plot thickens even more, if you remove the Account Type = Branch for the related Entity and say change the Status = Active to Inactive then it will very correctly find and show only those Branches where their Parent is Inactive.
That leads me to suspect some kind of a recursive error with the query builder they are using.
It finds Account Type = Branch twice and erroneously does not differentiate between the first occurrence which is for the outer selection and the second occurrence which would be for the nested (in the Where clause) selection.
But all that is mere speculation.
I don't really know why it can't handle it.
It begs the question in what other scenarios it can mess up recursive query builds.
Your thoughts?
and here is my fetch XML from the Advanced Find query
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="account">
<attribute name="etf_rating" />
<attribute name="parentaccountid" />
<attribute name="etf_lastcontact" />
<attribute name="etf_city" />
<attribute name="address1_line1" />
<attribute name="etf_accountlevel" />
<attribute name="name" />
<attribute name="ownerid" />
<attribute name="etf_segment" />
<attribute name="accountid" />
<order attribute="name" descending="false" />
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="etf_accountlevel" operator="eq" value="964850002" />
</filter>
<link-entity name="account" from="parentaccountid" to="accountid" alias="ag">
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="etf_accountlevel" operator="eq" value="964850002" />
</filter>
</link-entity>
</entity>
</fetch>
I have an xml like the following:
<table1>
<row>
<person>person1</person>
<value>10</value>
</row>
<row>
<person>person2</person>
<value>20</value>
</row>
<row>
<person>person1</person>
<value>5</value>
</row>
</table1>
<summaryTable>
<row>
<person>person1</person>
<value_total/>
</row>
<row>
<person>person2</person>
<value_total/>
</row>
</summaryTable>
With XForms 1 (there is no option to switch to XForms 2), using framework betterform, I want to calculate the values in the summary table, by doing the SUM of the rows in 'table1' that have the same person name. To do that I have the following binds:
<xf:bind id="bind_table1"
nodeset="table1" repeatableElement="row">
<xf:bind id="bind_head_table1" nodeset="head" />
<xf:bind id="bind_row_table1" nodeset="row">
<xf:bind id="bind_person" nodeset="person" type="xf:string" />
<xf:bind id="bind_value" nodeset="value" type="xf:integer" />
</xf:bind>
</xf:bind>
<xf:bind id="bind_summaryTable"
nodeset="summaryTable"
repeatableElement="row">
<xf:bind id="bind_head_summaryTable" nodeset="head" />
<xf:bind id="bind_row_summaryTable" nodeset="row">
<xf:bind id="bind_person_name" nodeset="person_name" type="xf:string" readonly="true"/>
<xf:bind id="bind_value_total" nodeset="value_total" type="xf:integer" readonly="true" calculate="SUM(//table1/row[person/text() = ../person_name/text()]/value)"/>
</xf:bind>
</xf:bind>
What I want to have at the end is the value_total for person1 = 15 and value_total for person2 = 20, but using this 'calculate' expression I'm getting 'NaN'. If I replace the calculate expression to compare with a literal String like:
<xf:bind id="bind_value_total" nodeset="value_total" type="xf:integer" readonly="true" calculate="SUM(//table1/row[person/text() = 'person1']/value)"/>
then I get as value_total 15 (the sum is correctly done). So it seems that the error is in the comparison expression person/text() = ../person_name/text() . Does someone have an idea about how should be the correct expression?
Thanks
Try the context() function in the calculate attribute to refer to the current node, like this:
<xf:bind nodeset="summaryTable/row/value_total" calculate="sum(//table1/row[person/text() = context()/../person/text()]/value)"/>
The context function gives you the current context node. If your bind references a nodeset with multiple nodes, it will be evaluated one time for every node, and that node is what context() returns.
It works for me with XSLTForms, maybe your version of betterForm supports it.