ydb_ci_*() functions return ZHALT argument
Final Release Note
A ZHALT in M code called by C code using a ydb_ci*()
function causes the ydb_ci*()
have as its status (the ydb_status_t
return value of the ydb_ci*()
function) the ZHALT argument. A HALT causes ydb_ci*()
to return a status of zero (0). Previously, the argument of ZHALT argument would show up as the return value of the corresponding function specified in the call-in table, if the function provided for a return value in the call-in table, and a NOTEXTRINSIC error otherwise, and also initialized return/output parameters of the C function. Note that:
-
Wrappers for other languages, such as Go, Perl, Python, and Rust all use
ydb_ci*()
if they call M code. -
When invoked through
ydb_ci*()
, a ZHALT argument can be a 4-byte integer with the entire 4-byte value returned. As before, a ZHALT that returns to the shell (i.e., M code directly invoked from the shell) has a 0-255 value as its status. -
When
ydb_ci*()
returns a status of a non-zero value, any return/output type parameters should be assumed uninitialized, whereas they are set for zero return values.
Description
The commit message of 0b4e31e9 (one of many commits for #59 (closed)) describes the following change.
ZHALT no longer halts but returns its argument to the call-in caller as the return value.
What this means is that if, for example, an M program invoked by ydb_ci()
has code that does a ZHALT 255
, it would abruptly terminate the call-in/M environment and return from ydb_ci()
with a 0 return value. The 255
return value would be stored as the return value in the function invoked by ydb_ci()
assuming that function accepted a return value in the call-in table definition. And if not, will issue a NOTEXTRINSIC
error.
This does not seem right to me. In my opinion, the return value of ydb_ci()
should be 255
in this case as it indicates the exit status from the M environment. And the return type of the function being invoked by ydb_ci()
should have no relation to the ZHALT
argument.
A ZHALT 0
should be considered a successful invocation and ydb_ci()
should return 0
in that case. A ZHALT
with a non-zero argument should cause ydb_ci()
to return the same non-zero value.
The caller of ydb_ci()
should check the return value and if non-zero should take appropriate error action. It cannot assume any return value and output parameter values of the call-in invocation to be set in case of a non-zero return from ydb_ci()
.
Additionally, while it is okay for ZHALT
return code to be limited to 1-byte if the base program is an M program (i.e. it exits to the shell which only accepts a 1-byte exit code), it seems more user-friendly for ZHALT
return code to be a 4-byte integer value in case this happens while inside a ydb_ci()
call. In that case, ydb_ci()
return value is an integer type and so should take in the full ZHALT
4-byte argument thus giving the user a lot bigger range of return values.
Draft Release Note
To understand this release note, you need to be cognizant of the fact that a ydb_ci*
call can have two returns:
- The status code of the call, which is ALWAYS returned.
- The extrinsic function return of the M code, which is optional, as that only happens if the M code uses
QUIT
with an argument.
The core of the issue is that ZHALT
with an argument behaved as if it was QUIT
with an argument, which is undesirable and does not fit the C API philosophy. Instead, it was changed so that it returns the status code.
The following is a more detailed description.
A ZHALT
with a non-zero argument while inside a ydb_ci*()
invocation causes ydb_ci*()
to return a status of that non-zero value. A ZHALT 0
(or the equivalent HALT
) while inside a ydb_ci*()
function causes ydb_ci*()
to return a status of 0
.
Previously, the ZHALT
argument would show up as the M extrinsic function return value of the C function that was invoked by ydb_ci*()
if the function accepted a return value in the call-in table, would issue a NOTEXTRINSIC
error otherwise and would initialize return/output parameters of the C function even in case a ZHALT
was invoked.
As of this release, The C function that is invoked by ydb_ci*()
can be defined with an M extrinsic function return value or not in the call-in table (defined by ydb_ci
env var) and that no longer has any connection to the ZHALT
argument.
Two other changes that are done as part of this issue are:
- In case of being invoked by
ydb_ci*()
, theZHALT
argument can even be a 4-byte integer in which case the full 4-byte value is returned throughydb_ci*()
. However, any returns to the shell (where the M program is directly invoked from the shell) will still keep the 0-255 return code. - If
ydb_ci*()
returns a status of a non-zero value, any return value parameters and output type parameters in the C function have to be assumed as uninitialized. This is important to note as this differs fromHALT
andZGOTO 0
, as well asZHALT 0
, where the return status is zero.