ACCEPT/REJECT : does they influence the NISNHQ value?

Natural 8

product with a customer license

I tried a READ loop with ACCEPT clause , and an UPDATE. I used ACCEPT instead of IF … END-IF .
I tried ACCEPT with the intention of minimizing the amount of records in lock. Something like this:

RD1. READ MY-VIEW WITH DESC-FIELD-1 GE #INI-SCOPE
  ACCEPT IF INI-DATE GE 20220412
        AND INI-DATE LE 20220416
        AND CONTROL-BUSINESS-FIELD-1 EQ 1
  MOVE *COUNTER TO #AMOUNT-READ
  MOVE 1 TO CONTROL-BUSINESS-FIELD-8
  UPDATE (RD1.)
  END TRANSACTION
  ADD 1 TO #AMOUNT-UPDATED
END-READ
/* JUST AN EXAMPLE...

I got Error 3047 on using ACCEPT.

So I’d like to understand the influence of ACCEPT on the amount of locked records in a READ loop.

installed latest fixes for the products? YES

Thanks in advance!

1 Like

ACCEPT has NO influence on the number of records placed on hold. It controls only whether the record will be processed by the logic in the loop.

Records are placed on hold because there is an UPDATE referring to the READ, so all records read will be in hold status.

As a general rule, avoid ACCEPT, REJECT, WHERE, and ESCAPE TOP when holding records. A record is in hold from the moment read until the END TRANSACTION is executed.

2 Likes

RI profile parameter

Use profile parameter RI=ON to release records from hold that are rejected via WHERE or ACCEPT/REJECT statements.

Or use a GET to only put selected records on hold. Instead of UPDATE (RD1.), use:
MY-GET. GET MY-VIEW *ISN (RD1.)
UPDATE (MY-GET.)

In terms of performance, you will do an Adabas call (RI) for every record to be released if you just use RI=ON. If you use the GET approach, you will do an Adabas call (L4) for each record to be updated. Either call will not use a lot of resources (the L4 will very likely just read the record from the buffer pool), so which to use will be a matter of how many records will be updated vs how many are read.

Incidentally, your #AMOUNT-READ will be incorrect unless the last record read is updated. if you reference *COUNTER (RD1.) after the END-READ, it will have the number of records read. Or, if you need #AMOUNT-READ for some reason, put the MOVE *COUNTER before the ACCEPT statement.

2 Likes

I didn’t want to hold all records - only the accepted. Noted.
One doubt: If I do END TRANSACTION on each record, the amount of locks is gradually decreasing?

This seems to be a good aproach for my case. This parameter is included in JCL job?

I do MOVE then UPDATE(RD1). But using GET, where do I place the MOVE?

Can I assume that ACCEPT has exactly the same effect of IF … END-IF in this situation?

Yes, you can supply the RI=ON from your Natural dynamic parameters (PARM=‘RI=ON’) or in your Natural parameters or profile (contact your sysadmin if you’re not clear on how to do this)

RD1. READ MY-VIEW WITH DESC-FIELD-1 GE #INI-SCOPE
  ACCEPT IF INI-DATE GE 20220412
        AND INI-DATE LE 20220416
        AND CONTROL-BUSINESS-FIELD-1 EQ 1
  MOVE 1 TO CONTROL-BUSINESS-FIELD-8
  MY-GET. GET MY-VIEW *ISN(RD1.)
  UPDATE (MY-GET.)
  END TRANSACTION
  ADD 1 TO #AMOUNT-UPDATED
END-READ
MOVE *COUNTER (RD1.) TO #AMOUNT-READ

With either the RI=ON or GET approach above, you will have at most 1 record on hold at a time since you are using a READ statement. A FIND statement can put all selected records (meeting WITH criteria) on hold at once, but a READ only puts the record on hold when read.

1 Like

I thinked I couldn’t use *COUNTER outside the related loop

Please note there’s a difference whether you have

READ MY-VIEW WITH DESC-FIELD-1 STARTING FROM #START ENDING AT #END

or

READ MY-VIEW WITH DESC-FIELD-1 STARTING FROM #START TO #END

In the first case only the #START value will be sent to the database and any selection will be handled by NATURAL once a record has been read.

However, in the second case both the #START and #END values will be sent to ADABAS and thus the database will handle the selection and only return selected records to NATURAL.

So if possible tighten your READ criteria to limit the number of records that hit NATURAL in the first place, and thus reduce the number of records put in hold.

In your example you don’t even have an upper limit so the number of records hitting ACCEPT most likely is even higher than it would need to be anyway.

2 Likes

Hi Tomas,

Just my 2 cents worth, and attempt to answer some of your ancillary questions that may not have been addressed.

Not exactly, if I understand your question. When an END TRANSACTION statement is executed, any updates to records on hold are committed to the database and all held records are released. So the number of “locks” is immediately reduced to zero. In your original example, the “locks” count would start increasing again for every new record read until one meets the update criteria and it is updated and ET’ed. However, with the GET method shown by Douglas, (my preference too) the number of held records is never more than 1 at a time, so the “locks” count is never > 1. A more advanced, slightly more efficient method would be to use an #ET-COUNTER you increment for each record you GET and UPDATE, and then only issue an ET when #ET-COUNTER > 50, and then reset #ET-COUNTER. You also have to add an ET after the END-READ, just in case. It’s only worth doing this if you are updating lots of records.

Since the GET rereads the record into the VIEW buffer, you should put the MOVE for any fields to be updated after the GET and before the UPDATE. If MOVE is before the GET, the values will just be overlaid with the original values.

That depends on the IF … END-IF, I guess and this exact coding. You can mimic the logic of ACCEPT with an IF … END-IF for most situations by adding an IGNORE ELSE ESCAPE TOP to the IF, for example:

RD1. READ MY-VIEW WITH DESC-FIELD-1 GE #INI-SCOPE
IF INI-DATE GE 20220412
AND INI-DATE LE 20220416
AND CONTROL-BUSINESS-FIELD-1 EQ 1
IGNORE /* Accept and process record
ELSE
ESCAPE TOP /* Reject record
END-IF
MY-GET. GET MY-VIEW *ISN(RD1.)
MOVE 1 TO CONTROL-BUSINESS-FIELD-8
UPDATE (MY-GET.)
END TRANSACTION
ADD 1 TO #AMOUNT-UPDATED
END-READ
MOVE *COUNTER (RD1.) TO #AMOUNT-READ

Yes the value of *COUNTER is available outside the loop. But always best to qualify with the READ label, *COUNTER (RD1), in case there are multiple Reads so Natural doesn’t get confused which *COUNTER you are referring to.

Great tip from Wolfgang, always a good idea to set an exit criteria of some kind for READ loops, either with an ENDING AT #END-KEY or TO #END-KEY, or you could put an IF test … ESCAPE BOTTOM (RD1.) END-IF before the ACCEPT statement. Unless you know the data and you will always have to read to the end of the descriptor from your starting point #INI-SCOPE to find all records that need to be updated.

Hope that helps more than confuses…
Good luck,
George

2 Likes

Good job of filling in the gaps, George. :wink:

Tomas,

Let’s consider a file of 1 million records.

If you are certain to be updating (almost) every record, then a few RI commands for the rejections would add little overhead, but 1,000,000 GETs would not be justified. (Why retrieve a record you already have?)

If you are certain that very few records will be updated, then a few GETs will add little overhead, but 1,000,000 RI commands would not be justified.

As a rule, I don’t like to issue Adabas commands that are unnecessary. I consider the RI and GET commands to be unnecessary overhead. Here is a program structure for updating a moderate number of records.

RD1. READ MY-VIEW WITH DESC-FIELD-1 GE #INI-SCOPE
  ADD 1 TO #COUNT
  IF   INI-DATE                 GE 20220412
   AND INI-DATE                 LE 20220416
   AND CONTROL-BUSINESS-FIELD-1 EQ 1
    THEN
      MOVE *COUNTER TO #AMOUNT-READ
      MOVE 1 TO CONTROL-BUSINESS-FIELD-8
      UPDATE (RD1.)
      ADD 1 TO #AMOUNT-UPDATED
      ADD 1 TO #ET
  END-IF
  IF  #COUNT > 500
   OR #ET    > 50
    THEN
      END TRANSACTION
      RESET #COUNT
            #ET
  END-IF
END-READ
END TRANSACTION
END

If you decide to use GETs, consider applying Multi-fetch to reduce the physical READ command count.

2 Likes

What a class! Amazing! I appreciate it!

buenas tardes como puedo leer dos work file en Natural de forma secencial

Please open a new thread for this topic.
Google translate: Por favor, abre un nuevo hilo para este tema.