Kbase P5091: Why don't we evaluate the expression of a FOR...WHERE clause within an internal procedure?
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  5/7/2009 |
|
Status: Unverified
GOAL:
Why don't we evaluate the expression of a FOR...WHERE clause within an internal procedure?
GOAL:
Why an expression is not evaluated in an internal Procedure within a FOR...WHERE clause?
FACT(s) (Environment):
Progress V7.X
Progress V8.X
Progress V9.X
OpenEdge 10
FIX:
The following code will lead to Compile Errors if you try to run it in the Progress Editor.
/*Example 1*/
DEF BUFFER BCUSTOMER FOR CUSTOMER.
FOR EACH BCUSTOMER WHERE CUSTOMER.CUSTNUM = 1 NO-LOCK:
MESSAGE 1 VIEW-AS ALERT-BOX.
END.
This code produces the following compile Errors:
** Missing FOR, FIND or CREATE for a table with <field> in current block. (232)
** <program> Could not understand line <number>. (196)
The following code does not produce any compilation errors. Note that the WHERE clause is illogical and will lead to a logical Error.
/*Example 2*/
DEF BUFFER BCUSTOMER FOR CUSTOMER.
RUN A.
PROCEDURE A:
FOR EACH BCUSTOMER WHERE CUSTOMER.CUSTNUM = 1 NO-LOCK.
MESSAGE 1 VEW-AS ALERT-BOX.
END.
MESSAGE 2 VIEW-AS ALERT-BOX.
FOR EACH BCUSTOMER WHERE ORDER.CUSTNUM = 1 NO-LOCK.
MESSAGE 3 VEW-AS ALERT-BOX.
END.
MESSAGE 4 VEW-AS ALERT-BOX.
END.
OpenEdge performs error checking very differently in the main block and the internal procedure.
The main .p version of the FOR EACH gives you an error, because no customer record is present.
So you get a compiler error.
In the internal procedure, things are different.
People run internal procedures as super procedures, or as RUN VALUE(myfld)... etc. It is impossible for the application to know what has gone on before the invocation of the internal procedure.
For this reason, OpenEdge does not try to figure out if you have arranged to find into any buffers that get referenced. OpenEdge just creates a default buffer for every reference (customer and order) and hope that you will have filled them by the time the procedure runs, however/wherever you may have invoked it.
Then at runtime, when the internal procedure does get invoked, the WHERE clauses is indeed evaluated. But any error messages from them are suppressed.
Why?
For performance considerations, the server takes in charge the evaluation of the WHERE clause since Progress 7. However, the server cannot retrieve extensive information regarding the local client environment. Therefore any expressions in the WHERE that are not appropriate for the server, are be evaluated on the client first.
For example:
FOR EACH cust WHERE custnum > 0 or order.ordernum = 3 ....
On the first pass, custnum cannot be known yet on the client side, but we do try to get the ordernum. Perhaps the order buffer is empty unless the custnum > 0, but the outcome is not known yet. Since many similar situation are eager to occur, OpenEdge simply goes ahead and attempts to retrieve order.ordernum. If there is no record match, returns the unknown value, suppressing the message and move on, waiting until the server gets a chance to perform his part of the query process.
It is true that we could have a switch to not do this, but then you would get a bunch of unwanted messages in otherwise successful FOR ..WHERE.. cases.