Thread: C function returns null values
Hello all,
I developed a C function which returns a record. The record contains 3 scalar values and 2 arrays. Randomly some record elements are null and I wonder why. I could trace down the problem to the point where the return record is created. Until this point everything is computed correctly. Below you see an excerpt of the relevant code. I use PostGres 8.4 on Ubuntu 10.10 (x64).
typedef struct {
// Size of the array
int size;
// Values of the array
double *values;
} array_d;
// Integer
typedef struct {
// Size of the array
int size;
// Values of the array
int *values;
} array_i;
typedef struct {
interval_orders o;
array_d *interval_weights;
array_d *interval_borders;
array_i *add_weights;
double b;
} c_param_type;
void create_dati_from_result(Datum *values, c_param_type *param) {
// Array creation
ArrayType *weights, *borders;
Datum *weights_elem;
Datum *borders_elem;
int16 typlen;
bool typbyval;
char typalign;
int i;
// Set values
values[0] = Float8GetDatum(param->o.interval_weight);
values[1] = Float8GetDatum(param->o.quantitiy);
values[2] = Float8GetDatum(param->o.long_sql);
// Create datum arrays
weights_elem = palloc(param->interval_weights->size * sizeof (Datum));
borders_elem = palloc(param->interval_borders->size * sizeof (Datum));
for (i = 0; i < param->interval_weights->size; i++) {
weights_elem[i] = Float8GetDatum((float8) param->interval_weights->values[i]);
}
for (i = 0; i < param->interval_borders->size; i++) {
borders_elem[i] = Float8GetDatum((float8) param->interval_borders->values[i]);
}
// Create array type
get_typlenbyvalalign(FLOAT8OID, &typlen, &typbyval, &typalign);
weights = construct_array(weights_elem, param->interval_weights->size, FLOAT8OID, typlen, typbyval, typalign);
borders = construct_array(borders_elem, param->interval_borders->size, FLOAT8OID, typlen, typbyval, typalign);
values[3] = PointerGetDatum(borders);
values[4] = PointerGetDatum(weights);
}
PG_FUNCTION_INFO_V1(insert_order);
Datum insert_order(PG_FUNCTION_ARGS) {
// Variable declarations go here
// …
// vars for result
TupleDesc tupdesc;
Datum *values;
bool *nulls;
int tuplen,i;
HeapTuple res_tuple;
// Look whether everything has been provided
if (PG_ARGISNULL(0)) {
ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("First argument is NULL")));
PG_RETURN_NULL();
}
// Allocate memory
param = palloc(sizeof (c_param_type));
// Get the HeapTupleHeader
header = PG_GETARG_HEAPTUPLEHEADER_COPY(0);
// Extract information from parameter
if (!extract_information(param, header)) {
PG_RETURN_NULL();
}
// Some more code goes here
// …
// Set values
param->o.long_sql = total_cost;
param->o.quantitiy = weight;
param->o.interval_weight = weight;
// Create result tuple
values = palloc(sizeof(Datum)*5);
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_SUCCESSFUL_COMPLETION), errmsg("function returning record called in context that cannot accept type record")));
// Get Dati
create_dati_from_result(values, param);
// Init Tuple Desc
tupdesc = BlessTupleDesc(tupdesc);
// Size
tuplen = tupdesc->natts;
// Allocate enough memory for nulls
nulls = palloc(tuplen * sizeof (bool));
// Create tuple
res_tuple = heap_form_tuple(tupdesc, values, nulls);
// Free allocated memory
pfree(nulls);
// Return result
PG_RETURN_DATUM(HeapTupleGetDatum(res_tuple));
}
I hope you can help me.
Regards,
Gregor
Gregor Trefs <gregor.trefs@delphit.com> writes: > I developed a C function which returns a record. The record contains 3 scalar values and 2 arrays. Randomly some recordelements are null and I wonder why. I could trace down the problem to the point where the return record is created.Until this point everything is computed correctly. Below you see an excerpt of the relevant code. I use PostGres8.4 on Ubuntu 10.10 (x64). You're not bothering to fill in the nulls[] array: > // Allocate enough memory for nulls > nulls = palloc(tuplen * sizeof (bool)); > // Create tuple > res_tuple = heap_form_tuple(tupdesc, values, nulls); palloc0 would work better here. BTW, it's a good idea to develop/test C code in a backend built with --enable-debug --enable-cassert. Had you been doing so, palloc would have given you back intentionally-garbage-filled memory, and you'd have noticed the mistake immediately. regards, tom lane
Thanks for your answer. I edited my code, but still get these random null values. What else can I do ? Regards -----Ursprüngliche Nachricht----- Von: Tom Lane [mailto:tgl@sss.pgh.pa.us] Gesendet: Freitag, 15. Juli 2011 16:24 An: Gregor Trefs Cc: pgsql-general@postgresql.org Betreff: Re: [GENERAL] C function returns null values Gregor Trefs <gregor.trefs@delphit.com> writes: > I developed a C function which returns a record. The record contains 3 scalar values and 2 arrays. Randomly some recordelements are null and I wonder why. I could trace down the problem to the point where the return record is created.Until this point everything is computed correctly. Below you see an excerpt of the relevant code. I use PostGres8.4 on Ubuntu 10.10 (x64). You're not bothering to fill in the nulls[] array: > // Allocate enough memory for nulls > nulls = palloc(tuplen * sizeof (bool)); > // Create tuple > res_tuple = heap_form_tuple(tupdesc, values, nulls); palloc0 would work better here. BTW, it's a good idea to develop/test C code in a backend built with --enable-debug --enable-cassert. Had you been doingso, palloc would have given you back intentionally-garbage-filled memory, and you'd have noticed the mistake immediately. regards, tom lane
Gregor Trefs <gregor.trefs@delphit.com> writes: > Thanks for your answer. I edited my code, but still get these random null values. What else can I do ? Mph ... you're aware that you have to start a fresh session to load a new version of a .so into the backend? regards, tom lane
Well, yes. I wrote a little make file which takes care of this part (except restarting the session): INCLUDEDIRS += -I$(shell pg_config --includedir-server) LIBDIR = -L$(shell pg_config --libdir) LIBINSTALL = $(shell pg_config --pkglibdir) integrated_c.so: integrated_c.c Makefile gcc -fpic -o integrated_c.o -c integrated_c.c $(INCLUDEDIRS) gcc -shared -o integrated_c.so integrated_c.o $(LIBDIR) -lmpfr -lgmp cp integrated_c.so $(LIBINSTALL) -----Ursprüngliche Nachricht----- Von: Tom Lane [mailto:tgl@sss.pgh.pa.us] Gesendet: Montag, 18. Juli 2011 16:33 An: Gregor Trefs Cc: pgsql-general@postgresql.org Betreff: Re: [GENERAL] C function returns null values Gregor Trefs <gregor.trefs@delphit.com> writes: > Thanks for your answer. I edited my code, but still get these random null values. What else can I do ? Mph ... you're aware that you have to start a fresh session to load a new version of a .so into the backend? regards, tom lane
Finally I got it working. You were right Tom Lane. I actually did not copy the corrected source file onto the server andthus still had this "mysterious" failure. So, palloc0 is the solution. Thanks again. Regards, Gregor Trefs -----Ursprüngliche Nachricht----- Von: pgsql-general-owner@postgresql.org [mailto:pgsql-general-owner@postgresql.org] Im Auftrag von Gregor Trefs Gesendet: Montag, 18. Juli 2011 17:20 Cc: pgsql-general@postgresql.org Betreff: Re: [GENERAL] C function returns null values Well, yes. I wrote a little make file which takes care of this part (except restarting the session): INCLUDEDIRS += -I$(shell pg_config --includedir-server) LIBDIR = -L$(shell pg_config --libdir) LIBINSTALL = $(shell pg_config--pkglibdir) integrated_c.so: integrated_c.c Makefile gcc -fpic -o integrated_c.o -c integrated_c.c $(INCLUDEDIRS) gcc -shared -o integrated_c.so integrated_c.o $(LIBDIR) -lmpfr -lgmp cp integrated_c.so $(LIBINSTALL) -----Ursprüngliche Nachricht----- Von: Tom Lane [mailto:tgl@sss.pgh.pa.us] Gesendet: Montag, 18. Juli 2011 16:33 An: Gregor Trefs Cc: pgsql-general@postgresql.org Betreff: Re: [GENERAL] C function returns null values Gregor Trefs <gregor.trefs@delphit.com> writes: > Thanks for your answer. I edited my code, but still get these random null values. What else can I do ? Mph ... you're aware that you have to start a fresh session to load a new version of a .so into the backend? regards, tom lane -- Sent via pgsql-general mailing list (pgsql-general@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-general