Exemplo n.º 1
0
Datum
count_distinct_append(PG_FUNCTION_ARGS)
{
    element_set_t  *eset;

    /* info for anyelement */
    Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    Datum       element = PG_GETARG_DATUM(1);

    /* memory contexts */
    MemoryContext oldcontext;
    MemoryContext aggcontext;

    /*
     * If the new value is NULL, we simply return the current aggregate state
     * (it might be NULL, so check it).
     */
    if (PG_ARGISNULL(1) && PG_ARGISNULL(0))
        PG_RETURN_NULL();
    else if (PG_ARGISNULL(1))
        PG_RETURN_DATUM(PG_GETARG_DATUM(0));

    /* from now on we know the new value is not NULL */

    /* switch to the per-group hash-table memory context */
    GET_AGG_CONTEXT("count_distinct_append", fcinfo, aggcontext);

    oldcontext = MemoryContextSwitchTo(aggcontext);

    /* init the hash table, if needed */
    if (PG_ARGISNULL(0))
    {
        int16       typlen;
        bool        typbyval;
        char        typalign;

        /* get type information for the second parameter (anyelement item) */
        get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);

        /* we can't handle varlena types yet or values passed by reference */
        if ((typlen < 0) || (! typbyval))
            elog(ERROR, "count_distinct handles only fixed-length types passed by value");

        eset = init_set(typlen, typalign, aggcontext);
    } else
        eset = (element_set_t *)PG_GETARG_POINTER(0);

    /* add the value into the set */
    add_element(eset, (char*)&element);

    MemoryContextSwitchTo(oldcontext);

    PG_RETURN_POINTER(eset);
}
Exemplo n.º 2
0
Datum
quantile_append_int64_array(PG_FUNCTION_ARGS)
{
    
    struct_int64 * data;
    
    MemoryContext oldcontext;
    MemoryContext aggcontext;

    GET_AGG_CONTEXT("quantile_append_int64_array", fcinfo, aggcontext);

    oldcontext = MemoryContextSwitchTo(aggcontext);
        
    if (PG_ARGISNULL(0)) {
        data = (struct_int64*)palloc(sizeof(struct_int64));
        data->elements  = (int64*)palloc(SLICE_SIZE*sizeof(int64));
        data->nelements = SLICE_SIZE;
        data->next = 0;
        
        /* read the array of quantiles */
        data->quantiles = array_to_double(fcinfo, PG_GETARG_ARRAYTYPE_P(2), &data->nquantiles);
        
    } else {
        data = (struct_int64*)PG_GETARG_POINTER(0);
    }
    
    /* ignore NULL values */
    if (! PG_ARGISNULL(1)) {
    
        int64 element = PG_GETARG_INT64(1);
        
        if (data->next > data->nelements-1) {
            data->elements = (int64*)repalloc(data->elements, sizeof(int64)*(data->nelements + SLICE_SIZE));
            data->nelements = data->nelements + SLICE_SIZE;
        }
        
        data->elements[data->next++] = element;
        
    }
    
    MemoryContextSwitchTo(oldcontext);
    
    PG_RETURN_POINTER(data);

}
Exemplo n.º 3
0
Datum
quantile_append_numeric(PG_FUNCTION_ARGS)
{
    
    struct_numeric * data;
    
    MemoryContext oldcontext;
    MemoryContext aggcontext;

    GET_AGG_CONTEXT("quantile_append_numeric", fcinfo, aggcontext);
    
    oldcontext = MemoryContextSwitchTo(aggcontext);
        
    if (PG_ARGISNULL(0)) {
        data = (struct_numeric*)palloc(sizeof(struct_numeric));
        data->elements  = (Numeric*)palloc(SLICE_SIZE*sizeof(Numeric));
        data->nelements = SLICE_SIZE;
        data->next = 0;
        
        data->quantiles = (double*)palloc(sizeof(double));
        data->quantiles[0] = PG_GETARG_FLOAT8(2);
        data->nquantiles = 1;
    } else {
        data = (struct_numeric*)PG_GETARG_POINTER(0);
    }
    
    /* ignore NULL values */
    if (! PG_ARGISNULL(1)) {
    
        Numeric element = PG_GETARG_NUMERIC(1);
        
        if (data->next > data->nelements-1) {
            data->elements = (Numeric*)repalloc(data->elements, sizeof(Numeric)*(data->nelements + SLICE_SIZE));
            data->nelements = data->nelements + SLICE_SIZE;
        }
        
        data->elements[data->next++] = element;
        
    }
    
    MemoryContextSwitchTo(oldcontext);
    
    PG_RETURN_POINTER(data);

}
Exemplo n.º 4
0
Datum
count_distinct_combine(PG_FUNCTION_ARGS)
{
    int i;
    char *data, *tmp, *ptr1, *ptr2, *prev;
    element_set_t *eset1;
    element_set_t *eset2;
    MemoryContext agg_context;
    MemoryContext old_context;

    GET_AGG_CONTEXT("count_distinct_combine", fcinfo, agg_context);

    eset1 = PG_ARGISNULL(0) ? NULL : (element_set_t *) PG_GETARG_POINTER(0);
    eset2 = PG_ARGISNULL(1) ? NULL : (element_set_t *) PG_GETARG_POINTER(1);

    if (eset2 == NULL)
        PG_RETURN_POINTER(eset1);

    if (eset1 == NULL)
    {
        old_context = MemoryContextSwitchTo(agg_context);

        eset1 = (element_set_t *)palloc(sizeof(element_set_t));
        eset1->item_size = eset2->item_size;
        eset1->nsorted = eset2->nsorted;
        eset1->nall = eset2->nall;
        eset1->nbytes = eset2->nbytes;

        eset1->data = palloc(eset1->nbytes);

        memcpy(eset1->data, eset2->data, eset1->nbytes);

        MemoryContextSwitchTo(old_context);

        PG_RETURN_POINTER(eset1);
    }

    Assert((eset1 != NULL) && (eset2 != NULL));
    Assert((eset1->item_size > 0) && (eset1->item_size == eset2->item_size));

    /* make sure both states are sorted */
    compact_set(eset1, false);
    compact_set(eset2, false);

    data = MemoryContextAlloc(agg_context, (eset1->nbytes + eset2->nbytes));
    tmp = data;

    /* merge the two arrays */
    ptr1 = eset1->data;
    ptr2 = eset2->data;
    prev = NULL;

    for (i = 0; i < eset1->nall + eset2->nall; i++)
    {
        char *element;

        Assert(ptr1 <= (eset1->data + eset1->nbytes));
        Assert(ptr2 <= (eset2->data + eset2->nbytes));

        if ((ptr1 < (eset1->data + eset1->nbytes)) &&
            (ptr2 < (eset2->data + eset2->nbytes)))
        {
            if (memcmp(ptr1, ptr2, eset1->item_size) <= 0)
            {
                element = ptr1;
                ptr1 += eset1->item_size;
            }
            else
            {
                element = ptr2;
                ptr2 += eset1->item_size;
            }
        }
        else if (ptr1 < (eset1->data + eset1->nbytes))
        {
            element = ptr1;
            ptr1 += eset1->item_size;
        }
        else if (ptr2 < (eset2->data + eset2->nbytes))
        {
            element = ptr2;
            ptr2 += eset2->item_size;
        }
        else
            elog(ERROR, "unexpected");

        /*
         * Now figure out what to do with the element - we need to compare it
         * to the last value, and only keep it if it's different (and it better
         * be greater than the last value).
         */
        if (tmp == data)
        {
            /* first value, so just copy */
            memcpy(tmp, element, eset1->item_size);
            prev = tmp;
            tmp += eset1->item_size;
        }
        else if (memcmp(prev, element, eset1->item_size) != 0)
        {
            /* not equal to the last one, so should be greater */
            Assert(memcmp(prev, element, eset1->item_size) < 0);

            /* first value, so just copy */
            memcpy(tmp, element, eset1->item_size);
            prev = tmp;
            tmp += eset1->item_size;
        }
    }

    /* we must have processed the input arrays completely */
    Assert(ptr1 == (eset1->data + (eset1->nall * eset1->item_size)));
    Assert(ptr2 == (eset2->data + (eset2->nall * eset2->item_size)));

    /* we might have eliminated some duplicate elements */
    Assert((tmp - data) <= ((eset1->nall + eset2->nall) * eset1->item_size));

    pfree(eset1->data);
    eset1->data = data;

    /* and finally compute the current number of elements */
    eset1->nbytes = tmp - data;
    eset1->nall = eset1->nbytes / eset1->item_size;
    eset1->nsorted = eset1->nall;

    PG_RETURN_POINTER(eset1);
}
Exemplo n.º 5
0
Datum
count_distinct_elements_append(PG_FUNCTION_ARGS)
{
    int             i;
    element_set_t  *eset = NULL;

    /* info for anyarray */
    Oid input_type;
    Oid element_type;

    /* array data */
    ArrayType  *input;
    int         ndims;
    int        *dims;
    int         nitems;
    bits8      *null_bitmap;
    char       *arr_ptr;
    Datum       element;

    /* memory contexts */
    MemoryContext oldcontext;
    MemoryContext aggcontext;

    /*
     * If the new value is NULL, we simply return the current aggregate state
     * (it might be NULL, so check it). In this case we don't really care about
     * the types etc.
     *
     * We may still get NULL elements in the array, but to check that we would
     * have to walk the array, which does not qualify as cheap check. Also we
     * assume that there's at least one non-NULL element, and we'll walk the
     * array just once. It's possible we'll get empty set this way.
     */
    if (PG_ARGISNULL(1) && PG_ARGISNULL(0))
        PG_RETURN_NULL();
    else if (PG_ARGISNULL(1))
        PG_RETURN_DATUM(PG_GETARG_DATUM(0));

    /* from now on we know the new value is not NULL */

    /* get the type of array elements */
    input_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
    element_type = get_element_type(input_type);

    /*
     * parse the array contents (we know we got non-NULL value)
     */
    input = PG_GETARG_ARRAYTYPE_P(1);
    ndims = ARR_NDIM(input);
    dims = ARR_DIMS(input);
    nitems = ArrayGetNItems(ndims, dims);
    null_bitmap = ARR_NULLBITMAP(input);
    arr_ptr = ARR_DATA_PTR(input);

    /* make sure we're running as part of aggregate function */
    GET_AGG_CONTEXT("count_distinct_elements_append", fcinfo, aggcontext);

    oldcontext = MemoryContextSwitchTo(aggcontext);

    /* add all array elements to the set */
    for (i = 0; i < nitems; i++)
    {
        /* ignore nulls */
        if (null_bitmap && !(null_bitmap[i / 8] & (1 << (i % 8))))
            continue;

        /* init the hash table, if needed */
        if (eset == NULL)
        {
            if (PG_ARGISNULL(0))
            {
                int16       typlen;
                bool        typbyval;
                char        typalign;

                /* get type information for the second parameter (anyelement item) */
                get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);

                /* we can't handle varlena types yet or values passed by reference */
                if ((typlen < 0) || (! typbyval))
                    elog(ERROR, "count_distinct_elements handles only arrays of fixed-length types passed by value");

                eset = init_set(typlen, typalign, aggcontext);
            }
            else
                eset = (element_set_t *)PG_GETARG_POINTER(0);
        }

        element = fetch_att(arr_ptr, true, eset->item_size);

        add_element(eset, (char*)&element);

        /* advance array pointer */
        arr_ptr = att_addlength_pointer(arr_ptr, eset->item_size, arr_ptr);
        arr_ptr = (char *) att_align_nominal(arr_ptr, eset->typalign);
    }

    MemoryContextSwitchTo(oldcontext);

    if (eset == NULL)
        PG_RETURN_NULL();
    else
        PG_RETURN_POINTER(eset);
}