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