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
Views: Raw Message | Whole Thread | Download mbox | Resend email
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

Browse pgsql-interfaces by date

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