Creating a PostgreSQL procedural language - Part 5 - Returning Results

March 15, 2020
Creating a PostgreSQL procedural language - Part 5 - Returning Results

This example will just be focusing on returning data from user defined functions, specifically returning a value as opposed to using OUT parameters.  The full code is on Github.

To quickly review, PL/Julia calls jl_eval_string() to execute Julia code and captures the returning jl_value_t data structure, which contains the result of the Julia code executed.  The result needs to be extracted from the jl_value_t data structure and then handled before returning the value to the calling SQL statement.

First we will create a helper function to convert a C string into the data type specified by the RETURN clause of the CREATE FUNCTION statement.

static Datum
cstring_to_type(char * input, Oid typeoid)
{
    HeapTuple typetuple;
    Form_pg_type pg_type_entry;
    Datum ret;

    typetuple = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0);
    pg_type_entry = (Form_pg_type) GETSTRUCT(typetuple);
    ret = OidFunctionCall3(pg_type_entry->typinput,
            CStringGetDatum(input), 0, -1);
    ReleaseSysCache(typetuple);
    PG_RETURN_DATUM(ret);
}

Let’s modify the user defined function test_julia() from before to now return a FLOAT4 value:

CREATE OR REPLACE FUNCTION test_julia(val INTEGER)
RETURNS FLOAT4 AS $$
    sqrt(val);
$$ LANGUAGE pljulia;

Now we will add some new code after calling jl_eval_string(). The results of the Julia code is captured and the jl_value_t structure needs to be examined to determine what kind of data is in it.  In this example, I only demonstrate how to check if the return type is floating point number.  If the returned data is verified to be a floating point (jl_float64_type), then convert it to a C string called buffer using a snprintf() call.

jl_value_t *ret;
ret = jl_eval_string(compiled_code);
if (jl_typeis(ret, jl_float64_type))
{
    double ret_unboxed = jl_unbox_float64(ret);

    buffer = (char *) palloc0((DOUBLE_LEN + 1) * sizeof(char));
    snprintf(buffer, DOUBLE_LEN, "%f", ret_unboxed);
}

We can now call the cstring_to_type() function with the results of jl_eval_string() copied into buffer and finally return from the user defined function.

PG_RETURN_DATUM(cstring_to_type(buffer, procedure_struct->prorettype));

Try executing the latest test_julia() user defined function again:

julia=# select test_julia(8);

test_julia
------------
2.828427
(1 row)

This is where I’ll stop blogging about PL/Julia development for the time being.  There are still a number of things left to do to make PL/Julia more robust and fully functional.  You may have also noticed various WARNING messages if you’ve been trying the code.  Please take a look at the issues list and feel free to try lending a hand.

Share this

Relevant Blogs

Random Data

This post continues from my report on Random Numbers. I have begun working on a random data generator so I want to run some tests to see whether different random...
December 03, 2020

More Blogs

Full-text search since PostgreSQL 8.3

Welcome to the third – and last – part of this blog series, exploring how the PostgreSQL performance evolved over the years. The first part looked at OLTP workloads, represented...
November 05, 2020

Números aleatorios

He estado trabajando gradualmente en el desarrollo desde cero de herramientas para probar el rendimiento de los sistemas de bases de datos de código abierto. Uno de los componentes de...
November 04, 2020