I am writing a Foreign Data Wrapper for Postgresql and trying to return dummy data but i am getting a memory access error when selecting from the foreign table.
I use a barebones FDW which returns three rows of data in IterateForeignScan(). I access the FDW with a small SQL script, where i create a foreign table with three columns and the appropriate data types and SELECT the whole table.
With debug output, i determined the line, which leads to the memory access error, but i have no idea why the error happens. Every help appreciated :).
My SQL script, to access the FDW:
-- creates the bachelor_fdw as extension
CREATE EXTENSION IF NOT EXISTS bachelor_fdw;
DROP SERVER IF EXISTS test1 CASCADE;
CREATE SERVER test1
FOREIGN DATA WRAPPER bachelor_fdw;
CREATE USER MAPPING FOR postgres
SERVER test1
OPTIONS (user 'postgres', password '123456');
DROP FOREIGN TABLE IF EXISTS pg1_sf1_region CASCADE;
-- IMPORT FOREIGN SCHEMA public LIMIT TO (pg1_sf1_region) FROM SERVER test1 INTO public;
CREATE FOREIGN TABLE IF NOT EXISTS pg1_sf1_region(
ID integer NOT NULL,
vorname varchar(20) NOT NULL,
nachname varchar(20) NOT NULL)
SERVER test1;
SELECT * FROM pg1_sf1_region;
My IterateForeignScan() function inside my FDW. The error appears at the call to heap_form_tuple():
static TupleTableSlot *bachelorIterateForeignScan(ForeignScanState *node){
ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
Datum *values;
TupleDesc tDescFromNode = node->ss.ss_currentRelation->rd_att;
HeapTuple tuple;
int dummycounter;
bool *isnull = palloc0(sizeof(bool)*3);
isnull[0]=false;
isnull[1]=false;
isnull[2]=false;
// dummy data array
values = (Datum *) palloc0(sizeof(Datum)*3);
elog_debug("%s",__func__);
dummycounter = linitial_int(plan->fdw_private);
if( dummycounter > 0){
if(dummycounter == 1){
values[0] = Int32GetDatum(3);
values[1] = CStringGetDatum("Antonia");
values[2] = CStringGetDatum("Neumann");
}
else if(dummycounter == 2){
values[0] = Int32GetDatum(2);
values[1] = CStringGetDatum("Karl");
values[2] = CStringGetDatum("Hermann");
}
else if(dummycounter == 3){
values[0] = Int32GetDatum(1);
values[1] = CStringGetDatum("Hugo");
values[2] = CStringGetDatum("Hunter");
}
list_head(plan->fdw_private)->data.int_value--;
ExecClearTuple(slot);
elog_debug("while tuple creation");
tuple = heap_form_tuple(tDescFromNode, values, isnull);
elog_debug("while tuple storing");
ExecStoreHeapTuple(tuple, slot, false);
elog_debug("Tuple returned");
return slot;
}
else return NULL;
}
The error message in the postgresql log just reads: "server process (PID 12310) was terminated by signal 11: Speicherzugriffsfehler" (memory access error)
EDIT
However it is working, when building tuples from cstrings, instead of datum *:
char **cstringvalues = (char **) palloc0(sizeof(char *)*3);
for(int i = 0; i < 3; i++){
cstringvalues[i] = (char *) palloc(sizeof(char) * 10);
}
...
if( dummycounter > 0){
if(dummycounter == 1){
strcpy(cstringvalues[0], "3");
strcpy(cstringvalues[1], "Antonia");
strcpy(cstringvalues[2], "Neumann");
}
else if(dummycounter == 2){
strcpy(cstringvalues[0], "2");
strcpy(cstringvalues[1], "Karl");
strcpy(cstringvalues[2], "Hermann");
}
else if(dummycounter == 3){
strcpy(cstringvalues[0], "1");
strcpy(cstringvalues[1], "Hugo");
strcpy(cstringvalues[2], "Hunter");
}
list_head(plan->fdw_private)->data.int_value--;
ExecClearTuple(slot);
attin = TupleDescGetAttInMetadata(tDescFromNode);
elog_debug("while tuple creation");
tuple = BuildTupleFromCStrings(attin,cstringvalues);
elog_debug("while tuple storing");
ExecStoreHeapTuple(tuple, slot, false);
elog_debug("Tuple returned");
return slot;
}
else return NULL;
My guess is that the problem is that the foreign table is defined to have a varchar
column, but you try to store a cstring
.
Try using CStringGetTextDatum
instead of CStringGetDatum
.