Search code examples
cpostgresqlmemoryforeign-data-wrapper

In a Postgresql Foreign Data Wrapper, how to return custom row data in a TupleTableSlot?


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;

Solution

  • 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.