Função escalar da linguagem Java

Este exemplo usa o seguinte nome de arquivo:

TestJavaInterface.java

Código

O código neste exemplo mostra que, com pequenas alterações, esse programa funciona no modo remoto. A mudança está na parte principal, onde um loop é adicionado ao redor de getAPI para que ele seja chamado duas vezes. Se a conexão for remota, ela será transferida para ser executada por um novo thread e aguardar uma nova conexão. Por fim, se a conexão não for remota, saia do loop após a primeira iteração. Esse código funciona como um AE local e lida com duas iterações como um AE 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;
     }
}

Compilação

Use a compilação padrão como no modo local:

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

Registro

O registro é um pouco diferente. Primeiro, execute isso para se registrar:

$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

Isso especifica que o código seja registrado como um ae remoto com um nome remoto de testjavapi, que corresponde ao código. Além disso, um lançador é registrado:

$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

Com exceção de --rname, --exe e a parte do nome de --sig, todos os inicializadores são parecidos com o acima. Nesse caso, é um UDTF, pois essa é a interface de todos os lançadores. O valor de --rname deve corresponder ao nome no código.

Executando

Para executar o AE no modo remoto, o executável é executado como um "servidor" Nesse caso, ele lida apenas com as consultas executadas no host. Normalmente, os AEs também são iniciados nas SPUs. Iniciar uma instância no 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 uma sintaxe diferente é usada para invocar o iniciador de estilo de função de tabela. Essa é a sintaxe usada para chamar qualquer AE baseado em UDTF. Agora, execute o AE:

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

Por fim, cause um erro:

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