Hi, I attempting to use "create call" to run a program with a set of parameters in a temp table. When I configure an "OUTPUT" parameter, I get an error stating: "Record paramTable not available for dynamic output parameter. (10088)" I first tried this by passing a table handle to a method and then creating a dynamic query. When this failed, I created a static temp-table in the class, and had the same problem. Does anyone know if there is any reason why this might not work in 10.2b008?
I followed the examples on this page: documentation.progress.com/.../index.html
Thanks, Michael
This is absolutely the problem … I’ve run into it and it’s a Royal PITA to work around.
There are a couple of approaches you can use.
1) Create a dynamic temp-table with one field per parameter (and one for the return value). Make sure you FIND it and keep it in scope before and after the INVOKE() call. This works pretty well except when you have parameters with variable-extent arrays.
2) In that case you end up defining a bunch of local variables in a single internal procedure or method and use what you need. Things get to look ugly fast but it works for pretty much everything. I used a bunch of case statements with include files
If you’re on 11.6.3+ you can see the approach I ended up taking for classes with the Progress.Lang.ParameterList object – which suffers from the same challenge. In 11.7.0+ there’ll be a procedure-based equivalent. The former is in the Execute() method in OpenEdge.Web.DataObject.ClassOperationHandler and the latter in OpenEdge.Web.DataObject.ProcedureOperationHandler. You can find both in the $DLC/src/netlib/OpenEdge.Net.pl procedure library.
It will help if you show some of the code involved, specially for the SET-PARAMETER() call.
This code, taken from the example works great:
define variable hCall as handle no-undo.
define variable outVal as character no-undo.
create call hCall.
/* Invoke hello.p non-persistently */
hCall:call-name = "node.p".
/* Sets CALL-TYPE to the default */
hCall:call-type = procedure-call-type.
hCall:num-parameters = 2.
hCall:set-parameter(1, "CHARACTER", "INPUT", "HELLO WORLD").
hCall:set-parameter(2, "CHARACTER", "OUTPUT", outVal).
hCall:invoke.
message outVal view-as alert-box.
/* Clean up */
delete object hCall.
This code, using a simple temp table for the parameters returns the error "Record paramTable not available for dynamic output parameter. (10088)." Please let me know if there is anything I need to change to make it work.
define variable hCall as handle no-undo.
define variable outVal as character no-undo.
define temp-table paramTable no-undo
field idx as integer
field mode as character
field typ as character
field val as character.
create paramTable.
assign
paramTable.idx = 1
paramTable.mode = "INPUT"
paramTable.typ = "character"
paramTable.val = "HELLO WORLD".
create paramTable.
assign
paramTable.idx = 2
paramTable.mode = "OUTPUT"
paramTable.typ = "character"
paramTable.val = "".
create call hCall.
/* Invoke hello.p non-persistently */
hCall:call-name = "node.p".
/* Sets CALL-TYPE to the default */
hCall:call-type = procedure-call-type.
hCall:num-parameters = 2.
for each paramTable:
message string(paramTable.idx) + ":" + paramTable.typ + ":" + paramTable.mode + ":" + paramTable.val.
hCall:set-parameter(paramTable.idx,paramTable.typ, paramTable.mode, paramTable.val).
end.
hCall:invoke.
message outVal view-as alert-box.
/* Clean up */
delete object hCall.
Hi,
I understand what you are trying to achieve, but I can also understand a little bit why Progress throws the error.
When the call is invoked, the temp-table records are out of scope, which makes it perhaps difficult to populate them with the output?
I feel that might be the problem.
That’s just because of your last parameter is an output one and you pass one of the temp-table field as value holder… that’s perfectly ok if you have a record available at the time of invoke so 4gl can go ahead and set the output value into that field, not the case here as you’re doing the call out of the for-each loop.
You are thinking in the line of "one row, one parameter" and you should think it as "one row, one invocation".
With that I mean that each table rows must/may have every calling parameter, as a column.
You have options, but the thing is that ABL needs to access the OUTPUT placeholder before, and after, the CALL.
That means that every row you are using as an OUTPUT needs to be AVAILABLE after the CALL, with your example is still possible with little changes, but: what if you have more than one OUTPUT?
In the later case you need to use a different TABLE for each OUTPUT so every one is AVAILABLE at the same time, or different columns of the same ROW.
In our framework we create a dynamic TEMP-TABLE with a column for each parameter of the invocation, whether it is an INPUT, OUTPUT or INPUT-OUTPUT, create a row, populate it, make the CALL, read the outputs, create another row, populate it, make the CALL, etc.
This is absolutely the problem … I’ve run into it and it’s a Royal PITA to work around.
There are a couple of approaches you can use.
1) Create a dynamic temp-table with one field per parameter (and one for the return value). Make sure you FIND it and keep it in scope before and after the INVOKE() call. This works pretty well except when you have parameters with variable-extent arrays.
2) In that case you end up defining a bunch of local variables in a single internal procedure or method and use what you need. Things get to look ugly fast but it works for pretty much everything. I used a bunch of case statements with include files
If you’re on 11.6.3+ you can see the approach I ended up taking for classes with the Progress.Lang.ParameterList object – which suffers from the same challenge. In 11.7.0+ there’ll be a procedure-based equivalent. The former is in the Execute() method in OpenEdge.Web.DataObject.ClassOperationHandler and the latter in OpenEdge.Web.DataObject.ProcedureOperationHandler. You can find both in the $DLC/src/netlib/OpenEdge.Net.pl procedure library.
Thanks everyone for the responses, all were very helpful. I see the problem now, and wish there was a more elegant way to handle it. Too bad the call can't retain a reference to the output field. I will have to go the route for a dynamic temp table with a single row and then pull the data back out.