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 <[email protected]>
> To: [email protected]
> 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 ([email protected])
> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general