Spring Batch Paging Issue - spring

I am working on Spring Batch and I am using paging for fetching data from DB. for the first time Its firing Query as expected but for second page its adding one more unexpected parameter. I don't understand why.
My Query in XML file is
<bean id="summaryAppReader" scope="step" autowire-candidate="false"
class="org.springframework.batch.item.database.JdbcPagingItemReader">
<property name="dataSource" ref="dataSource" />
<property name="rowMapper">
<bean class="com.majesco.nyl.batch.mapper.SummaryApplicationRowMapper" />
</property>
<property name="queryProvider">
<bean
class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="fromClause" value="VIEW_SUMMARY_APPLICATION" />
<property name="selectClause"
value="application_id, upper(application_status) as application_status,relationship_code, create_date,submission_date,transmission_date,TRANSMISSION_STATUS,tpa_notes,site_details_id,transaction_num,PROCESS_STATUS,process_date,application_status_date,first_name,middle_name,last_name,suffix,prefix,APPROVED_REJECTED_DATE,action_by,ass_acronym,user_name,applicant_name,site_name,ASSOCIATION_ID, (TO_DATE('#{jobParameters['runDate']}', 'yyyy-mm-dd') - trunc(create_date)) as elapsedDays" />
<property name="sortKeys">
<map>
<entry key="transaction_num" value="ASCENDING" />
</map>
</property>
<property name="whereClause"
value="(upper(application_status)='PENDING' OR (upper(application_status) IN ('APPROVED','DECLINED') AND trunc(application_status_date) = TO_DATE('#{jobParameters['runDate']}', 'yyyy-mm-dd'))) and TRANSACTION_NUM >= :minId and TRANSACTION_NUM <= :maxId" />
</bean>
</property>
<property name="parameterValues">
<map>
<entry key="minId" value="#{stepExecutionContext[minValue]}" />
<entry key="maxId" value="#{stepExecutionContext[maxValue]}" />
</map>
</property>
</bean>
for fetching data for first page its firing query something like this and its expected
Reading page 0
SQL used for reading first page: [SELECT * FROM (SELECT application_id, upper(application_status) as application_status,relationship_code, create_date,submission_date,transmission_date,TRANSMISSION_STATUS,tpa_notes,site_details_id,transaction_num,PROCESS_STATUS,process_date,application_status_date,first_name,middle_name,last_name,suffix,prefix,APPROVED_REJECTED_DATE,action_by,ass_acronym,user_name,applicant_name,site_name,ASSOCIATION_ID, (TO_DATE('2016-06-29', 'yyyy-mm-dd') - trunc(create_date)) as elapsedDays FROM VIEW_SUMMARY_APPLICATION WHERE (upper(application_status)='PENDING' OR (upper(application_status) IN ('APPROVED','DECLINED') AND trunc(application_status_date) = TO_DATE('2016-06-29', 'yyyy-mm-dd'))) and TRANSACTION_NUM >= :minId and TRANSACTION_NUM <= :maxId ORDER BY transaction_num ASC) WHERE ROWNUM <= 10]
Using parameterMap:{minId=100000002630, maxId=100000002663}
But for the second page its adding one more parameter in Query _TRANSACTION_NUM which is unexpected like
Reading page 1
SQL used for reading remaining pages: [SELECT * FROM (SELECT application_id, upper(appication_status) as application_status,relationship_code, create_date,submission_date,transmission_date,TRANSMISSION_STATUS,tpa_notes,site_details_id,transaction_num,PROCESS_STATUS,process_date,application_status_date,first_name,middle_name,last_name,suffix,prefix,APPROVED_REJECTED_DATE,action_by,ass_acronym,user_name,applicant_name,site_name,ASSOCIATION_ID, (TO_DATE('2016-06-29', 'yyyy-mm-dd') - trunc(create_date)) as elapsedDays FROM VIEW_SUMMARY_APPLICATION WHERE (upper(application_status)='PENDING' OR (upper(application_status) IN ('APPROVED','DECLINED') AND trunc(application_status_date) = TO_DATE('2016-06-29', 'yyyy-mm-dd'))) and TRANSACTION_NUM >= :minId and TRANSACTION_NUM <= :maxId ORDER BY transaction_num ASC) WHERE ROWNUM <= 10 AND ((transaction_num > :_transaction_num))]
Using parameterMap:{minId=100000002596, maxId=100000002629, _transaction_num=100000002622}
FYI. TRANSACTION_NUM is not unique.

It's due to your sortKeys. You defined the following:
<property name="sortKeys">
<map>
<entry key="transaction_num" value="ASCENDING" />
</map>
</property>
Spring Batch is using the highest transaction_num from page 0 and saying the next page must have a transaction_num higher than that.
The framework will increment the bind variable with each page to ensure you keep getting unique results. The problem here is that you realistically need a Primary Key to page correctly otherwise your pageSize (default = 10 and seen where it adds WHERE ROWNUM <= 10 to your query) will cut off some of your records.

Related

Can i use complex condition using XPath in Filter Mediator WSO2?

I have a condition written in SQL Language that i would like to use it in Filter Mediator XPath but it didn't work and it give me an error .
NB : I got variable value from JSON payload .
Actual SQL Condition
(!ISNULL(a) && a== 2 && b== 1) || c== 5
Expected XPath Condition
(//a=2 AND //b=1) OR //c=5
Try the following.
<filter xpath="boolean(//a/text() = '1' and //b/text() = '2') or //c/text() = '3'">
<then>
<log>
<property value="===== TRUE" name="MSG"/>
</log>
</then>
<else>
<log>
<property value="===== FALSE" name="MSG"/>
</log>
</else>
</filter>

XPath Param Value Is Not Evaluating In Expression

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']]

XPATH to get multiple values

<values>
<value index="1">
<token>
<secret>
<client_key>
</value>
<value index="2">
<token>
<secret>
<client_key>
</value>
<value index="3">
<token>
<secret>
<client_key>
</value>
</values>
Can anyone please help me with the xpath to get the token value from all the indexes . The no of indexes will vary each time and not a constant.possible values are (1 or >1)
Searches for tokens inside values that has attribute index
//value[#index]/token

How to read complex input pattern using SPring Batch

I have a situation where it is require to parse complex flat file, each record scatter to multiple lines as shown below.
BFT ICVMORDR1400210IJ5 *P*
00800RRJNZM 1EK19 1EL ***** 101
00800RRJNZM ******************* 5 201
00800RRJNZM ******************* 5 202
00800RRJNZM ******************* 5 203
00800RRJNZM ******************* 5 204
00800RRJNZM ******************* 5 205
00800RRJNZM ****************** 5 206
00800RRJNZM ****************** 5 301
00800RRJNZM ****************** 5 302
00800RRJNZM ****************** 59401
I have header line for file, and detailed record was scatters to 4 different types of records like 100,200,300,400 series at the end. How to parse this complex using Spring Batch.
to read one line as records - you can use below configuration in ur xml file --
<bean id="customlineTokenizer"
class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
<property name="columns" value="1-5,6-10" />
<property name="names" value="firstname,lastname" />
</bean>
<bean id="customFieldSetMapper" class="com.mkyong.model.ReportFieldSetMapper" />
<bean id="cvsFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="strict" value="false" />
<property name="resource" value="classpath:report1" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer" ref="customlineTokenizer" />
<property name="fieldSetMapper" ref="customFieldSetMapper" >
</property>
</bean>
</property>
</bean>

XPath-1.0: mark node where opposite node is missing

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])]

Resources