Обсуждение: Return setof values from C-function

Поиск
Список
Период
Сортировка

Return setof values from C-function

От
Yuriy Rusinov
Дата:
Dear Colleagues !

I have to return setof values from C-function

I wrote

    FuncCallContext *funcctx;
    int call_cntr;
    int max_calls;
    AttInMetadata *attinmeta;
    unsigned long il;
    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext   oldcontext;
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        funcctx->max_calls = num;
        if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));
        attinmeta = 0;//TupleDescGetAttInMetadata(tupdesc);
        funcctx->attinmeta = 0;//attinmeta;
        MemoryContextSwitchTo(oldcontext);
        funcctx->tuple_desc = BlessTupleDesc( tupdesc );
        elog (INFO, "1st row");
    }
    funcctx = SRF_PERCALL_SETUP();
    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    attinmeta = funcctx->attinmeta;
    HeapTuple tuple;
    if (call_cntr < max_calls)
    {
        elog (INFO, "Rows");
        unsigned long il = call_cntr;
        Datum * hvalues = (Datum *)palloc (2*sizeof(Datum));
        double val = gsl_histogram_get (gHist, il);
        hvalues[0] = UInt32GetDatum (il);
        hvalues[1] = Float8GetDatum (val);
        bool * nulls = palloc( 2 * sizeof( bool ) );

        elog (INFO, "%lu", il);
        tuple = heap_form_tuple( tupdesc, hvalues, nulls);
        elog (INFO, "%lu", il);
        //BuildTupleFromCStrings (attinmeta, hvalues);
        pfree (nulls);
        pfree (hvalues);
        SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum( tuple ) );
    }
    else
    {
        SRF_RETURN_DONE(funcctx);
    }
as written in documentation, but my function drops on 
tuple = heap_form_tuple( tupdesc, hvalues, nulls);
Could you tell me, are there any errors ?

--
Best regards,
Sincerely yours,
Yuriy Rusinov.

Re: Return setof values from C-function

От
Merlin Moncure
Дата:
On Tue, Dec 10, 2013 at 1:30 AM, Yuriy Rusinov <yrusinov@gmail.com> wrote:
> Dear Colleagues !
>
> I have to return setof values from C-function
>
> I wrote
>
>     FuncCallContext *funcctx;
>     int call_cntr;
>     int max_calls;
>     AttInMetadata *attinmeta;
>     unsigned long il;
>     if (SRF_IS_FIRSTCALL())
>     {
>         MemoryContext   oldcontext;
>         funcctx = SRF_FIRSTCALL_INIT();
>         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
>         funcctx->max_calls = num;
>         if (get_call_result_type(fcinfo, NULL, &tupdesc) !=
> TYPEFUNC_COMPOSITE)
>             ereport(ERROR,
>                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
>                      errmsg("function returning record called in context "
>                             "that cannot accept type record")));
>         attinmeta = 0;//TupleDescGetAttInMetadata(tupdesc);
>         funcctx->attinmeta = 0;//attinmeta;
>         MemoryContextSwitchTo(oldcontext);
>         funcctx->tuple_desc = BlessTupleDesc( tupdesc );
>         elog (INFO, "1st row");
>     }
>     funcctx = SRF_PERCALL_SETUP();
>     call_cntr = funcctx->call_cntr;
>     max_calls = funcctx->max_calls;
>     attinmeta = funcctx->attinmeta;
>     HeapTuple tuple;
>     if (call_cntr < max_calls)
>     {
>         elog (INFO, "Rows");
>         unsigned long il = call_cntr;
>         Datum * hvalues = (Datum *)palloc (2*sizeof(Datum));
>         double val = gsl_histogram_get (gHist, il);
>         hvalues[0] = UInt32GetDatum (il);
>         hvalues[1] = Float8GetDatum (val);
>         bool * nulls = palloc( 2 * sizeof( bool ) );
>
>         elog (INFO, "%lu", il);
>         tuple = heap_form_tuple( tupdesc, hvalues, nulls);
>         elog (INFO, "%lu", il);
>         //BuildTupleFromCStrings (attinmeta, hvalues);
>         pfree (nulls);
>         pfree (hvalues);
>         SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum( tuple ) );
>     }
>     else
>     {
>         SRF_RETURN_DONE(funcctx);
>     }
> as written in documentation, but my function drops on
> tuple = heap_form_tuple( tupdesc, hvalues, nulls);
> Could you tell me, are there any errors ?

Where is 'tupdesc' coming from.  Don't you need to copy it from the
function context?

merlin


Re: Return setof values from C-function

От
Yuriy Rusinov
Дата:
I have added code

        Oid * oids = (Oid *)palloc (2*sizeof (Oid));
        oids[0] = INT8OID;
        oids[1] = FLOAT8OID;
        if (get_call_result_type(fcinfo, oids, &tupdescRes) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));

and try to obtain tupdescRes  from get_call_result_type function, before this I do 

create type hist_point as (inum bigint, bin float8);
 and
create or replace function histogram (varchar, float8, float8, int4) returns setof hist_point
    as '$libdir/libfloader.so', 'histogram' language 'c' strict security definer;

but the result does not obtained.


On Tue, Dec 10, 2013 at 7:33 PM, Merlin Moncure <mmoncure@gmail.com> wrote:
On Tue, Dec 10, 2013 at 1:30 AM, Yuriy Rusinov <yrusinov@gmail.com> wrote:
> Dear Colleagues !
>
> I have to return setof values from C-function
>
> I wrote
>
>     FuncCallContext *funcctx;
>     int call_cntr;
>     int max_calls;
>     AttInMetadata *attinmeta;
>     unsigned long il;
>     if (SRF_IS_FIRSTCALL())
>     {
>         MemoryContext   oldcontext;
>         funcctx = SRF_FIRSTCALL_INIT();
>         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
>         funcctx->max_calls = num;
>         if (get_call_result_type(fcinfo, NULL, &tupdesc) !=
> TYPEFUNC_COMPOSITE)
>             ereport(ERROR,
>                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
>                      errmsg("function returning record called in context "
>                             "that cannot accept type record")));
>         attinmeta = 0;//TupleDescGetAttInMetadata(tupdesc);
>         funcctx->attinmeta = 0;//attinmeta;
>         MemoryContextSwitchTo(oldcontext);
>         funcctx->tuple_desc = BlessTupleDesc( tupdesc );
>         elog (INFO, "1st row");
>     }
>     funcctx = SRF_PERCALL_SETUP();
>     call_cntr = funcctx->call_cntr;
>     max_calls = funcctx->max_calls;
>     attinmeta = funcctx->attinmeta;
>     HeapTuple tuple;
>     if (call_cntr < max_calls)
>     {
>         elog (INFO, "Rows");
>         unsigned long il = call_cntr;
>         Datum * hvalues = (Datum *)palloc (2*sizeof(Datum));
>         double val = gsl_histogram_get (gHist, il);
>         hvalues[0] = UInt32GetDatum (il);
>         hvalues[1] = Float8GetDatum (val);
>         bool * nulls = palloc( 2 * sizeof( bool ) );
>
>         elog (INFO, "%lu", il);
>         tuple = heap_form_tuple( tupdesc, hvalues, nulls);
>         elog (INFO, "%lu", il);
>         //BuildTupleFromCStrings (attinmeta, hvalues);
>         pfree (nulls);
>         pfree (hvalues);
>         SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum( tuple ) );
>     }
>     else
>     {
>         SRF_RETURN_DONE(funcctx);
>     }
> as written in documentation, but my function drops on
> tuple = heap_form_tuple( tupdesc, hvalues, nulls);
> Could you tell me, are there any errors ?

Where is 'tupdesc' coming from.  Don't you need to copy it from the
function context?

merlin



--
Best regards,
Sincerely yours,
Yuriy Rusinov.

Re: Return setof values from C-function

От
Merlin Moncure
Дата:
On Tue, Dec 10, 2013 at 9:44 AM, Yuriy Rusinov <yrusinov@gmail.com> wrote:
> I have added code
>
>         Oid * oids = (Oid *)palloc (2*sizeof (Oid));
>         oids[0] = INT8OID;
>         oids[1] = FLOAT8OID;
>         if (get_call_result_type(fcinfo, oids, &tupdescRes) !=
> TYPEFUNC_COMPOSITE)
>             ereport(ERROR,
>                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
>                      errmsg("function returning record called in context "
>                             "that cannot accept type record")));
>
> and try to obtain tupdescRes  from get_call_result_type function, before
> this I do
>
> create type hist_point as (inum bigint, bin float8);
>  and
> create or replace function histogram (varchar, float8, float8, int4) returns
> setof hist_point
>     as '$libdir/libfloader.so', 'histogram' language 'c' strict security
> definer;
>
> but the result does not obtained.

what error are you getting?  Also, I think you are not properly
initializing NULLs array -- that could be your issue.

merlin


Re: Return setof values from C-function

От
Yuriy Rusinov
Дата:
I have received an error
The connection to the server was lost. Attempting reset: Failed

This problem was solved using by C-strings instead of Datum

such as

    FuncCallContext *funcctx;
    int call_cntr;
    int max_calls;
    AttInMetadata *attinmeta;
    unsigned long il;
    TupleDesc tupdescRes;
    gsl_histogram * gHist;
    if (SRF_IS_FIRSTCALL())
    {
        size_t nr_rand = strlen ( VARDATA (PG_GETARG_VARCHAR_P(0)));
        char * sql = (char *) palloc (nr_rand+1);
    //    strncpy (sql, (char *)PG_GETARG_VARCHAR_P(0), nr_rand);
        snprintf (sql, nr_rand+1, "%s", VARDATA (PG_GETARG_VARCHAR_P (0)));
        float8 xmin = PG_GETARG_FLOAT8 (1);
        float8 xmax = PG_GETARG_FLOAT8 (2);
        unsigned int num = PG_GETARG_UINT32(3);

        //float8 * result = (float8 *) (palloc (sizeof(float8)));

        //*result= 5.0;

        gHist = gsl_histogram_alloc (num);
        elog (INFO, "query = %s\n", sql);
        gsl_histogram_set_ranges_uniform (gHist, (double)xmin, (double)xmax);
    //    Datum d = PointerGetDatum (gHist);
        SPI_connect ();
        int retVal = SPI_execute (sql, true, 0);
        if (retVal != SPI_OK_SELECT)
        {
            elog (ERROR, "Cannot load values");
            SPI_finish ();
            PG_RETURN_NULL();
        }
        elog (INFO, "%d\n", retVal);
        unsigned long int nproc = SPI_processed;
        elog (INFO, "number of points is %lu, number of bins is %u", nproc, num);
    //    SPI_finish ();
    //    pfree (sql);
    //    PG_RETURN_NULL();
        int i=0;

        TupleDesc tupdesc = SPI_tuptable->tupdesc;
        for (; i< nproc; i++)
        {
            HeapTuple tuple = SPI_tuptable->vals[i];
            int ncolbuf = 1;
            char * x_str = SPI_getvalue (tuple, tupdesc, ncolbuf);
            if (!x_str)
                continue;
            double x= atof (x_str);
            //elog (INFO, "value=%f", x);
            int res = gsl_histogram_increment (gHist, x);
            if (res != 0)
            {
                elog (NOTICE, "Range error, value is %lf, min value is %lf, max value %lf", x, gsl_histogram_min(gHist), gsl_histogram_max (gHist) );
                continue;
            }
        }
        SPI_finish ();
        pfree (sql);
        elog (INFO, "Reading was completed\n");
        MemoryContext   oldcontext;
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        funcctx->max_calls = num;
        Oid * oids = (Oid *)palloc (2*sizeof (Oid));
        oids[0] = INT8OID;
        oids[1] = FLOAT8OID;
        if (get_call_result_type(fcinfo, oids, &tupdescRes) != TYPEFUNC_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("function returning record called in context "
                            "that cannot accept type record")));
        attinmeta = TupleDescGetAttInMetadata(tupdescRes);
        funcctx->attinmeta = attinmeta;
        MemoryContextSwitchTo(oldcontext);
        //funcctx->tuple_desc = BlessTupleDesc( tupdescRes );
        pfree (oids);
        elog (INFO, "1st row");
    }
    funcctx = SRF_PERCALL_SETUP();
    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    elog (INFO, "number of rows = %d, number of columns are %d", max_calls, tupdescRes->natts );
    attinmeta = funcctx->attinmeta;
    HeapTuple tuple;
    if (call_cntr < max_calls)
    {
        elog (INFO, "Rows");
        il = call_cntr;
        //Datum * hvalues = (Datum *)palloc (2*sizeof(Datum));

        char ** svals = (char **) palloc (2*sizeof (char*));
        svals [0] = (char *) palloc(5 * sizeof(char));
        svals [1] = (char *) palloc(20 * sizeof(char));
        double val = gsl_histogram_get (gHist, il);
        snprintf (svals[0], 5, "%lu", il);
        snprintf (svals[1], 20, "%lf", val);
        //hvalues[0] = UInt32GetDatum (il);
        //hvalues[1] = Float8GetDatum (val);
        bool * nulls = palloc( 2 * sizeof( bool ) );

        elog (INFO, "%lu", il);
        tuple = BuildTupleFromCStrings (attinmeta, svals);//heap_form_tuple( tupdescRes, hvalues, nulls);
        elog (INFO, "%lu", il);
        Datum result = HeapTupleGetDatum(tuple);
        pfree (nulls);
        pfree (svals[1]);
        pfree (svals[0]);
        pfree (svals);
        //pfree (hvalues);
        SRF_RETURN_NEXT(funcctx, result);//HeapTupleGetDatum( tuple ) );
    }
    else
    {
        SRF_RETURN_DONE(funcctx);
    }

Thanks a lot.

Yuriy Rusinov