Subject: Backend crashes--is it me or a bug?

From: [email-masked] (John Campbell)
Date: Fri, 11 Dec 92 16:08:07 -0800

Platform:  SS2 running SunOS 4.1.2
Postgres: 4.0.1

I'm wondering if I've run across a bug in postgres 4.0.1.
Unfortunately, I'm so new to postgres that I very easily 
could be doing something wrong.

The symptom is that a query hangs and sometimes the backend
crashes when I do

   retrieve (COMPUTER.ip) \g

but succeeds if I then do

   retrieve (COMPUTER.ip) where COMPUTER.name ~ ".*cse.*" \g
   retrieve (COMPUTER.ip) \g
 
In other words, the success of one query depends on having another 
query precede it, which seems odd, even given my novice status.

I *think* this is reproducible.  ip is a postquel function that
calls a 'C' language function (called ip_text) both of which return 
text.  I've tried to be *very* careful about getting the data in 
and out of the text variable correctly--however, I might have 
stomped something, but I don't see how at this point.  (Especially
since I put a large number into palloc at one point to see if
the behavior would change.)

To reproduce the bug, I believe you would just compile the
ip.c program and run the monitor script ``computer.pq'' (after
adjusting the ".o" location, of course).  If it hangs or the 
backend crashes, then you might try running a new monitor 
and typing:

   retrieve (COMPUTER.ip) where COMPUTER.name ~ ".*cse.*" \g
   retrieve (COMPUTER.ip) \g

When I do this, both queries finally succeed.  (Is that odd?)

Also, when you use elog(WARN,...), do you need to return a
value (say 0) or does WARN kill the execution of the object
file at that point?

 ==============================================================

Here's a monitor script and the 'C' program that hangs or crashes 
the backend on the last retrieve.  Someone please tell me why!

---cut here for computer.pq---
/* Learn by playing with a small test set. */

destroy VENDOR \p\g
destroy COMPUTER \p\g
remove function vendor \p \g
remove function ip_text \p \g
remove function ip \p \g

create VENDOR (name = text, phone=text) \p\g
create COMPUTER (name = text, model=text, _ven=text) \p\g

define function ip_text
 (language = "c", returntype = text)
 arg is (text)
 as "/home/sunset/jdc/.postgres/ip.o" \g

/* Remember that postgres has to have read privilege.*/
load "/home/sunset/jdc/.postgres/ip.o" \g

define function vendor
 (language = "postquel", returntype = VENDOR)
 arg is (COMPUTER)
 as "retrieve (VENDOR.all) where VENDOR.name = $1._ven" \p\g

/* populate with 2 VENDORs and 3 COMPUTERs */
append VENDOR (name = "SUN", phone="1234") \p\g
append VENDOR (name = "DEC", phone="5678") \p\g

append COMPUTER (name = "sunset.cse.nau.edu", model="SS2", _ven="SUN") \p\g
append COMPUTER (name = "slate.cse.nau.edu", model="SS2", _ven="SUN") \p\g
append COMPUTER (name = "naucse.cse.nau.edu", model="MVII", _ven="DEC") \p\g

/* Now define a different function. */
define function ip
   (language="postquel", returntype = text)
   arg is (COMPUTER)
   as "retrieve ($1.name.ip_text)" \p\g

/* retrieve (COMPUTER.name, COMPUTER.ip) where 1=1 */

retrieve (COMPUTER.ip, COMPUTER.name) where COMPUTER.name = "naucse.cse.nau.edu" \p\g

retrieve (COMPUTER.name, COMPUTER.ip) \p\g

----cut here for ip.c-----
#include "tmp/postgres.h"
#include "utils/log.h"   /* For logging (& debugging) */

#include <netdb.h>
extern int h_errno;

#define BIG 100  /* No host name should be larger than this */

text *ip_text (tval)
text *tval;
{
   text *rval;
   char space[BIG];
   unsigned char **ip_addr(), **value, *elem;
   int len;

   if (tval == 0) return 0;  /* Is this a good idea? */

   len = VARSIZE(tval) - sizeof(VARSIZE(tval));
   if (len <= 0) return 0;

   if (len > BIG)
      elog (WARN, "Error converting ip address, hostname = %d bytes!", len);
   
/* Copy tval out of counted array into '\0' terminated array. */
   strncpy (space, VARDATA(tval), len);
   space[len] = '\0';

/* 
   Get enough space for the new text object 
   (should we be returning a char16 * instead?)
*/
   rval = (text *)palloc (sizeof(text)+16);/* IP address < 16 bytes */
   if (!rval)
      elog (WARN, "Couldn't allocate %d bytes", sizeof(text)+16);
   
/* Compute the ip address. (Data in "value" must be copied! */
   value = ip_addr (space);

/* Just do first list element for now. */
   elem = *value; 
   sprintf (space, "%d.%d.%d.%d", elem[0], elem[1], elem[2], elem[3]);
   if ((len = strlen (space)) > 16)
      elog (WARN, "Error converting ip address, (%s) too large", space);

   strncpy (VARDATA(rval), space, len);
   VARSIZE(rval) = len + sizeof(VARSIZE(rval));

/* elog (NOTICE, "conversion finished, value is %s", space); */

   return rval;
}

unsigned char **ip_addr (name)
char *name;
{
   struct hostent *gethostbyname(), *result;

/* How to format herror message into a buffer for elog? */
   if ((result = gethostbyname(name)) == 0) {
      elog(WARN,"Failure during ip name lookup of \"%s\"", name);  /* Can't use herror! */
    }

/* Return the whole list */
   return (unsigned char **)result->h_addr_list;
}
----end of ip.c-----

-- 
	John Campbell               [email-masked]
        [email-masked]      [email-masked]

---

From: [email-masked] (John Campbell)
Date: Fri, 11 Dec 92 20:52:04 -0800

Shoot...  In preparing my previous article I included the wrong script!

I'm refering to the following:

On Dec 11 at  4:08pm, John Campbell writes:
 >Message-Id: <[email-masked]>
 >Subject: Backend crashes--is it me or a bug?
 >To: [email-masked]
 >
  . . .
 >   retrieve (COMPUTER.ip) \g

And then I included the script I had been experimenting with (it
has a critical query commented out).

If you have any patience left, please try this script instead:
----cut here for computer.pq----

destroy VENDOR \p\g
destroy COMPUTER \p\g

define function ip_text

define function vendor

retrieve (COMPUTER.name, COMPUTER.ip) where 1=1 \p\g

/* Now we hang, I believe because of the previous query */
retrieve (COMPUTER.name, COMPUTER.ip) \p\g