Search Postgresql Archives

Re: Fwd: SPI_palloc problem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, Oct 29, 2017, at 07:40 PM, Aron Widforss wrote:
> I mailed this from my main email address instead of the one I'm
> subscribed to pgsql-general with. So, here goes.
> 
> ----- Original message -----
> From: Aron Widforss <aron@xxxxxxxxxx>
> To: pgsql-general@xxxxxxxxxxxxxx
> Subject: SPI_palloc problem
> Date: Sun, 29 Oct 2017 19:35:30 +0100
> 
> Good evening,
> 
> I'm really new to PostgreSQL, and even C, but am trying to put together
> a small pathfinding module to learn about it. Right now I'm just writing
> a function to load my graph into a convenient data structure to use
> later. I'm currently just loading the data of each vertice into my data
> structure and then printing the loaded position out with elog(). It
> works, but when I try to use SPI_palloc instead of palloc it disconnects
> every time.
> 
> I suspect that my bug is really trivial, so maybe someone on this list
> can just see what it is in the code and save me some time. :)
> 
> Regards,
> Aron Widforss
> 
> Here is my version, example data and program:
> 
> pathfinding-hike=# SELECT version();
>                                                      version             
> -----------------------------------------------------------------------------------------------------------------
>  PostgreSQL 9.5.9 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu
>  5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609, 64-bit
> (1 row)
> 
> ----
> 
> pathfinding-hike=# SELECT * FROM toc LIMIT 10;
>  node |       pos        | connected  |    length     |     costs     | 
>   lines    
> ------+------------------+------------+---------------+---------------+------------
>     1 | {268582,6528365} | {2}        | {297}         | {297}         |
>     {1}
>     2 | {268773,6528472} | {1}        | {297}         | {297}         |
>     {1}
>     3 | {269103,6534918} | {15}       | {676}         | {676}         |
>     {2}
>     4 | {269436,6534931} | {12}       | {263}         | {263}         |
>     {4}
>     5 | {269521,6534450} | {11}       | {373}         | {373}         |
>     {6}
>     6 | {269535,6536629} | {28,22,7}  | {894,1508,66} | {894,1508,66} |
>     {7,3,8}
>     7 | {269542,6536693} | {6,9,9}    | {66,657,218}  | {66,657,218}  |
>     {8,5,9}
>     8 | {269585,6535610} | {14}       | {70}          | {70}          |
>     {10}
>     9 | {269631,6536886} | {7,7,36}   | {657,218,584} | {657,218,584} |
>     {5,9,11}
>    10 | {269642,6534754} | {12,20,11} | {137,140,6}   | {137,140,6}   |
>    {12,13,14}
> (10 rows)
> 
> ----
> 
> #include "postgres.h"
> #include "utils/array.h"
> #include "utils/lsyscache.h"
> #include "catalog/pg_type.h"
> #include "executor/spi.h"
> #include "utils/builtins.h"
> 
> int check_err(int code);
> int check_err(int code)
> {
>     if(code < 0) {
>         elog(ERROR, "%m");
>     }
>     return code;
> }
> 
> int32_t * get_int_arr(HeapTuple tuple, TupleDesc rowdesc, int fnumber);
> int32_t * get_int_arr(HeapTuple tuple, TupleDesc rowdesc, int fnumber)
> {
>     Datum     raw_arr;
>     ArrayType *pg_arr;
>     Datum     *c_arr;
>     bool      isnull;
>     /* Parameters for data alignment */
>     Oid       eltype;
>     int16     typlen;
>     bool      typbyval;
>     char      typalign;
>     /* Info about unwrapped array */
>     int32_t   *int_arr;
>     int       arr_len;
>     int       arr_dim;
> 
>     /* Get array raw-format */
>     raw_arr = SPI_getbinval(tuple, rowdesc, fnumber, &isnull);
>     check_err(SPI_result);
>     if(isnull) {
>         elog(ERROR, "Cannot deconstruct null array");
>     }
> 
>     /* Get array db-format */
>     pg_arr  = DatumGetArrayTypeP(raw_arr);
>     arr_dim = ARR_NDIM(pg_arr);
>     eltype  = ARR_ELEMTYPE(pg_arr);
>     //TODO: More thorough type checking has to be done in plpgsql
>     if(eltype != INT4OID) {
>         elog(ERROR, "Array not of type Integer");
>     }
> 
>     /* Get array as C-array (length prepended to 1st element) */
>     get_typlenbyvalalign(eltype, &typlen, &typbyval, &typalign);
>     if(arr_dim != 1) {
>         elog(ERROR, "Cannot interpret multidimensional arrays");
>     }
>     deconstruct_array(pg_arr, eltype, typlen, typbyval, typalign,
>                       &c_arr, NULL, &arr_len);
>     int_arr = palloc((arr_len+1)*sizeof(int32_t));
>     for(int i = 0; i<arr_len; i++) {
>         int_arr[i+1] = DatumGetInt32(c_arr[i]);
>     }
>     int_arr[0] = arr_len+1;
> 
>     return int_arr;
> }
>     
> uint32_t * get_uint_arr(HeapTuple tuple, TupleDesc rowdesc, int
> fnumber);
> uint32_t * get_uint_arr(HeapTuple tuple, TupleDesc rowdesc, int fnumber)
> {
>     int32_t  *int_arr;
>     int_arr = get_int_arr(tuple, rowdesc, fnumber);
> 
>     for(int i = 1; i < int_arr[0]; i++) {
>         if(int_arr[i] < 0) {
>             elog(ERROR, "Unsigned int stored as negative in database");
>         }
>     }
> 
>     return (uint32_t *)int_arr;
> }
>                  
> PG_MODULE_MAGIC;
> 
> PG_FUNCTION_INFO_V1(astarc);
> Datum
> astarc(PG_FUNCTION_ARGS)
> {
>     int rows;
> 
>     typedef struct node node;
>     struct node {
>         int32_t *pos;
>         uint32_t *conn;
>         uint32_t *costs;
>         uint32_t *edges;
>     };
> 
>     struct node *graph;
> 
>     check_err(SPI_connect());
>     check_err(SPI_execute("SELECT * FROM toc", true, 10));
>     rows = SPI_processed;
> 
>     graph = palloc((rows + 1)*sizeof(node));
>     // Store size of array in first connected[]
>     graph[0].conn[0] = rows+1;
> 
>     if(rows > 0 && SPI_tuptable != NULL) {
>         TupleDesc tupdesc = SPI_tuptable->tupdesc;
>         SPITupleTable *tuptable = SPI_tuptable;
> 
>         for (uint32_t i = 0; i < rows; i++) {
>             HeapTuple tuple = tuptable->vals[i];
>             graph[i].pos   = get_int_arr(tuple, tupdesc, 2);
>             graph[i].conn  = get_uint_arr(tuple, tupdesc, 3);
>             graph[i].costs = get_uint_arr(tuple, tupdesc, 5);
>             graph[i].edges = get_uint_arr(tuple, tupdesc, 6);
> 
>             elog(INFO, "x: %i, y: %i", graph[i].pos[1],
>             graph[i].pos[2]);
>         }
>     }
> 
>     if(rows == 0) {
>         elog(ERROR, "Graph not found");
>     }
> 
>     check_err(SPI_finish());
> 
>     PG_RETURN_TEXT_P(cstring_to_text("test"));
> }
> 
> 
> -- 
> Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-general

After some sleep I attacked my problem again and resolved it myself. I
had some of by one errors, but the main problem seemed to be that I did
not allocate space for the elements of my first node, where I stored the
size of the graph array. I though that allocation was implicit in the
struct declaration, but apparently not. For the sake of completeness
I'll post my working code below.

Regards,
Aron Widforss

----

#include "postgres.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "utils/builtins.h"

typedef struct node {
    int32_t *pos;
    uint32_t *conn;
    uint32_t *costs;
    uint32_t *edges;
} node;

void delay(unsigned int secs);
int check_err(int code);
int32_t * get_int_arr(HeapTuple tuple, TupleDesc rowdesc, int fnumber);
uint32_t * get_uint_arr(HeapTuple tuple, TupleDesc rowdesc, int
fnumber);
node * load_graph(void);

PG_MODULE_MAGIC;

PG_FUNCTION_INFO_V1(astarc);
Datum
astarc(PG_FUNCTION_ARGS)
{
    struct node *graph;
    graph = load_graph();

    for(int i = 0; i < *(graph[0].pos); i++) {
        elog(INFO, "x: %i, y: %i", graph[i].pos[1], graph[i].pos[2]);
    }
    elog(INFO, "%i", *(graph[0].pos));

    for(int i = 1; i < graph[0].pos[0]; i++) {
        pfree(graph[i].pos);
        pfree(graph[i].conn);
        pfree(graph[i].costs);
        pfree(graph[i].edges);
    }
    pfree(graph);

    PG_RETURN_TEXT_P(cstring_to_text("test"));
}

node * load_graph(void) {
    int rows;
    struct node *graph;

    check_err(SPI_connect());
    check_err(SPI_execute("SELECT * FROM toc", true, 10));
    rows = SPI_processed;
    elog(INFO, "%i", rows);

    graph = SPI_palloc((rows + 1)*sizeof(node));
    // Store size of array in first connected[]
    graph[0].pos = SPI_palloc(sizeof(int32_t));
    graph[0].conn = SPI_palloc(sizeof(uint32_t));
    graph[0].costs = SPI_palloc(sizeof(uint32_t));
    graph[0].edges = SPI_palloc(sizeof(uint32_t));
    *(graph[0].pos) = rows+1;
    *(graph[0].conn) = 0;
    *(graph[0].costs) = 0;
    *(graph[0].edges) = 0;

    if(rows > 0 && SPI_tuptable != NULL) {
        TupleDesc tupdesc = SPI_tuptable->tupdesc;
        SPITupleTable *tuptable = SPI_tuptable;

        for (uint32_t i = 0; i < rows; i++) {
            HeapTuple tuple = tuptable->vals[i];
            graph[i+1].pos   = get_int_arr(tuple, tupdesc, 2);
            graph[i+1].conn  = get_uint_arr(tuple, tupdesc, 3);
            graph[i+1].costs = get_uint_arr(tuple, tupdesc, 5);
            graph[i+1].edges = get_uint_arr(tuple, tupdesc, 6);
        }
    }

    if(rows == 0) {
        elog(ERROR, "Graph not found");
    }

    check_err(SPI_finish());

    return graph;
}

int check_err(int code)
{
    if(code < 0) {
        elog(ERROR, "%m");
    }
    return code;
}

int32_t * get_int_arr(HeapTuple tuple, TupleDesc rowdesc, int fnumber)
{
    Datum     raw_arr;
    ArrayType *pg_arr;
    Datum     *c_arr;
    bool      isnull;
    /* Parameters for data alignment */
    Oid       eltype;
    int16     typlen;
    bool      typbyval;
    char      typalign;
    /* Info about unwrapped array */
    int32_t   *int_arr;
    int       arr_len;
    int       arr_dim;

    /* Get array raw-format */
    raw_arr = SPI_getbinval(tuple, rowdesc, fnumber, &isnull);
    check_err(SPI_result);
    if(isnull) {
        elog(ERROR, "Cannot deconstruct null array");
    }

    /* Get array db-format */
    pg_arr  = DatumGetArrayTypeP(raw_arr);
    arr_dim = ARR_NDIM(pg_arr);
    eltype  = ARR_ELEMTYPE(pg_arr);
    //TODO: More thorough type checking has to be done in plpgsql
    if(eltype != INT4OID) {
        elog(ERROR, "Array not of type Integer");
    }

    /* Get array as C-array (length prepended to 1st element) */
    get_typlenbyvalalign(eltype, &typlen, &typbyval, &typalign);
    if(arr_dim != 1) {
        elog(ERROR, "Cannot interpret multidimensional arrays");
    }
    deconstruct_array(pg_arr, eltype, typlen, typbyval, typalign,
                      &c_arr, NULL, &arr_len);
    int_arr = SPI_palloc((arr_len+1)*sizeof(int32_t));
    for(int i = 0; i<arr_len; i++) {
        int_arr[i+1] = DatumGetInt32(c_arr[i]);
    }
    int_arr[0] = arr_len+1;

    return int_arr;
}
    
uint32_t * get_uint_arr(HeapTuple tuple, TupleDesc rowdesc, int fnumber)
{
    int32_t  *int_arr;
    int_arr = get_int_arr(tuple, rowdesc, fnumber);

    for(int i = 1; i < int_arr[0]; i++) {
        if(int_arr[i] < 0) {
            elog(ERROR, "Unsigned int stored as negative in database");
        }
    }

    return (uint32_t *)int_arr;
}


-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]

  Powered by Linux