Return-Path: pg_adm@postgres.berkeley.edu
Received: by postgres.Berkeley.EDU (5.61/1.29)
	id AA15021; Tue, 18 Feb 92 09:24:05 -0800
Message-Id: <9202181724.AA15021@postgres.Berkeley.EDU>
From: Peter van Oosterom <Peter.van.Oosterom@tnofel.fel.tno.nl>
Subject: NULL pointers in ADTs
To: postgres@postgres.berkeley.edu
Sender: pg_adm@postgres.berkeley.edu
To: postgres@postgres.berkeley.edu
Date: Tue, 18 Feb 92 18:28:26 MET
X-Mailer: ELM [version 2.3 PL11]

Dear Postgres-group,

There is a problem with the return of NULL pointers in ADTs.
I'm working on the implementation of some 3D data types: POINT3, BOX3, etc.
I have implemented one function for calculation the intersection of
two boxes. The function is called Intersect3BoxBox and the source code
is given at the end of this email.

In case the intersection is empty, this function returns NULL
(similar to the standard Postgres function for the intersection of
two 2D boxes). The function works fine as long as there is a non empty
intersection of the BOX3es. An example:

============================================================================
* create b3test (b=BOX3)\g

Query sent to backend is "create b3test (b=BOX3)"
CREATE
Go 
* append b3test (b="(0,0,0, 2,2,2)")\g

Query sent to backend is "append b3test (b="(0,0,0, 2,2,2)")"
APPEND
Go 
* append b3test (b="(1,1,1, 3,3,3)")\g

Query sent to backend is "append b3test (b="(1,1,1, 3,3,3)")"
APPEND
Go 
* retrieve (pb=p.b, qb=q.b, i=Intersect3BoxBox(p.b,q.b)) from p,q in b3test\g

Query sent to backend is "retrieve (pb=p.b, qb=q.b, i=Intersect3BoxBox(p.b,q.b)) from p,q in b3test"
-------------------------------------------
| pb          | qb          | i           |
-------------------------------------------
| (0,0,0,2,2,2)| (0,0,0,2,2,2)| (0,0,0,2,2,2)|
-------------------------------------------
| (1,1,1,3,3,3)| (0,0,0,2,2,2)| (1,1,1,2,2,2)|
-------------------------------------------
| (0,0,0,2,2,2)| (1,1,1,3,3,3)| (1,1,1,2,2,2)|
-------------------------------------------
| (1,1,1,3,3,3)| (1,1,1,3,3,3)| (1,1,1,3,3,3)|
-------------------------------------------

Go 
============================================================================

Ok, so far so good. Now I insert a new BOX3 that does not have overlap
with the others:

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

Go
* append b3test (b="(5,5,5, 6,6,6)")\g

Query sent to backend is "append b3test (b="(5,5,5, 6,6,6)")"
APPEND
Go 
* retrieve (pb=p.b, qb=q.b, i=Intersect3BoxBox(p.b,q.b)) from p,q in b3test\g


Query sent to backend is "retrieve (pb=p.b, qb=q.b, i=Intersect3BoxBox(p.b,q.b)) from p,q in b3test"

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

The last query causes the monitor to loop forever (until ^C). This is caused
by the return of the NULL pointer in the situation that there is no overlap.
I could put an "elog(WARN, "No intersection BOX3 BOX3");" statement in
my code for Intersect3BoxBox (as suggested some time ago on the Postgres BBS).
However, this causes the transaction to abort and will therefore not give
any answers:

============================================================================
Go 
* retrieve (pb=p.b, qb=q.b, i=Intersect3BoxBox(p.b,q.b)) from p,q in b3test\g


Query sent to backend is "retrieve (pb=p.b, qb=q.b, i=Intersect3BoxBox(p.b,q.b)) from p,q in b3test"
WARN:Feb 18 17:58:05:No intersection BOX3 BOX3


Go 
* 
============================================================================


By the way, this problem also applies to all the "standard" Postgres
functions that return NULL pointers (as the original 2D box intersection
function: box_intersect in /usr/postgres/src/utils/adt/geo-ops.c).

Another aspect of this problem is that the Intersect3BoxBox function
will also be used for the 3D R-tree. Other functions within Postgres 
which are used to manipulate the R-tree need the Intersect3BoxBox function.
These functions can explicitly deal with the NULL-pointer return.
However, aborting the transaction (through a call to elog(WARN,"...");)
would be wrong in this situation.

Is there a more elegant solution for this NULL-pointer problem?

Kind regards, Peter van Oosterom.

========================sorce code Intersect3BoxBox=========================
BOX3 *
Intersect3BoxBox(box1, box2)
   BOX3     *box1, *box2;
{
   BOX3     *result;
   long     Overlap3BoxBox();

   if (! Overlap3BoxBox(box1,box2)) {
      elog(WARN, "No intersection BOX3 BOX3");    /*********OK?***********/
      return(NULL);
   }
   result = PALLOCTYPE(BOX3);
   result->xh = MIN(box1->xh, box2->xh);
   result->xl = MAX(box1->xl, box2->xl);
   result->yh = MIN(box1->yh, box2->yh);
   result->yl = MAX(box1->yl, box2->yl);
   result->zh = MIN(box1->zh, box2->zh);
   result->zl = MAX(box1->zl, box2->zl);

   return(result);
}
============================================================================
