Fortran language scalar function

The following example shows a simple scalar function that sums a set of numbers. This example starts from the beginning to construct a simple AE. It uses the following file name: applyop.f

Code

  1. Create the program and call nzaeRun(). This call sets up the AE and then makes a callback to nzaeHandleRequest(), which is necessary for Fortran implementation. This can typically be accomplished by using:
    program applyopProgram
    call nzaeRun()
    stop
    end
    subroutine nzaeHandleRequest(handle)
    c Our custom Fortran code will go here.
    return
    end
  2. Complete the custom Fortran code. In this UDF, you pass in a string operator, which is either a "+" (add) or a "*" (multiply), as well as two integers. The code returns either the product or the sum of the integers. In SQL, a simple version of this might be called by either:
    SELECT applyop('+', 3, 5);
    or
    SELECT applyop('*', 3, 5);
    Although the mentioned example has only one input, the NPS system deals with streams of input. Therefore, the NPS system is more likely to use:
    SELECT applyop(mytable.operator, mytable.value1, mytable.value2) FROM mytable;

    In the first example, the NPS system takes the constants, "+", 3, and 5 and turns them into a stream of length one containing three elements. Internally, all of the mentioned cases are handled in the same manner and the assumption can be made that there are multiple inputs to the applyop AE.

  3. A loop handling input is needed, which in Fortran 77 can be accomplished with an if statement and a goto. For example:
    program applyopProgram
    call nzaeRun()
    stop
    end
    subroutine nzaeHandleRequest(handle)
    integer hasNext, leftInput, rightInput, result
    character operator
    hasNext = -1
    10 call nzaeGetNext(handle, hasNext)
    if (hasNext .eq. 0) then
    goto 20
    endif
    c Our loop work will go here.
    goto 10
    20 return
    end

    Note the initialization of the hasNext variable. This is necessary for "out" variables that call into the underlying interface. Without this, the hasNext pointer remains unallocated and cannot receive data from the underlying call. The nzaeGetNext() function sets the variable hasNext to 1 (TRUE) if there is another element in the stream, and to 0 (FALSE) if the stream is done.

  4. Add the logic:
    program applyOpProgram
    call nzaeRun()
    stop
    end
    subroutine nzaeHandleRequest(handle)
    integer hasNext, leftInput, rightInput, isNull, result
    character operator
    hasNext = -1
    leftInput = 0
    rightInput = 0
    operator = 'f'
    isNull = 0
    10 call nzaeGetNext(handle, hasNext)
    if (hasNext .eq. 0) then
    goto 20
    endif
    c GET OUR INPUT.
    call nzaeGetInputString(handle, 0, operator, isNull)
    call nzaeGetInputInt32(handle, 1, leftInput, isNull)
    call nzaeGetInputInt32(handle, 2, rightInput, isNull)
    c OPERATE.
    if (operator .eq. '+') then
    result = leftInput + rightInput
    else if (operator .eq. '*') then
    result = leftInput * rightInput
    else
    call nzaeUserError(handle, 'Unhandled operator.')
    endif
    c OUTPUT.
    call nzaeSetOutputInt32(handle, 0, result)
    call nzaeOutputResult(handle)
    goto 10
    20 return
    end

    Each input in the loop contains the three elements that are passed into the function. The function nzaeGetInputX() takes the handle that represents one user request, a column index that in this case specifies 0 for operator, 1 for left input and 2 for right input, and the output variable. The function nzaeUserError() reports an error to the SQL user. The function nzaeSetOutputX() outputs the result. Because this is run as a UDF, there can be only one column in the result. A later example demonstrates how to use UDTFs to output multiple columns. When the code is complete, it must be compiled and registered.

Compilation

Compile the code:
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language fortran --version 3 \
--template compile --exe applyopFortran applyop.f

The output executables, one for the host and one for the SPU, are placed under the host and spu directories in /nz/export/ae/applications/$NZ_USER/$NZ_DATABASE

Registration

Register the executables:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --language fortran --version 3 \
--template udf --exe applyopFortran \
--sig "applyop_fortran(varchar(1), int4, int4)" --return int4

Running

You can now run the AE in SQL:
SELECT applyop_fortran('+', 4, 10);
APPLYOP
---------
14
(1 row)
Note that in the code, when you validate the types in nzaeHandleRequest(), you call nzaeUserError() to send an error. The following example triggers an error:
SELECT applyop_fortran('-',1,2);
ERROR: Unhandled operator.