My code is more or less like the following:
define rec record like t.*
define f like t.f
prepare upd_cur from "select * from t for update"
prepare upd_stmt from "update t set f = ? where current of upd_cur"
foreach upd_cur into rec.*
let f = rec.f
# ... code here may change the value of f ...
if (f != rec.f)
execute upd_stmt using f where current of upd_cur
end if
end foreach
On the first iteration through the FOREACH loop, on the UPDATE ... WHERE CURRENT statement, the result is:
status -6372 (General SQL error, check SQLCA.SQLERRD[2].)
sqlcode -6732
sqlerrd[2] -16916 (SQL Server Error: "A cursor with the name '%.*ls' does not exist.")
On the second iteration, the following line yields an error:
let f = r.f
The error is:
sqlca.sqlcode -400 (Fetch attempted on unopen cursor.)
After this, our actual program entered an infinite loop. I don't want to re-run that scenario (in order not to wind up with another runaway process on our server), so unfortunately I can't report any further details about the infinite loop.
As a workaround, I tried changing the update statement to use the current record's primary key rather than "WHERE CURRENT OF":
prepare upd_stmt from "update t set f = ? where t.key = ?"
foreach upd_cur into rec.*
...
if (f != rec.f)
execute upd_stmt using f, t.key
end if
end foreach
This appears to work fine.
However, my team is cautious. They've never previously used FOR UPDATE cursors in a FOREACH statement. They're concerned that FOREACH might have other unexpected behavior when used with a FOR UPDATE cursor. Consequently, they prefer that I use an ordinary SELECT cursor, and explicitly lock/unlock records inside the FOREACH loop.
I googled this a bit, and found a few very old threads referring to Informix bug 31661, which also involves a cursor not found error. In the following thread, Jonathan Leffler of Informix explained that the problem had to do with name mangling by the compiler. His recommended workaround was to use the CURSOR_NAME() function to get the mangled name of the cursor.
https://groups.google.com/forum/#!topic/comp.databases.informix/-aBoIYsDVzEGiven that Leffler's recommendation is 20 years old, it may no longer be relevant. In addition, I'm not sure how the 4Js product relates to the Informix product. I assume there is a shared history, but am not sure.
I'd like to just test the CURSOR_NAME() function and see if it works, but there is no such function in the 4Js product.
What approach would you recommend?
Can we safely use a FOR UPDATE cursor in a FOREACH statement, provided the UPDATE statement in the body of the loop doesn't use WHERE CURRENT OF?