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@antarkt.is>
> To: pgsql-general@postgresql.org
> 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@postgresql.org)
> 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
negativein database"); } }
return (uint32_t *)int_arr;
}
--
Sent via pgsql-general mailing list (pgsql-general@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general