Función escalar en lenguaje Java

Este ejemplo utiliza el siguiente nombre de archivo:

TestJavaInterface.java

Código

El código de este ejemplo muestra que, con pequeños cambios, este programa funciona en modo remoto. El cambio está en el main donde se añade un bucle alrededor de getAPI para que sea llamado dos veces. Si la conexión es remota, se transfiere para ser ejecutada por un nuevo hilo y esperar una nueva conexión. Por último, si la conexión no es remota, salga del bucle después de la primera iteración. Este código funciona como un EA local y maneja dos iteraciones como un EA remoto.

import org.netezza.ae.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class TestJavaInterface {

    private static final Executor exec =
        Executors.newCachedThreadPool();

    public static final void main(String [] args) {
        try {
            mainImpl(args);
        } catch (Throwable t) {
            System.err.println(t.toString());
            NzaeUtil.logException(t, "main");
        }
    }

    public static final void mainImpl(String [] args) {
        NzaeApiGenerator helper = new NzaeApiGenerator();
 
       while (true) {
           final NzaeApi api = helper.getApi(NzaeApi.FUNCTION);
           if (api.apiType == NzaeApi.FUNCTION) {
               if (!helper.isRemote()) {
                   run(api.aeFunction);
                   break;
               } else {
                   Runnable task = new Runnable() {
                           public void run() {
                               try {
                                   TestJavaInterface.run(api.aeFunction);
                               } finally {
                                   api.aeFunction.close();
                               }
                           }
                       };
                   exec.execute(task);
               }
           }
        }
        helper.close();
    }

    public static class MyHandler implements NzaeMessageHandler
    {
        public void evaluate(Nzae ae, NzaeRecord input, NzaeRecord output) { 
            final NzaeMetadata meta = ae.getMetadata();
  
            int op = 0;
            double result = 0;

            if (meta.getOutputColumnCount() != 1 ||
                meta.getOutputNzType(0) != NzaeDataTypes.NZUDSUDX_DOUBLE) {
                throw new NzaeException("expecting one output column of type
double");

            }
            if (meta.getInputColumnCount() < 1) {
                throw new NzaeException("expecting at least one input column");
            }
            if (meta.getInputNzType(0) != NzaeDataTypes.NZUDSUDX_FIXED &&
                meta.getInputNzType(0) != NzaeDataTypes.NZUDSUDX_VARIABLE) {
                throw new NzaeException("first input column expected to be a
string type");
            }

            for (int i = 0; i < input.size(); i++) {
                if (input.getField(i) == null) {
                continue;
            }
            int dataType = meta.getInputNzType(i);
            if (i == 0) {
                if (!(dataType == NzaeDataTypes.NZUDSUDX_FIXED
                        || dataType == NzaeDataTypes.NZUDSUDX_VARIABLE)) {
 
                    ae.userError("first column must be a string");
                }
                String opStr = input.getFieldAsString(0);
                if (opStr.equals("*")) {
                    result = 1;
                    op = OP_MULT;
                }
                else if (opStr.equals("+")) {
                    result = 0;
                    op = OP_ADD;
                }
                else {
                    ae.userError("invalid operator = " + opStr);
                }
                continue;
            }
            switch (dataType) {
                case NzaeDataTypes.NZUDSUDX_INT8:
                case NzaeDataTypes.NZUDSUDX_INT16:
                case NzaeDataTypes.NZUDSUDX_INT32:
                case NzaeDataTypes.NZUDSUDX_INT64:
                case NzaeDataTypes.NZUDSUDX_FLOAT:
                case NzaeDataTypes.NZUDSUDX_DOUBLE:
                case NzaeDataTypes.NZUDSUDX_NUMERIC32:
                case NzaeDataTypes.NZUDSUDX_NUMERIC64:
                case NzaeDataTypes.NZUDSUDX_NUMERIC128:
                    switch (op) {
                        case OP_ADD:
                            result +=
input.getFieldAsNumber(i).doubleValue();
                            break;
                        case OP_MULT:
                            result *=
input.getFieldAsNumber(i).doubleValue();
                            break;
                    default:
                        break;
                    }
                    break;
                default:
                    break;
            }
        }   // end of column for loop

        output.setField(0, result);
        }

     }
     private static final int OP_ADD = 1;
     private static final int OP_MULT = 2;

     public static int run(Nzae ae)
     {
         ae.run(new MyHandler());
         return 0;
     }
}

Una compilación

Utiliza la compilación estándar como en modo local:

$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language java --template \
     compile TestJavaInterface.java --version 3

Registro

El registro es ligeramente diferente. Primero ejecuta esto para registrarte:

$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "rem_applyop_java(varargs)" \
     --return "double" --class AeUdf --language java --template udf \
     --define "java_class=TestJavaInterface" --version 3 --remote \
     --rname testjavapi

Esto especifica que el código se registre como un ae remoto con un nombre remoto de testjavapi, que coincide con el código. Además, se registra un lanzador:

$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "rem_applyop_launch(int8)" \
     --return "TABLE(aeresult varchar(255))" --class AeUdtf --language java \
     --template udtf --define "java_class=TestJavaInterface" --version 3 \
     --remote --rname testjavapi --launch

A excepción de --rname, --exe y la parte del nombre de --sig, todos los lanzadores se parecen a los anteriores. En este caso se trata de una UDTF, ya que es la interfaz de todos los lanzadores. El valor de --rname debe coincidir con el nombre del código.

En ejecución

Para ejecutar el AE en modo remoto, el ejecutable se ejecuta como "servidor" En este caso, sólo gestiona las consultas ejecutadas en el host. Normalmente, los EA se inician también en las SPU. Iniciar una instancia en el host:

SELECT * FROM TABLE WITH FINAL(rem_applyop_launch(0));
                                AERESULT
-------------------------------------------------------------------------
 tran: 14896 session: 18286 DATA slc: 0 hardware: 0 machine: bdrosendev process:
15937 thread: 15938
(1 row)

Observe que se utiliza una sintaxis diferente para invocar el lanzador de estilo de función de tabla. Esta es la sintaxis utilizada para llamar a cualquier AE basado en UDTF. Ahora ejecute el AE:

SELECT rem_applyop_java('+', 4,5,1.1);
 REM_APPLYOP_JAVA
------------------
 10.1
(1 row)

Por último, provocar un error:

SELECT rem_applyop_java(1);
ERROR: first input column expected to be a string type