X-Original-To: pgsql-interfaces-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [200.46.204.144]) by svr1.postgresql.org (Postfix) with ESMTP id 571C252894 for ; Mon, 11 Jul 2005 18:37:18 -0300 (ADT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 54449-06 for ; Mon, 11 Jul 2005 21:37:13 +0000 (GMT) Received: from mail.ints.com (67.108.61.131.ptr.us.xo.net [67.108.61.131]) by svr1.postgresql.org (Postfix) with ESMTP id 8013D52818 for ; Mon, 11 Jul 2005 18:37:12 -0300 (ADT) Received: from localhost (localhost [127.0.0.1]) by mail.ints.com (Postfix) with ESMTP id E066B7EC4 for ; Mon, 11 Jul 2005 14:37:14 -0700 (PDT) Received: from mail.ints.com ([127.0.0.1]) by localhost (mail [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 10676-01 for ; Mon, 11 Jul 2005 14:37:08 -0700 (PDT) Message-ID: <42D2E683.5080302@ints.com> Date: Mon, 11 Jul 2005 14:37:07 -0700 From: Tim Jackson Organization: Integrated Services Inc. User-Agent: Mozilla Thunderbird 1.0.2 (X11/20050317) X-Accept-Language: en-us, en MIME-Version: 1.0 To: pgsql-interfaces@postgresql.org Subject: Re: C set return function differences on 8.0?]] Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: by amavisd-new at ints.com X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, hits=0.167 tagged_above=0 required=5 tests=AWL, FORGED_RCVD_HELO X-Spam-Level: X-Archive-Number: 200507/20 X-Sequence-Number: 5656 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 #include #include #include #include #include #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); } }