Peter Dow (ML) wrote:
I hope you're not feeling picked on here! I'm still having a hard time
understanding your objection and some of your explanations.
If I were, I would just accuse everyone of being blind and give up.
Albeit, I am almost there.
CRPence wrote:
No. Insert Trigger act between the trigger program and the
database; they have their own contractual obligations. A Read
Trigger is between the HLL and the database. That is what makes
them totally different.
What does this mean? From the app pgm point of view, all of these
triggers -- READ, INSERT, UPDATE, DELETE -- are between it and
the database.
*INSERT\*BEFORE
HLLPGM->HLLWRITE->[TRIGGER->CHGDTA->DBWRITE]->HLLPOSTWRITELOGIC
Contract is between TRIGGER&DBWRITE, the row of CHGDTA is validated
and logged by the database. Whatever the HLLPGM wrote, that program is
still aware of, and can continue with that same HLL logic _unaffected_,
knowing that it just wrote what it wrote. This remains true,
irrespective of what the trigger might have really done in its contract
with the db write.
*READ\*AFTER
HLLPGM->HLLREADx->[DBREAD->TRIGGER]->CHGDTA->HLLPOSTREADLOGIC
Contract is between the DBREADx&TRIGGER, the row of CHGDTA occurs
outside the realm of the database but impacts the database row, and the
logic in the HLL-Post-Read activity may be impacted because the physical
data that it should be receiving may not match what was received.
What if the read was a keyed-read and the key value was modified
such that it is no longer collating. The coded assumption of the
program *and* its run-time HLL routines [that the data is arriving in a
known order] are caught unaware, and the output [to the program] is
flawed. If the row is not also then updated, the logic in the program
is operating against a value which is different in the physical row than
in the program. Although this may be desirable in the wished-it-were-so
change-capable read trigger, that is a *huge* problem for any other
READer of that row, without being *very* *very* *aware* of the magical
manipulation taking place without the full validation and logging of the
database. Contrast this with a UDF, where the program *asks* for the
data to have been changed, and when the row retrieval occurred, it was
according to the result of the UDF when so requested.
I have obviously not been articulating well, the flaws in a change
capable trigger, since all that comes from it is the repeated argument
that "anything can mess with the data, so a Read Trigger should be able
to as well." So maybe a theoretical example, assuming the added Read
Trigger is change capable:
create table qgpl. T (i int, c char)
addpftrg qgpl/T *after *read pgm(plusone)
-- plusone returns a value one greater than in field i
insert into table qgpl.T values(1, DEFAULT)
call read4upd /* open T for upd, read, upd C='', close */
-- trigger program is called, set i = 2 as /desired/
-- Does the row update to the value 2 or stay 1 ?
-- Well, to pass the row with that value to the program,
-- the buffer was just updated to have the value 2
-- So the program updates without changing the value i,
-- yet the value in the table for i is now 2
The same table now, with the value 2:
select i from qgpl.T where i <= 2 into :ii
The fetched value ii does not meet the selection logic; i.e. ii=3
whereas all coded logic is with respect to selecting only values that
were /less than or equal to two/. Where is the logic in that? This is
much worse for /native/ programs, where logic is more likely to be
deferred to the application and HLL run-time.
What if you turned your example around? Put an update trigger on a
file. Have it always add 1 to i. Now what? App pgm reads the file,
adds 1 to i, updates the record. If i started out as 1, it is now 3.
Where's the logic in that?
If the business rule for the data on writing is that every value i is
one greater than every posted value, then that is acceptable and has no
impact on the READ from the database. Indeed a read, increment, and
update will double increment. That was a business rule being applied to
the physical data that is entirely separate from the logic of the
program... Well unless the programmer knows about the trigger and thinks
there is some flaw in the business rules, so then tries to instead of
inserting the incremented value inserts one less for every value of i;
but that is its own cranial failure in its own right. So if the value
always needs to be incremented on a write, then the logic was applied...
and the data owner says "That is good. That is right." If the result
was flawed, then it was a flaw in the business rule or the trigger
program, but the value which was written was capable of being logged;
all activity remained in the realm of the db.
It should be absolutely clear, and why I am somewhat frustrated [and
thus my opening comment here], how it can not be *intuitively obvious*
with simple _logic_, why the above given SELECT is horribly impacted by
an intermediary changing the selected\read data. Compare that SELECT
with the following which are each logical [assuming no intermediary
changing the value of i without the knowledge of either the database
selection or the program processing the selected row(s)]:
select iplusone(i) from qgpl.T where i <= 2
select i from qgpl.T where iplusone(i) <= 2
select iplusone(i) from qgpl.T where iplusone(i) <= 2
In these three SELECT, the _requesting_ program is fully aware that
the value of i is being manipulated by the iplusone() function. No
flawed logic here. Revisit the case where an intermediary has changed
the value of i, and there is clearly flawed logic whereby the incorrect
results are inherent by the specified selection in the WHERE clause.
If those SELECT were encapsulated in a VIEW which a program referred
to, the logic remains valid. The same can not be said if the modified
results were obtained instead from an intermediary changing the row data
outside of the db.
Regards, Chuck
As an Amazon Associate we earn from qualifying purchases.