define(_HELP,1000)
define(_INSERT,2000)
define(_UPDATE,3000)
define(_DELETE,4000)
define(_retcode,`eval($1)')
These macro definitions together with stored procedure return statements such as
return _retcode(_INSERT)
which expands to
return 2000
allow us to use the same return codes across all stored procedures without having to remember what
they are. Just remember to include(macro_def.m).
In the above macro definition we use the predefined eval() macro which attempts
to interpret its argument as an arithmetic expression and then
evaluates to the value of that
expression. We can also add specifics to the _retcode macro such as consecutively numbering
each use of the macro in a particular stored procedure.
define(_location, 0) /* executed once at the beginning of the
procedure */
define(_retcode,`eval(ifelse($1,,,$1 +) _location)
define(`_location',eval(_location + 1))')
This macro is made up of two components - eval(ifelse($1,,,$1 +) _location) and
define(`_location',eval(_location + 1)).
The first component uses the current value of _location in defining the actual return code.
The ifelse(a,b,c,d) built-in macro works as follows: if a and b, once evaluated, are
identical then ifelse returns the evaluation of c; otherwise it evaluates to the
value of d. Hence the ifelse($1,,,$1) macro starts by evaluating $1. If it is NULL
(ie, equal to the second (missing) argument in the ifelse
macro) the macro returns nothing (ie, the third (missing) argument);
otherwise the macro returns the evaluation of $1 + (the
fourth argument). As a result the first component produces either
eval($1 + _location) or
eval(_location) depending on whether an argument is
passed to the _retcode macro or not, respectively. Of course,
this must be evaluated further to produce an actual number.
The second component, define(`_location',eval(_location + 1)), is a bit more subtle. Recall that the macro _location has just been used to produce an actual return code. Now we seem to be defining _location within another macro. This is exactly what is happening. Indeed, _location is being defined to be 1 greater than its previous value. This ensures that the next time the _retcode macro is used, even with the same argument, say _INSERT, it will produce a different value - one greater than its previous value. What really allows this to happen are the quotes around the _location macro being defined which prevent the _location macro from being evaluated immediately. Otherwise something like define(5, eval(5 + 1)) would be encountered by m4 and it would complain.
Thus the SQL/m4 code
... /* SQL code */
return _retcode(_INSERT)
... /* more SQL code */
return _retcode(_INSERT)
... /* still more SQL code */
which repeatedly uses _retcode with the argument _INSERT in a stored procedure will generate the SQL code
... /* SQL code */
return 2000
... /* more SQL code */
return 2001
... /* still more SQL code */
when processed by m4.