giggty
6th March 2018, 08:59
Hello,
so I'm trying to do something like this:
select tisfc010.opno
from tisfc010 for update
where tisfc010._index1 = {:tisfc001.pdno}
order by tisfc010.opno
selectdo
db.retry.point()
if some.condition > 0 then
if not dal.change.object("tisfc010") then
dal.set.field(...)
if dal.save.object("tisfc010") <> 0 then
show.dal.messages()
endif
endif
else
if dal.destroy.object("tisfc010") <> 0 then
show.dal.messages()
endif
endif
commit.transaction()
endselect
The problem is it doesn't work correctly when an update happens after the previous record was deleted: "Record [pdno, opno] cannot be saved in table Production Order Operations in company _compnr. Record is not locked." What would be the correct approach here?
hklett
6th March 2018, 13:23
Put the retry Point before the select and not inside.
giggty
6th March 2018, 13:31
I did some additional testing and it seems the update error arises 100% consistently when deletion happens first (e. g. records 1-3 was deleted and 4th is being updated).
I have found two workarounds:
1. Move db.retry.point() before select statement and use "order by with retry" hint, so when an update hiccup occurs the record is fetched anew (and the second time it works).
2. Move commit.transaction() after select statement, so updates/deletions are commited in one batch.
Still I would like to know where the problem is in the original code and what technique one should adhere to in such cases.
giggty
6th March 2018, 13:37
Put the retry Point before the select and not inside.
Thanks hklett, seems like it never should be put inside select (correct me if there are exceptions). But still, why am i hitting a retry point here?
hklett
6th March 2018, 14:23
The retry Point should always set autside of the query.
I think your update will run in an error, because you do not query all fields of this table.
Because LN do not update only one field but allways all fields of a record, you should always use
select tisfc010.*.
Otherwise the content of the other fields are undefinede,,
Also it is important that you abort a transaction , if an update on a table failes:
if some.condition > 0 then
if not dal.change.object("tisfc010") then
dal.set.field(...)
if dal.save.object("tisfc010") <> 0 then
abort.transaction()
show.dal.messages()
else
commit.transaction()
endif
endif
else
if dal.destroy.object("tisfc010") <> 0 then
abort.transaction()
show.dal.messages()
else
commit.transaction()
endif
endif
giggty
6th March 2018, 15:15
Thank you for your comments hklett. I tried selecting tisfc010.*, but it didn't help.
hklett
6th March 2018, 16:17
Can you pleae send the whole Code of your update function?
giggty
7th March 2018, 07:28
Here it is:
function long get.production.orders(long ops.num.selected,
ref long marked.ops())
{
select tisfc001.pdno
from tisfc001
where tisfc001.grid = :tisfc350.grid
selectdo
process.ops(dal.mode.set, marked.ops)
endselect
return(0)
}
function void process.ops(ref long marked.ops())
{
string msg.code(14), msg.text(132) mb
long search_def(1, 4)
qss.start(search_def, 1, 1)
qss.way(search_def, 1, QSS.UP)
qss.type(search_def, 1, DB.LONG)
db.retry.point()
select tisfc010.*
from tisfc010 for update
where tisfc010._index1 = {:tisfc001.pdno}
order by tisfc010.opno with retry
selectdo
if qss.search(QSS.SRC.IS.SORTED + QSS.EQUAL, tisfc010.opno, marked.ops, search_def) > 0 then
if not dal.change.object("tisfc010") then
dal.set.field("tisfc010.copo", tcyesno.yes)
if dal.save.object("tisfc010") <> 0 then
while dal.get.last.message(MSG.ERROR, msg.code, msg.text)
print.update.error.msg(tisfc010.opno, msg.code, msg.text)
endwhile
abort.transaction()
else
commit.transaction()
endif
endif
else
if dal.destroy.object("tisfc010") <> 0 then
while dal.get.last.message(MSG.ERROR, msg.code, msg.text)
print.delete.error.msg(tisfc010.opno, msg.code, msg.text)
endwhile
abort.transaction()
else
commit.transaction()
endif
endif
endselect
}
marked.ops is an array of operation numbers that need to be updated. All other operations in the production order should be deleted.
hklett
7th March 2018, 12:51
What is the message from the DAL?
Maybee the modification of the record is forbidden because of the status of the operation?
bhushanchanda
7th March 2018, 13:54
The problem could be that the standard DAL is not letting you update/delete the record due to some conditions as hklett rightly said.
Other problem could be, the DAL is expecting some DLL call before handling updates to the table like SFC parameter reading. This may be because of the problem with underlying standard code. You could give a shot to reading tisfc000 table prior to performing updates.
giggty
20th March 2018, 10:26
Ok, sorry, I was on vacation :)
Let me clear it up. I can do updates and deletes on tisfc010. The problem I am facing when doing this though is the following (and which is 100% reproducable):
1. For a given production order delete the first operation - no probs
2. Commit transaction - no probs
3. Then try to update the second operation (they are being processed sequentially) for the same order - it jumps from dal.change.object("tisfc010") to db.retry.point()
4. After that select gets executed again and the second operation gets updated successfully.
So, the question is why I am (even) hitting db.retry.point() here :confused:
vahdani
20th March 2018, 11:06
Hi,
the reason is that when changing or deleting an operation the previous and next operations are also changed in DAL by calling on of the following:
tisfc.dll0224.update.operation.backward(...)
tisfc.dll0224.update.operation.forward(...)
This causes the return to db.retry.point() as the already selected records for update are changed!
I recommend using two selects. First one to select the operations and the secound one to update/delete the actually selected operation:
domain tcopno this.opno
select tisfc010.opno:this.opno
from tisfc010
where tisfc010._index1 = {:tisfc001.pdno}
order by tisfc010.opno
selectdo
db.retry.point()
select tisfc010.*
from tisfc010 for update
where tisfc010._index1 = {:tisfc001.pdno, :this.opno}
selectdo
if qss.search(QSS.SRC.IS.SORTED + QSS.EQUAL, tisfc010.opno, marked.ops, search_def) > 0 then
if not dal.change.object("tisfc010") then
dal.set.field("tisfc010.copo", tcyesno.yes)
if dal.save.object("tisfc010") <> 0 then
while dal.get.last.message(MSG.ERROR, msg.code, msg.text)
print.update.error.msg(tisfc010.opno, msg.code, msg.text)
endwhile
abort.transaction()
else
commit.transaction()
endif
endif
else
if dal.destroy.object("tisfc010") <> 0 then
while dal.get.last.message(MSG.ERROR, msg.code, msg.text)
print.delete.error.msg(tisfc010.opno, msg.code, msg.text)
endwhile
abort.transaction()
else
commit.transaction()
endif
endif
endselect
endselect
giggty
20th March 2018, 16:01
vahdani, thank you for clarification!
I agree, it would totally make sense, but seems like the following senario (i tested it) contradicts your point:
1. update 1st operation and commit
2. delete 2nd operation and commit
3. update 3rd operation and commit - no retry point hit here!
4. proceed updating the rest of operations
So the case with deleting the first record and updating the second seems to be somewhat unique...
As a side-question, before doing updates/deletes on tisfc010 I need to call DAL method "set.dal.mode.production.planning" which sets the global variable gl.calling.context to CALLER_PRODUCTION_PLANNING and therefore permits changes on the table. But there are three other methods (set.calling.context.add.explode.phantom, set.calling.context.production.order.creation, set.dal.mode.report.complete) which also set gl.calling.context. What is the difference between them and which one should I use (I only tested set.calling.context.production.order.creation and it works just like set.dal.mode.production.planning)?
vahdani
21st March 2018, 16:53
Hi,
as I see you only update the field "cout point" when you update. This is apparantly not a big change like changing quantities etc. so DAL does not change the subsequent operations and therefore there is no jump to the db.retry.point(). But when you delete an operation this definitely does cause a change of the subsequent operations and therefore the jump to db.retry.point() that you observe :rolleyes:
giggty
22nd March 2018, 10:59
vahdani, eh, not really. When I delete the second operation (the first one having been updated) it does not jump to retry point :(
I tested it with other 3 gl.calling.context values. set.dal.mode.production.planning, set.calling.context.add.explode.phantom, set.calling.context.production.order.creation exhibit the same behavior, set.dal.mode.report.complete allows modification only for orders with status "active".