Variable Visibility and Liftime

I have a TEMP-TABLE 'Zmiany' which is an OUTPUT PARAMETER from procedure. I am using this TEMP-TABLE 'Zmiany' in QUERY. I am processing QUERY in DO WHILE NOT QUERY-OFF-END loop. But inside this loop I would like to search again through TEMP-TABLE 'Zmiany'.

After FIND FIRST I don't know if I will have access to 'Zmiany' from QUERY or from FIND FIRST statement?. And what will be a Liftime and Visibility of 'Zmiany' from FIND FIRST statement? I would like to have only access to 'Zmiany' from FIND FIRST statement inside "IF Zmiany.Pole = '15' THEN DO:" block.

I put (1), (2) and (3) in code. I know that in (1) I have available 'Zmiany' from QUERY but I am not sure from which place (QUERY of FIND FIRST statement) I will have available 'Zmiany' in (2) and (3)?

Code:
RUN Procedure.p (OUTPUT TABLE Zmiany) NO-ERROR.

DEFINE QUERY Change FOR Zmiany, POHeader.

OPEN QUERY Change FOR 
    EACH Zmiany,
    EACH POHeader WHERE POHeader.PONum = INTEGER(Zmiany.Klucz1)
        NO-LOCK BY POHeader.PONum,
.    

GET FIRST Change.
DO WHILE NOT QUERY-OFF-END('Change'):
    Zmiany.Pole (1)
    IF Zmiany.Pole = '15' THEN
    DO:
        FIND FIRST Zmiany WHERE... 
        Zmiany.Pole (2)
    END.
    Zmiany.Pole (3)
END.
 

RealHeavyDude

Well-Known Member
The reference to the table Zmiany in reality is a reference to the default buffer of the table. Since there can only be one record in the record buffer you must use another buffer, a defined buffer to do the FIND.

DEFINE BUFFER <your-buffer-name> FOR Zmiany.

Working with a defined buffer is exactly the same than working with the default buffer.

HTH, RealHeavyDude.
 

RealHeavyDude

Well-Known Member
Named buffers are also a perfect means to prevent unwanted large buffer scopes and thus share-locks "hanging" around ...

For database updates by static buffers I only use named buffers for that reason.

Regards, RealHeavyDude.
 
After DEF Zmiany2 I lost Zmiany BUFFER - WHY? Because of running external procedure?

The code is like following
Code:
DEFINE BUFFER Zmiany2 FOR Zmiany. 

RUN Procedure.p (OUTPUT TABLE Zmiany).

DEFINE QUERY Change FOR Zmiany, POHeader.

OPEN QUERY Change FOR 
    EACH Zmiany,
    EACH POHeader WHERE POHeader.PONum = INTEGER(Zmiany.Klucz1)
        NO-LOCK BY POHeader.PONum,
.    

GET FIRST Change.
DO WHILE NOT QUERY-OFF-END('Change'):
   Zmiany.Pole /* Zmiany table is AVAILALBE here (1) */
   IF Zmiany.Pole = '15' THEN
   DO:
      RUN Procedure.p (OUTPUT TABLE Zmiany2).
      Zmiany2.Pole /* Zmiany2 table is AVAILABLE here (2) */
      Zmiany.Pole /* Zmiany table is not longer AVAILABLE here WHY ? (3) */
   END.
END.
 

RealHeavyDude

Well-Known Member
Since you only show code excepts it's hard to say - one would need to speculate what the code in the external procedures does, so I just need to guess:

I think you mixing and matching defined buffers and the default record buffer for a table. You can define a buffer with the same name than the default record buffer for that table and the compile will happily compile it - but at runtime you are facing something that's called buffer scope that might behave different as to what you expect it to. That means, each buffer has a scope and it is only valid within the boundaries of that scope. If the buffer goes out of scope, depending on the type of scoping, you might be able to reference it, but it won't hold a record anymore.

You should make yourself familiar with blocks and how they relate to the scope of things. You should read the chapter "Record Buffers and Record Scope" of the ABL handbook which is part of the documentation that ships with the product for a start.

HTH, RealHeavyDude.
 
Since you only show code excepts it's hard to say - one would need to speculate what the code in the external procedures does, so I just need to guess:

I think you mixing and matching defined buffers and the default record buffer for a table. You can define a buffer with the same name than the default record buffer for that table and the compile will happily compile it - but at runtime you are facing something that's called buffer scope that might behave different as to what you expect it to. That means, each buffer has a scope and it is only valid within the boundaries of that scope. If the buffer goes out of scope, depending on the type of scoping, you might be able to reference it, but it won't hold a record anymore.

You should make yourself familiar with blocks and how they relate to the scope of things. You should read the chapter "Record Buffers and Record Scope" of the ABL handbook which is part of the documentation that ships with the product for a start.

HTH, RealHeavyDude.

I went through handbook and probably I know where is the problem. But not exactly.

I have DefineVariable.i file which is included both, mentioned procedure and external procedure. I have also ExternalProcedure.p file and MainProcedure.p file.
Code:
DefineVariable.i file:
DEFINE TEMP-TABLE Zmiany NO-UNDO
    FIELD Creation AS LOGICAL INITIAL FALSE
    FIELD...
.
Code:
MainProcedure.p file:
{DefineVariable.i}
DEFINE BUFFER Zmiany2 FOR Zmiany. 
RUN Procedure.p (OUTPUT TABLE Zmiany). /* (0) */
DEFINE QUERY Change FOR Zmiany, POHeader.

OPEN QUERY Change FOR 
    EACH Zmiany,
  EACH POHeader WHERE POHeader.PONum = INTEGER(Zmiany.Klucz1)
    NO-LOCK BY POHeader.PONum
.    

GET FIRST Change.
DO WHILE NOT QUERY-OFF-END('Change'):
   Zmiany.Pole /* Zmiany table is AVAILALBE here (1) */
   IF Zmiany.Pole = '15' THEN DO:
     RUN Procedure.p (OUTPUT TABLE Zmiany2). /* (2) */
      Zmiany2.Pole /* Zmiany2 table is AVAILABLE here (3) */
      Zmiany.Pole /* Zmiany table is not longer AVAILABLE here WHY ? (4) */
   END.
END.
Code:
ExternalProcedure.p file:
{DefineVariable.i}
DEFINE OUTPUT PARAMETER TABLE FOR Zmiany.
DO WHILE loop:
   CREATE Zmiany.
     Zmiany.Creation = TRUE.
     Zmiany.OtherField....
END.

RETURN
In point (0) I am running External Procedure.p with Zmiany TABLE as OUTPUT PARAMETER. In Procedure.p Zmiany TABLE is CREATED and FILLED OUT. In a point (1) I have available TABLE Zmiany. In point (2) I am running again External Procedure.p with Zmiany2 table as OUTPUT PARAMETER (Zmiany2 is an BUFFER FOR Zmiany). I thought that as far as I am passing a Zmiany2 to External Procedure, it will not change a Zmiany TABLE. But probably it happened in that way because in point (4) Zmiany table is not longer AVAILABLE why?

When I did a changes and replace BUFFER DEFINITION with creating another TEMP-TABLE (DEFINE TEMP-TABLE Zmiany LIKE Zmiany.) everything was OK. But I would like to know why External Procedure is touching Zmiany TABLE if I am passing there Zmiany2 TABLE? Is it because Zmiany2 is a BUFFER for Zmiany?
 
You can pass temp tables as input-output parameters and change its contents inside internal procedure. Else you will overwrite old table contents.
Actually it is better to define new shared temp-table (in definevariables.i) with this style of programming and do not pass any tables as input/output parameters.
 

RealHeavyDude

Well-Known Member
You define two buffers to the same temp-table so they both point to the same source. The output parameter table means that you are passing the table no matter what and how many buffers point to it. There is an APPEND option which will append the contents as long as you don't violate a unique index. If you don't specify this parameter then the contents of the temp-table are completely wiped before the contents from the output is accepted.

I do not understand what you're trying to achieve - to me it looks like the APPEND should do.


Regards, RealHeavyDude.
 
You define two buffers to the same temp-table so they both point to the same source. [.....] If you don't specify this parameter then the contents of the temp-table are completely wiped before the contents from the output is accepted. [.....]
Regards, RealHeavyDude.
Your answer makes the whole situation much more clear for me. The problem is in wipping out the table Zmiany. Now I know the rule but can't understand the filosophy. Why I can't fill out the BUFFER for table Zmiany in external procedure without wipping out table Zmiany?
Regarding BUFFERS:
1. In BUFFER I can store a different quantity of rows than in original table
2. In BUFFER I can store a rows that are not exisiting in original table
So what is the connection between original table and BUFFER for it?
I was thinking about BUFFER like a table with the exactly same field structure like original table. I am not aware about any other similarity (connection) between original table and a BUFFER for it.
 
I was thinking about BUFFER like a table with the exactly same field structure like original table.

You are wrong. Buffer it is just another reference to the same table. Buffer and original table both have the same structure and contents.
Diffrent buffers may have diffrent current record to process. For exampe, buffer Zmiany refers to first record, buffer Zmiany2 refers to second record.

About philosophy. INPUT-OUTPUT TABLE parameters supports SOA Archticture. First layer is DB layer, second layer - is business logic layer, third layer is interface layer. In your example you mix all layers.
Ordinary, you have to process you condition (Zmiany.pole = 15) inside your External Procedure.p and return Result of query.

Your code will work if you write
RUN Procedure.p (INPUT-OUTPUT TABLE Zmiany2).
instead
RUN Procedure.p (OUTPUT TABLE Zmiany2).
 
Top