Crash on SRF execution
Hi
I'm attempting to program a simple SRF function but it constantly crashes (details and code below).
Any idea why?
Thanks!
-Itai
-------------------------------------------------------------
Environment
-------------------------------------------------------------
Ubunto: 14.04.2 (server)
PG Ver: PostgreSQL 9.4.1 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2, 64-bit
Install: deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main
Dev: postgresql-server-dev-9.4 (9.4.1-1.pgdg14.04+1)
-------------------------------------------------------------
Execution
-------------------------------------------------------------
select * from pg_srf();
INFO: ----------- data source -----------
INFO: value: 1203000000
INFO: is_even: 1
INFO: value: 1203000001
INFO: is_even: 0
...
INFO: value: 1203003998
INFO: is_even: 1
INFO: value: 1203003999
INFO: is_even: 0
INFO: ----------- data context -----------
INFO: call_cntr: 0
INFO: value: 1203000000
INFO: is_even: 1
INFO: call_cntr: 1
INFO: value: 1203000001
INFO: is_even: 0
INFO: call_cntr: 2
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
!>
-------------------------------------------------------------
pg_srf.h
-------------------------------------------------------------
#ifndef PGSRF_H
#define PGSRF_H
#include "fmgr.h"
// using int as bool due to a different issue (one prob. at a time)
typedef struct Number_tag
{
int value;
int is_even;
} Number;
typedef struct NumberList_tag
{
int length;
Number ** pp_numbers;
} NumberList;
extern Datum pg_srf(PG_FUNCTION_ARGS);
#endif
-------------------------------------------------------------
pg_srf.c
-------------------------------------------------------------
#include <postgres.h>
#include <access/htup_details.h>
#include <catalog/pg_type.h>
#include <funcapi.h>
#include "pg_srf.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PG_FUNCTION_INFO_V1(pg_srf);
Datum
pg_srf(PG_FUNCTION_ARGS)
{
int call_cntr, i, length, base_num;
Number * num;
NumberList * list;
HeapTuple rettuple;
FuncCallContext *funcctx;
MemoryContext oldcontext;
if (SRF_IS_FIRSTCALL())
{
length = 4000;
base_num = 1203000000;
list = (NumberList *)palloc(sizeof(NumberList));
list->pp_numbers = (Number **)palloc(sizeof(Number*) * length);
list->length = length;
i = 0;
for (; i < length; i++)
{
num = (Number *)palloc(sizeof(Number));
num->value = base_num + i;
num->is_even = ((base_num + i) % 2 == 0) ? 1 : 0;
list->pp_numbers[i] = num;
}
ereport(INFO, (errmsg("----------- data source -----------")));
i = 0;
for (; i < length; i++)
{
ereport(INFO, (errmsg("value: %d", list->pp_numbers[i]->value)));
ereport(INFO, (errmsg("is_even: %d", list->pp_numbers[i]->is_even)));
}
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
funcctx->user_fctx = list;
funcctx->max_calls = list->length;
if (get_call_result_type(fcinfo, NULL, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("check if sql function definition returns SETOF record")));
BlessTupleDesc(funcctx->tuple_desc);
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
list = funcctx->user_fctx;
call_cntr = funcctx->call_cntr;
if (call_cntr < funcctx->max_calls)
{
Datum retvals[2];
bool retnulls[2];
if (call_cntr == 0)
{
ereport(INFO, (errmsg("----------- data context -----------")));
}
ereport(INFO, (errmsg("call_cntr: %d", call_cntr)));
ereport(INFO, (errmsg("value: %d", list->pp_numbers[call_cntr]->value)));
retvals[0] = Int32GetDatum(list->pp_numbers[call_cntr]->value);
ereport(INFO, (errmsg("is_even: %d", list->pp_numbers[call_cntr]->is_even)));
retvals[1] = Int32GetDatum(list->pp_numbers[call_cntr]->is_even);
retnulls[0] = false;
retnulls[1] = false;
rettuple = heap_form_tuple(funcctx->tuple_desc, retvals, retnulls);
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(rettuple));
}
else
{
SRF_RETURN_DONE(funcctx);
}
}
-------------------------------------------------------------
Makefile
-------------------------------------------------------------
MODULES = pg_srf
OBJS = pg_srf.o
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
-------------------------------------------------------------
SQL
-------------------------------------------------------------
CREATE OR REPLACE FUNCTION
pg_srf(OUT value integer, OUT is_even integer)
RETURNS
SETOF record
AS
'pg_srf.so', 'pg_srf'
LANGUAGE
C
STRICT
IMMUTABLE;
Itai <itaid@outlook.com> writes:
I'm attempting to program a simple SRF function but it constantly crashes (details and code below).
Any idea why?
Looks like you're pallocing some stuff in the calling context (ie, a
short-lived context) during the first execution and expecting it to
still be there in later executions. You'd need to allocate those
data structures in the multi_call_memory_ctx instead.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2015-03-15 17:40:11 +0200, Itai wrote:
I'm attempting to program a simple SRF function but it constantly crashes (details and code below).
Any idea why?
if (SRF_IS_FIRSTCALL())
{
length = 4000;
base_num = 1203000000;
list = (NumberList *)palloc(sizeof(NumberList));
list->pp_numbers = (Number **)palloc(sizeof(Number*) * length);
list->length = length;
i = 0;
for (; i < length; i++)
{
num = (Number *)palloc(sizeof(Number));
num->value = base_num + i;
num->is_even = ((base_num + i) % 2 == 0) ? 1 : 0;
list->pp_numbers[i] = num;
}
ereport(INFO, (errmsg("----------- data source -----------")));
i = 0;
for (; i < length; i++)
{
ereport(INFO, (errmsg("value: %d", list->pp_numbers[i]->value)));
ereport(INFO, (errmsg("is_even: %d", list->pp_numbers[i]->is_even)));
}funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
funcctx->user_fctx = list;
funcctx->max_calls = list->length;
if (get_call_result_type(fcinfo, NULL, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("check if sql function definition returns SETOF record")));BlessTupleDesc(funcctx->tuple_desc);
MemoryContextSwitchTo(oldcontext);
}
The palloc() for list above is in the per call memory context, but you
use it across several calls. You should allocate it in the multi call
context you use some lines below.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Thanks for the quick response!! :)
But I don't get it... isn't:
if (SRF_IS_FIRSTCALL()){
}
the iterator one time
"initialization block" where I setup the data to be iterated
upon?
Can you please elaborate on how should I fix this? I'm probably missing something basic...
Show quoted text
Date: Sun, 15 Mar 2015 16:50:27 +0100
From: andres@2ndquadrant.com
To: itaid@outlook.com
CC: pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Crash on SRF executionHi,
On 2015-03-15 17:40:11 +0200, Itai wrote:
I'm attempting to program a simple SRF function but it constantly crashes (details and code below).
Any idea why?
if (SRF_IS_FIRSTCALL())
{
length = 4000;
base_num = 1203000000;
list = (NumberList *)palloc(sizeof(NumberList));
list->pp_numbers = (Number **)palloc(sizeof(Number*) * length);
list->length = length;
i = 0;
for (; i < length; i++)
{
num = (Number *)palloc(sizeof(Number));
num->value = base_num + i;
num->is_even = ((base_num + i) % 2 == 0) ? 1 : 0;
list->pp_numbers[i] = num;
}
ereport(INFO, (errmsg("----------- data source -----------")));
i = 0;
for (; i < length; i++)
{
ereport(INFO, (errmsg("value: %d", list->pp_numbers[i]->value)));
ereport(INFO, (errmsg("is_even: %d", list->pp_numbers[i]->is_even)));
}funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
funcctx->user_fctx = list;
funcctx->max_calls = list->length;
if (get_call_result_type(fcinfo, NULL, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("check if sql function definition returns SETOF record")));BlessTupleDesc(funcctx->tuple_desc);
MemoryContextSwitchTo(oldcontext);
}The palloc() for list above is in the per call memory context, but you
use it across several calls. You should allocate it in the multi call
context you use some lines below.Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2015-03-15 17:59:39 +0200, Itai wrote:
Thanks for the quick response!! :)
But I don't get it... isn't:
if (SRF_IS_FIRSTCALL()){
}
the iterator one time
"initialization block" where I setup the data to be iterated
upon?Can you please elaborate on how should I fix this? I'm probably missing something basic...
if (SRF_IS_FIRSTCALL())
{
length = 4000;
base_num = 1203000000;
list = (NumberList *)palloc(sizeof(NumberList));
list->pp_numbers = (Number **)palloc(sizeof(Number*) * length);
You allocate memory in the per call context here.
list->length = length;
i = 0;
for (; i < length; i++)
{
num = (Number *)palloc(sizeof(Number));
num->value = base_num + i;
num->is_even = ((base_num + i) % 2 == 0) ? 1 : 0;
list->pp_numbers[i] = num;
}
ereport(INFO, (errmsg("----------- data source -----------")));
i = 0;
for (; i < length; i++)
{
ereport(INFO, (errmsg("value: %d", list->pp_numbers[i]->value)));
ereport(INFO, (errmsg("is_even: %d", list->pp_numbers[i]->is_even)));
}funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
Because you only switch the memory context here. Move this up, to the
beginning of the SRF_IS_FIRSTCALL block. Before the palloc()s.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Fantastic! That solved this problem.
However I still get a crash if I change:
is_even to bool num->is_even = ((base_num + i) % 2 == 0) ? true : false; retvals[1] = BoolGetDatum(list->pp_numbers[call_cntr]->is_even); CREATE OR REPLACE FUNCTION pg_srf(OUT value integer, OUT is_even bit) RETURNS SETOF recordAS 'pg_srf.so', 'pg_srf'LANGUAGE CSTRICTIMMUTABLE;
Show quoted text
Date: Sun, 15 Mar 2015 17:03:38 +0100
From: andres@2ndquadrant.com
To: itaid@outlook.com
CC: pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Crash on SRF executionHi,
On 2015-03-15 17:59:39 +0200, Itai wrote:
Thanks for the quick response!! :)
But I don't get it... isn't:
if (SRF_IS_FIRSTCALL()){
}
the iterator one time
"initialization block" where I setup the data to be iterated
upon?Can you please elaborate on how should I fix this? I'm probably missing something basic...
if (SRF_IS_FIRSTCALL())
{
length = 4000;
base_num = 1203000000;
list = (NumberList *)palloc(sizeof(NumberList));
list->pp_numbers = (Number **)palloc(sizeof(Number*) * length);You allocate memory in the per call context here.
list->length = length;
i = 0;
for (; i < length; i++)
{
num = (Number *)palloc(sizeof(Number));
num->value = base_num + i;
num->is_even = ((base_num + i) % 2 == 0) ? 1 : 0;
list->pp_numbers[i] = num;
}
ereport(INFO, (errmsg("----------- data source -----------")));
i = 0;
for (; i < length; i++)
{
ereport(INFO, (errmsg("value: %d", list->pp_numbers[i]->value)));
ereport(INFO, (errmsg("is_even: %d", list->pp_numbers[i]->is_even)));
}funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);Because you only switch the memory context here. Move this up, to the
beginning of the SRF_IS_FIRSTCALL block. Before the palloc()s.Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Thanks Tom.
Assuming the SRF had a parameter, would this be a correct approach
(considering the iterative model) to bail-out early?
if (SRF_IS_FIRSTCALL())
{
int i;
if (get_call_result_type(fcinfo, NULL, &funcctx->tuple_desc) !=
TYPEFUNC_COMPOSITE)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Check if sql function definition returns SETOF
record")));
return;
}
if (PG_ARGISNULL(0))
{
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("Null value not allow for ...")));
return;
}
if((i = PG_GETARG_INT32(0)) != 'WHATEVER')
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Null value not allow for ...")));
return;
}
-----Original Message-----
From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
Sent: Sunday, March 15, 2015 5:50 PM
To: Itai
Cc: pgsql-hackers@postgresql.org
Subject: Re: [HACKERS] Crash on SRF execution
Itai <itaid@outlook.com> writes:
I'm attempting to program a simple SRF function but it constantly crashes
(details and code below).
Any idea why?
Looks like you're pallocing some stuff in the calling context (ie, a
short-lived context) during the first execution and expecting it to still be
there in later executions. You'd need to allocate those data structures in
the multi_call_memory_ctx instead.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers