Passing dataset handle to generic handle parameter

Posted by Patrick Tingen on 20-Apr-2017 05:14

I happen to have a debugging procedure that can receive the handle of a query, buffer or temp-table and spit out its contents to a log file. Recently, I added support for datasets ( which was actually around 5 lines of code), but how am I supposed to call this procedure?

My procedure requires a parameter of type HANDLE and is normally called via a publish statement like:

PUBLISH 'publishTable' (INPUT TEMP-TABLE ttCustomer:HANDLE ).      /* fixed after remark */

But for a dataset, this does not work. I do have 2 workarounds though:

/* Does not work */
PUBLISH 'publishTable' (INPUT DATASET dsData:HANDLE ).

/* Works */
DEFINE VARIABLE h AS HANDLE NO-UNDO.
h = DATASET dsData:HANDLE.
PUBLISH 'publishTable' (INPUT h ).

/* Works */
PUBLISH 'publishTable' (INPUT HANDLE(STRING(DATASET dsData:HANDLE)) ).

But the latter two seem a bit clumsy. Is is possible to do it in one step, elegantly?

Posted by Fernando Souza on 20-Apr-2017 08:21

First I am assuming the temp-table example above is actually INPUT TEMP-TABLE ttCustomer:HANDLE.

The syntax for INPUT DATASET is expecting a dataset name. Jut add parenthesis around what in your case is an expression. This should give you what you want.

(INPUT (DATASET dsData:HANDLE))

All Replies

Posted by Peter Judge on 20-Apr-2017 08:08

What does the signature of the publishTable procedure look like?
 
And if you change the PUBLISH to RUN in this code, does it work?
/* Does not work */
PUBLISH 'publishTable' (INPUT DATASET dsData:HANDLE ).
 
It smells buggy to me , since a handle is a handle. Or it should be.
 

Posted by Fernando Souza on 20-Apr-2017 08:21

First I am assuming the temp-table example above is actually INPUT TEMP-TABLE ttCustomer:HANDLE.

The syntax for INPUT DATASET is expecting a dataset name. Jut add parenthesis around what in your case is an expression. This should give you what you want.

(INPUT (DATASET dsData:HANDLE))

Posted by Patrick Tingen on 20-Apr-2017 08:22

If I change it to a RUN, I get this:

RUN publishTable(INPUT DATASET dsData:HANDLE).

The ABL compiler just does not accept the structure as a valid input.

The signature is like this:

PROCEDURE publishTable:
  DEFINE INPUT PARAMETER phSource AS HANDLE NO-UNDO.

Posted by gdb390 on 20-Apr-2017 08:33

Just use the suggestion of Fernando

DEFINE TEMP-TABLE tt NO-UNDO

   FIELD a AS CHARACTER.

DEFINE DATASET dsData FOR tt.

PROCEDURE publishTable :

   DEFINE INPUT PARAMETER iph AS HANDLE NO-UNDO.

END PROCEDURE.

RUN publishTable(INPUT (DATASET dsData:HANDLE)).

Posted by Patrick Tingen on 20-Apr-2017 09:36

Thanks, it works like a charm!

Posted by Patrick Tingen on 21-Apr-2017 02:12

Although it works, I agree with Peter that it smells like a bug.

Stronger: I think it /is/ a bug and I have logged case #00356867 with progress for this.

Posted by Peter Judge on 21-Apr-2017 11:34

I had the detail explained to me in short words that I can understand (thanks Fernando :)
 
The “fun” part of this is that this is perfectly legal syntax.
 
Think about
                RUN foo (INPUT DATASET myDataset).
 
Where
PROCEDURE foo:
      DEF INPUT PARAM DATASET FOR myDataset.
END.
All good and proper.
 
Now look at
                RUN foo (INPUT DATASET myDataset:HANDLE ).
 
Where the leading portion is the same as the good, compiling code. The compiler cannot disambiguate between the intent to pass a DATASET and a HANDLE  and so (to use a technical term) does a rainbow or technicolour yawn*.
 
This is not a problem for tables because the keywords used differ
                RUN bar (INPUT TEMP-TABLE ttData:HANDLE)
                RUN bar( INPUT BUFFER ttData:HANDLE)
 
Where
PROCEDURE bar:
      DEF INPUT PARAM TABLE FOR ttData.
END.
 
So while it smells buggy it isn’t and is not likely to change (for backwards compat reasons).
 
Classes behave better; in 11.7 (at least) this works (compile and does what you think)
 
class TestArray:
 
     def temp-table ttdata
        field d1 as dec.
       
     def dataset dsData for ttdata.
 
    method public void Foo (input hdl as handle):
    end method.
    
 
    method public void Foo (input table for ttData):
    end method.
 
    method public void Foo (input dataset for dsdata):
    end method.
 
end class.
 
def temp-table ttdata
    field d1 as dec.
   
 def dataset dsData for ttdata.
 
def var o1 as TestArray.
 
o1 = new TestArray().
 
o1:Foo(dataset dsData).
o1:Foo(table ttData).
o1:Foo(temp-table ttData:handle).
o1:Foo(dataset dsData:handle).
 
 
 
 
 
 
 
* barfs horribly
 

Posted by Patrick Tingen on 24-Apr-2017 08:34

This is not entirely true and I beg to differ :)

If you look at

RUN foo (INPUT DATASET myDataset:HANDLE ).

It is perfectly clear for the compiler that it is a HANDLE that is passed to the procedure. That is because the word 'HANDLE' is added. There is a difference in passing the table as a whole or the handle and we are doing the latter here. Stronger, if you try to pass the handle when the procedure is expecting the table, you will get a runtime error.

Try this:

DEFINE TEMP-TABLE ttData
  FIELD cField AS CHARACTER.

CREATE ttData. ttData.cField = 'Hello world'.

RUN bar(INPUT TEMP-TABLE ttData:HANDLE).

PROCEDURE bar:
  DEFINE INPUT PARAMETER TABLE FOR ttData.

  FIND FIRST ttData.
  MESSAGE ttData.cField VIEW-AS ALERT-BOX INFO BUTTONS OK.
END PROCEDURE. 


It will give you this:


This thread is closed