Skip site navigation (1) Skip section navigation (2)

Re: C set return function differences on 8.0?]]

From: Tim Jackson <tim(dot)jackson(at)ints(dot)com>
To: pgsql-interfaces(at)postgresql(dot)org
Subject: Re: C set return function differences on 8.0?]]
Date: 2005-07-11 21:37:07
Message-ID: 42D2E683.5080302@ints.com (view raw or flat)
Thread:
Lists: pgsql-interfaces
Michael Fuhr wrote:

>Where did you look for a core dump?  If one was made then it'll
>probably be somewhere under $PGDATA (e.g., $PGDATA/base/XXX/core)
>unless your system is configured to put core dumps elsewhere.
>
>  
>
I was able to get the core dump by adding 'ulimit -c unlimited' to the 
start script
(thanks Tom)
It is huge (14 megs)
One interesting thing happened once the core dump is created. 
Now if I re connect to the data base and rerun the select on the view 
after it has crashed once it will select the view.

>If there isn't a core dump then you could add some debugging ereport()
>calls to your code so you can find out where the crash is happening.
>Another possibility might be to attach a debugger to the backend.
>
>  
>
If you can tell me how to do that.  I tried attaching gdb to the running 
servers pid and it seems to lock up the server.

>So your C function calls these library functions, which query some
>other data source and return strings back to you, right?  How are
>these strings returned -- as char * values?  Can you at least post
>your code?
>
>  
>
The full so code is 4000 lines and caused the news group to reject the mail
, but here is the basic format with the piece that builds the record replaced 
by hardcoded values.  


/*******************************/
//
//   Program:  call_good.c
//
//   Listing Date: 07/08/2005
//
/*******************************/

#include "server/postgres.h"
#include "server/fmgr.h"
#include "server/funcapi.h"

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <ctype.h>
#include <time.h>


#define TRUE    1
#define FALSE   0
#define OK      0
#define ERROR1   (-1)
#define YES     1
#define NO      0
#define DATA1    2
#define MAYBE   2

  char record[1024 * 1024];

  char buffer[256];
  unsigned char * bufptr = (unsigned char *)buffer;
  char buffer1[256];
  unsigned char * bufptr1 = (unsigned char *)buffer1;
  char buffer2[256];
  unsigned char * bufptr2 = (unsigned char *)buffer2;
  char buffer3[256];
  unsigned char * bufptr3 = (unsigned char *)buffer3;

  int count, count1;
 
  long    CurrentSize;
 
  char request[8192];
  char response[512];

  char typedefin[1024];
  int  max_fields;
  int  field_lengths[256];
  char field_types[256][16];
  char *record_add;
  char parsed[256];

  char *select_add;
  char *from_add;
  char *where_add;
  char *end_add;
 
  char select1[8192];
  char from[512];
  char where[512];

  FILE *stream;
  FILE *stream1;
 
  char filein[128];
  char fileout[128];
  char filename_out[128];
 
    int num_targets_work;
    int num_targets_index;
    int chunk_amount = 5;
    int chunk_counter;
    int fileOpen;
   
    FuncCallContext *funcctx;
    int             call_cntr;
    int             max_calls;
    TupleDesc       tupdesc;
    TupleTableSlot  *slot;
    AttInMetadata   *attinmeta;


/***********************************/
// select_more_data
/***********************************/
int tselect_more_data (void)
{
    int recordFound;

    memset (record, 0, sizeof(record));

       sprintf (buffer1, "%s|%s|%s|%s|", "6","6666.01","6-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "7","7777.01","7-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "8","888888.0001","8-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "9","9999.01","9-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "10","1010.01","10-6 Wide","Y");
       strcat (record, buffer1);

       count = 5;

    if (count)
        recordFound = DATA1;

    return (recordFound);
}

/***********************************/
// select_data
/***********************************/
int tselect_data (void)
{
    int recordFound;

    memset (record, 0, sizeof(record));
   
       sprintf (buffer1, "%s|%s|%s|%s|", "1","1111.01","1-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "2","2222.01","2-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "3","3333.01","3-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "4","  4444.01","4-6 Wide","Y");
       strcat (record, buffer1);
       sprintf (buffer1, "%s|%s|%s|%s|", "5","5555.01","5-8 Wide","Y");
       strcat (record, buffer1);

       count = 5;

    if (count)
        recordFound = DATA1;

    return (recordFound);
}

/***********************************/
// select_field_lengths
/***********************************/
int tselect_field_lengths (void)
{
    int recordFound;
    int len;

      CurrentSize = 10;
     
        len = 3;
          field_lengths[0] = len * 2 + 1;
          strcpy (field_types[0], "numeric");

        len = 4;
          field_lengths[1] = len * 2 + 1;
          strcpy (field_types[1], "numeric");
     
        len = 30;
          field_lengths[2] = len;
          strcpy (field_types[2], "string");
     
        len = 1;
          field_lengths[3] = len;
          strcpy (field_types[3], "string");
     
    max_fields = 4;
   
    recordFound = DATA1;
    return (recordFound);
}

/***********************************/
// parse_record
/***********************************/
void tparse_record (void)
{
    char    *ptr;
    char    *ptr1;

    ptr = record_add;
   
    ptr1 = strchr (ptr, '|');
    if (ptr1)
    {
        *ptr1 = 0;
        strcpy (parsed,ptr);
    }
    record_add = ++ptr1;
}

/***********************************/
//  parse_sql
/***********************************/
int tparse_sql (char * request)
{
    int func;

    select_add    =
    from_add      =
    where_add     =
    end_add       = 0L;

    memset ( select1,   0, sizeof(select1));
    memset ( from,      0, sizeof(from));
    memset ( where,     0, sizeof(where));

    select_add    = strstr(request, "SELECT ");
    if (select_add == 0)
        select_add    = strstr(request, "select ");
   
    if (select_add != 0)
    {
        from_add      = strstr(request, "FROM ");
        if (from_add == 0)
            from_add      = strstr(request, "from ");
    }

    where_add     = strstr(request, "WHERE ");
    if (where_add == 0)
        where_add     = strstr(request, "where ");

    if (select_add != 0)
    {
        end_add       = select_add+strlen(request);
        func = 40;
    }
    else
    {
        func = 999;
        return func;
    }

    if (select_add != 0)
    {
        memcpy ( select1, select_add, from_add-select_add);
        if (where_add == 0)
        {
            memcpy ( from, from_add, end_add-from_add);
        }
        else if (where_add)
        {
            memcpy ( from, from_add, where_add-from_add);
            memcpy ( where, where_add, end_add-where_add);
        }
    }
    return func;
}

/************************************/

PG_FUNCTION_INFO_V1 (call_good);

Datum
call_good (PG_FUNCTION_ARGS)
{
    int  i, func, retval;

    // stuff done only on the first call of the function
    if (SRF_IS_FIRSTCALL())
    {
        MemoryContext   oldcontext;

        text *t  = PG_GETARG_TEXT_P(0);
        text *t1 = PG_GETARG_TEXT_P(1);

        memset (request, 0, sizeof(request));
        strncpy (request, t->vl_dat, t->vl_len- VARHDRSZ);

        memset (typedefin, 0, sizeof(typedefin));
        strncpy (typedefin, t1->vl_dat, t1->vl_len- VARHDRSZ);

        // create a function context for cross-call persistence
        funcctx = SRF_FIRSTCALL_INIT();

        // switch to memory context appropriate for multiple function calls
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

        // Build a tuple description for a incoming type tuple
        tupdesc = RelationNameGetTupleDesc(typedefin);

        // allocate a slot for a tulpe with this tupdesc
        slot = TupleDescGetSlot(tupdesc);

        // assign slot to function context
        funcctx->slot = slot;

        // Generate attribute metadata needed later to produce
        // tupples from raw C strings
        attinmeta = TupleDescGetAttInMetadata(tupdesc);
        funcctx->attinmeta = attinmeta;

        MemoryContextSwitchTo(oldcontext);
   
        strcpy (fileout, "pfxG");
        sprintf (filename_out, "/tmp/%s.rsp", fileout);     // rf

        if ((stream1 = fopen (filename_out, "wb")) == NULL)
        {
            return 1;
        }
       
        if ((stream = fopen ("/tmp/call_good.log", "a+")) == NULL)
        {
            return 1;
        }
        fprintf (stream1,"Call_Good\n");   
        fprintf (stream1,"request>%s<\n",request);   
        fprintf (stream1,"file: %s\n",typedefin); 

        func = tparse_sql (request);

        record_add = 0;

        tselect_field_lengths();
        fprintf (stream,"NumRecs = %ld NumFields = %d\n",
                CurrentSize, max_fields);   
        for (i=0; i < max_fields; i++)
        {
            fprintf (stream1,"Field: %3d Type: %-8s Length: %d\n",
                    i,field_types[i],field_lengths[i]);
        }

        switch (func)
        {
            case 40:
                if (select_add)
                {
                    fprintf (stream1, "select: %s\n",select1);
                    fprintf (stream1, "from: %s\n",from);
                    if (where_add)
                    {
                        fprintf (stream1, "where: %s\n",where);
                    }
                }
                funcctx->max_calls = CurrentSize;

                // Go get first chunk of records from file
                retval = tselect_data();

                if (retval != DATA1)
                {
                    strcpy (record, "Not Found\n");
                    fwrite (record, strlen(record), 1, stream1);
                }
                break;
            case 999:
                strcpy (record, "Invalid Statement");
                fwrite (record, strlen(record), 1, stream1);
                break;

            default:
                strcpy (record, "Invalid");
                fwrite (record, strlen(record), 1, stream1);
                retval = NO;
                break;
        }
        fprintf (stream,"Count = %ld Data = %.50s\n",CurrentSize,record); 
        fprintf (stream,"File: %s Type: %s\n",filein,typedefin); 
        record_add = record;
        chunk_counter = chunk_amount;
        fflush (stream);
    }
   
    // stuff done on every call of the function
    funcctx = SRF_PERCALL_SETUP();

    call_cntr = funcctx->call_cntr;
    max_calls = funcctx->max_calls;
    slot = funcctx->slot;
    attinmeta = funcctx->attinmeta;

    if (call_cntr < max_calls)
    {
        char        **values;
        HeapTuple   tuple;
        Datum       result;

        if (call_cntr == chunk_counter)
        {
            // Go get next chunk of records from file
            retval = tselect_more_data();
            record_add = record;
            chunk_counter += chunk_amount;
        }

        // Prepare a values array for storage in our slot.
        // This should be an array of C strings which will
        // be processed later by the appropriate "in" functions.
       
        values = (char **) palloc(max_fields * sizeof(char *));
        for (i=0; i < max_fields; i++)
        {
            values[i] = (char *) palloc(field_lengths[i] * sizeof(char));
        }

        for (i=0; i < max_fields; i++)
        {
            tparse_record();

            if (strlen(parsed) == 0 && strcmp(field_types[i],"date") == 0)
            {
                strcpy (values[i], "01/01/1980");
            }
            else
            {
                strcpy (values[i], parsed);
            }
        }

        // build a tuple
        tuple = BuildTupleFromCStrings(attinmeta, values);
        // make the tuple into a datum
        result = TupleGetDatum(slot,tuple);
       // result = HeapTupleGetDatum(tuple);

        // Clean up (this is not actually necessary)
        for (i=0; i < max_fields; i++)
        {
            pfree(values[i]);
        }
        pfree(values);

        fflush (stream);
        SRF_RETURN_NEXT(funcctx, result);
    }
    else    // do when there is no more left
    {
        if (fileOpen)
        {
            fprintf (stream, "EOD Set5\n");
            fileOpen = 0;
        }
        fprintf (stream1,"DONE: call_cntr= %d max_calls= %d\n",
                call_cntr,max_calls); 
        fclose (stream1);
        fclose (stream);
        SRF_RETURN_DONE(funcctx);
    }
}





Responses

pgsql-interfaces by date

Next:From: Tim JacksonDate: 2005-07-11 23:09:28
Subject: Re: C set return function differences on 8.0?
Previous:From: Dirk JagdmannDate: 2005-07-09 21:26:00
Subject: ecpg and VARCHAR

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group