PenMax example (UDX version 2)

/*
Copyright (c) 2007-2010 Netezza Corporation, an IBM Company
All rights reserved.

The aggregate PenMax displays the penultimate (second largest) value. 

REGISTRATION:

CREATE AGGREGATE PENMAX(INT4) RETURNS INT4 STATE (INT4, INT4)
LANGUAGE CPP API VERSION 2 PARAMETER STYLE NPSGENERIC
EXTERNAL CLASS NAME 'CPenMax'
EXTERNAL HOST OBJECT '/home/nz/udx_files/penmax.o_x86'
EXTERNAL SPU OBJECT '/home/nz/udx_files/penmax.o_spu10'

Usage:
CREATE TABLE myints (a int, b int);
INSERT INTO myints VALUES (1,2);
INSERT INTO myints VALUES (1,4);
INSERT INTO myints VALUES (1,6);
INSERT INTO myints VALUES (2,8);
INSERT INTO myints VALUES (2,10);
INSERT INTO myints VALUES (2,12);

SELECT penmax(b) FROM myints;
*/

#include "udxinc.h"

using namespace nz::udx_ver2;

class CPenMax: public nz::udx_ver2::Uda
{
public:
CPenMax(UdxInit *pInit) : Uda(pInit)
{
}
static nz::udx_ver2::Uda* instantiate(UdxInit *pInit);

void CPenMax::accumulate()
{
    int *pCurMax = int32State(0);
    bool curMaxNull = isStateNull(0);
    int *pCurPenMax = int32State(1);
    bool curPenMaxNull = isStateNull(1);
    int curVal = int32Arg(0);
    bool curValNull = isArgNull(0);

    if ( !curValNull ) { // do nothing if argument is null - can't
                         //affect max or penmax
        if ( curMaxNull ) { // if current max is null, this arg
                            //becomes current max
            setStateNull(0, false); // current max no longer null
            *pCurMax = curVal;
        } else 
            { if ( curVal > *pCurMax ) { // if arg is new max
                setStateNull(1, false); // then prior current max
                                       // becomes current penmax
                *pCurPenMax = *pCurMax;
                *pCurMax = curVal; // and current max gets arg
            } else if ( curPenMaxNull || curVal > *pCurPenMax ){
                        // arg might be greater than current penmax
                setStateNull(1, false); // it is
                *pCurPenMax = curVal;
            }
        }
    }
}

void CPenMax::merge()
{
    int *pCurMax = int32State(0);
    bool curMaxNull = isStateNull(0);
    int *pCurPenMax = int32State(1);
    bool curPenMaxNull = isStateNull(1);
    int nextMax = int32Arg(0);
    bool nextMaxNull = isArgNull(0);
    int nextPenMax = int32Arg(1);
    bool nextPenMaxNull = isArgNull(1);

    if ( !nextMaxNull ) { // if next max is null, then so is 
                          //next penmax and we do nothing
        if ( curMaxNull ) {
            setStateNull(0, false); // current max was null, 
                                   // so save next max
            *pCurMax = nextMax;
        } else {
           if ( nextMax > *pCurMax ) {
               setStateNull(1, false);
                  // next max is greater than current, so save next
               *pCurPenMax = *pCurMax;
                  // and make current penmax prior current max
               *pCurMax = nextMax;
           } else if ( curPenMaxNull || nextMax > *pCurPenMax ) {
                // next max may be greater than current penmax
               setStateNull(1, false); // it is
               *pCurPenMax = nextMax;
           }
        }

        if ( !nextPenMaxNull ) {
            if ( isStateNull(1) ) {
              // can't rely on curPenMaxNull here, might have
              // change state var null flag above
                setStateNull(1, false); // first non-null penmax,
                                        // save it
                *pCurPenMax = nextPenMax;
            } else {
                if ( nextPenMax > *pCurPenMax ) {
                    *pCurPenMax = nextPenMax;
                    // next penmax greater than current, save it
                }
            }
        }
    }
}

ReturnValue CPenMax::finalResult()
{
    int curPenMax = int32Arg(1);
    bool curPenMaxNull = isArgNull(1);

    if ( curPenMaxNull )
        NZ_UDX_RETURN_NULL();
    setReturnNull(false);
    NZ_UDX_RETURN_INT32(curPenMax);
}
};

nz::udx_ver2::Uda* CPenMax::instantiate(UdxInit *pInit)
{
    return new CPenMax(pInit);
}