mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
190 lines
4.7 KiB
C
190 lines
4.7 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* rtproc.c
|
|
* pg_amproc entries for rtrees.
|
|
*
|
|
* NOTE: for largely-historical reasons, the intersection functions should
|
|
* return a NULL pointer (*not* an SQL null value) to indicate "no
|
|
* intersection". The size functions must be prepared to accept such
|
|
* a pointer and return 0. This convention means that only pass-by-reference
|
|
* data types can be used as the output of the union and intersection
|
|
* routines, but that's not a big problem.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtproc.c,v 1.37 2003/08/04 02:39:57 momjian Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "utils/geo_decls.h"
|
|
|
|
|
|
Datum
|
|
rt_box_union(PG_FUNCTION_ARGS)
|
|
{
|
|
BOX *a = PG_GETARG_BOX_P(0);
|
|
BOX *b = PG_GETARG_BOX_P(1);
|
|
BOX *n;
|
|
|
|
n = (BOX *) palloc(sizeof(BOX));
|
|
|
|
n->high.x = Max(a->high.x, b->high.x);
|
|
n->high.y = Max(a->high.y, b->high.y);
|
|
n->low.x = Min(a->low.x, b->low.x);
|
|
n->low.y = Min(a->low.y, b->low.y);
|
|
|
|
PG_RETURN_BOX_P(n);
|
|
}
|
|
|
|
Datum
|
|
rt_box_inter(PG_FUNCTION_ARGS)
|
|
{
|
|
BOX *a = PG_GETARG_BOX_P(0);
|
|
BOX *b = PG_GETARG_BOX_P(1);
|
|
BOX *n;
|
|
|
|
n = (BOX *) palloc(sizeof(BOX));
|
|
|
|
n->high.x = Min(a->high.x, b->high.x);
|
|
n->high.y = Min(a->high.y, b->high.y);
|
|
n->low.x = Max(a->low.x, b->low.x);
|
|
n->low.y = Max(a->low.y, b->low.y);
|
|
|
|
if (n->high.x < n->low.x || n->high.y < n->low.y)
|
|
{
|
|
pfree(n);
|
|
/* Indicate "no intersection" by returning NULL pointer */
|
|
n = NULL;
|
|
}
|
|
|
|
PG_RETURN_BOX_P(n);
|
|
}
|
|
|
|
Datum
|
|
rt_box_size(PG_FUNCTION_ARGS)
|
|
{
|
|
BOX *a = PG_GETARG_BOX_P(0);
|
|
|
|
/* NB: size is an output argument */
|
|
float *size = (float *) PG_GETARG_POINTER(1);
|
|
|
|
if (a == (BOX *) NULL || a->high.x <= a->low.x || a->high.y <= a->low.y)
|
|
*size = 0.0;
|
|
else
|
|
*size = (float) ((a->high.x - a->low.x) * (a->high.y - a->low.y));
|
|
|
|
PG_RETURN_VOID();
|
|
}
|
|
|
|
/*
|
|
* rt_bigbox_size() -- Compute a size for big boxes.
|
|
*
|
|
* In an earlier release of the system, this routine did something
|
|
* different from rt_box_size. We now use floats, rather than ints,
|
|
* as the return type for the size routine, so we no longer need to
|
|
* have a special return type for big boxes.
|
|
*/
|
|
Datum
|
|
rt_bigbox_size(PG_FUNCTION_ARGS)
|
|
{
|
|
return rt_box_size(fcinfo);
|
|
}
|
|
|
|
Datum
|
|
rt_poly_union(PG_FUNCTION_ARGS)
|
|
{
|
|
POLYGON *a = PG_GETARG_POLYGON_P(0);
|
|
POLYGON *b = PG_GETARG_POLYGON_P(1);
|
|
POLYGON *p;
|
|
|
|
p = (POLYGON *) palloc0(sizeof(POLYGON)); /* zero any holes */
|
|
p->size = sizeof(POLYGON);
|
|
p->npts = 0;
|
|
p->boundbox.high.x = Max(a->boundbox.high.x, b->boundbox.high.x);
|
|
p->boundbox.high.y = Max(a->boundbox.high.y, b->boundbox.high.y);
|
|
p->boundbox.low.x = Min(a->boundbox.low.x, b->boundbox.low.x);
|
|
p->boundbox.low.y = Min(a->boundbox.low.y, b->boundbox.low.y);
|
|
|
|
/* Avoid leaking memory when handed toasted input. */
|
|
PG_FREE_IF_COPY(a, 0);
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
PG_RETURN_POLYGON_P(p);
|
|
}
|
|
|
|
Datum
|
|
rt_poly_inter(PG_FUNCTION_ARGS)
|
|
{
|
|
POLYGON *a = PG_GETARG_POLYGON_P(0);
|
|
POLYGON *b = PG_GETARG_POLYGON_P(1);
|
|
POLYGON *p;
|
|
|
|
p = (POLYGON *) palloc0(sizeof(POLYGON)); /* zero any holes */
|
|
p->size = sizeof(POLYGON);
|
|
p->npts = 0;
|
|
p->boundbox.high.x = Min(a->boundbox.high.x, b->boundbox.high.x);
|
|
p->boundbox.high.y = Min(a->boundbox.high.y, b->boundbox.high.y);
|
|
p->boundbox.low.x = Max(a->boundbox.low.x, b->boundbox.low.x);
|
|
p->boundbox.low.y = Max(a->boundbox.low.y, b->boundbox.low.y);
|
|
|
|
if (p->boundbox.high.x < p->boundbox.low.x ||
|
|
p->boundbox.high.y < p->boundbox.low.y)
|
|
{
|
|
pfree(p);
|
|
/* Indicate "no intersection" by returning NULL pointer */
|
|
p = NULL;
|
|
}
|
|
|
|
/* Avoid leaking memory when handed toasted input. */
|
|
PG_FREE_IF_COPY(a, 0);
|
|
PG_FREE_IF_COPY(b, 1);
|
|
|
|
PG_RETURN_POLYGON_P(p);
|
|
}
|
|
|
|
Datum
|
|
rt_poly_size(PG_FUNCTION_ARGS)
|
|
{
|
|
Pointer aptr = PG_GETARG_POINTER(0);
|
|
|
|
/* NB: size is an output argument */
|
|
float *size = (float *) PG_GETARG_POINTER(1);
|
|
POLYGON *a;
|
|
double xdim,
|
|
ydim;
|
|
|
|
/*
|
|
* Can't just use GETARG because of possibility that input is NULL;
|
|
* since POLYGON is toastable, GETARG will try to inspect its value
|
|
*/
|
|
if (aptr == NULL)
|
|
{
|
|
*size = 0.0;
|
|
PG_RETURN_VOID();
|
|
}
|
|
/* Now safe to apply GETARG */
|
|
a = PG_GETARG_POLYGON_P(0);
|
|
|
|
if (a->boundbox.high.x <= a->boundbox.low.x ||
|
|
a->boundbox.high.y <= a->boundbox.low.y)
|
|
*size = 0.0;
|
|
else
|
|
{
|
|
xdim = (a->boundbox.high.x - a->boundbox.low.x);
|
|
ydim = (a->boundbox.high.y - a->boundbox.low.y);
|
|
|
|
*size = (float) (xdim * ydim);
|
|
}
|
|
|
|
/* Avoid leaking memory when handed toasted input. */
|
|
PG_FREE_IF_COPY(a, 0);
|
|
|
|
PG_RETURN_VOID();
|
|
}
|