Skip to content

Commit

Permalink
Add support for empty 2D geometries - it's a prototype, need more tes…
Browse files Browse the repository at this point in the history
…ting
  • Loading branch information
Giuseppe Broccolo committed Jul 3, 2016
1 parent 7f48284 commit 8ad5c75
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 6 deletions.
98 changes: 93 additions & 5 deletions postgis/brin_2d.c
Expand Up @@ -11,14 +11,23 @@
* FunctionCallInvoke machinery for each heap tuple.
*/

static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
uint16 procnum);

static bool isempty(Datum the_datum);

PG_FUNCTION_INFO_V1(geom2d_brin_inclusion_add_value);
Datum
geom2d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
{
BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
Datum newval = PG_GETARG_DATUM(2);
bool isnull = PG_GETARG_BOOL(3);
BOX2DF box_geom, *box_key;
Datum newval = PG_GETARG_DATUM(2);
bool isnull = PG_GETARG_BOOL(3);
Oid colloid = PG_GET_COLLATION();
FmgrInfo *finfo;
AttrNumber attno;
BOX2DF box_geom, *box_key;

/*
* If the new value is null, we record that we saw it if it's the first
Expand All @@ -33,8 +42,32 @@ geom2d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(true);
}

if (gserialized_datum_get_box2df_p(newval, &box_geom) == LW_FAILURE)
elog(ERROR, "Error while extracting the box2df from the geom");

/*
* If the opclass supports the concept of empty values, test the passed
* new value for emptiness; if it returns true, we need to set the
* "contains empty" flag in the element (unless already set).
*/
if (gserialized_datum_get_box2df_p(newval, &box_geom) == LW_FAILURE) {
if (isempty(newval)) {
attno = column->bv_attno;

finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY);
if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval)))
{
if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
{
column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
PG_RETURN_BOOL(true);
}

PG_RETURN_BOOL(false);
}
} else {
/* check other cases where it is not possible to retrieve a box*/
elog(ERROR, "Error while extracting the box2df from the geom");
}
}

/* if the recorded value is null, we just need to store the box2df */
if (column->bv_allnulls)
Expand All @@ -61,3 +94,58 @@ geom2d_brin_inclusion_add_value(PG_FUNCTION_ARGS)

PG_RETURN_BOOL(false);
}

/*
* Cache and return inclusion opclass support procedure
*
* Return the procedure corresponding to the given function support number
* or null if it is not exists.
*/
static FmgrInfo *
inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
{
InclusionOpaque *opaque;
uint16 basenum = procnum - PROCNUM_BASE;

/*
* We cache these in the opaque struct, to avoid repetitive syscache
* lookups.
*/
opaque = (InclusionOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;

/*
* If we already searched for this proc and didn't find it, don't bother
* searching again.
*/
if (opaque->extra_proc_missing[basenum])
return NULL;

if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
{
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
procnum)))
{
fmgr_info_copy(&opaque->extra_procinfos[basenum],
index_getprocinfo(bdesc->bd_index, attno, procnum),
bdesc->bd_context);
}
else
{
opaque->extra_proc_missing[basenum] = true;
return NULL;
}
}

return &opaque->extra_procinfos[basenum];
}

static bool
isempty(Datum the_datum)
{
GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(the_datum);
LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
bool empty = lwgeom_is_empty(lwgeom);

lwgeom_free(lwgeom);
return empty;
}
1 change: 1 addition & 0 deletions postgis/postgis.sql.in
Expand Up @@ -5768,6 +5768,7 @@ CREATE OPERATOR CLASS brin_geometry_inclusion_ops_2d
FUNCTION 2 geom2d_brin_inclusion_add_value(internal, internal, internal, internal) ,
FUNCTION 3 brin_inclusion_consistent(internal, internal, internal) ,
FUNCTION 4 brin_inclusion_union(internal, internal, internal) ,
FUNCTION 14 st_isempty(geometry) ,
STORAGE box2df;

ALTER OPERATOR FAMILY brin_geometry_inclusion_family_2d USING brin ADD
Expand Down
15 changes: 14 additions & 1 deletion postgis/postgis_brin.h
Expand Up @@ -12,11 +12,24 @@
#include <math.h>
#include <float.h>
#include <string.h>
#include "access/genam.h"
#include "access/stratnum.h"
#include "access/brin_tuple.h"
#include "utils/datum.h"
#include "gserialized_gist.h"

#define INCLUSION_UNION 0
#define INCLUSION_MAX_PROCNUMS 4 /* maximum support procs we need */
#define PROCNUM_BASE 11

#define INCLUSION_UNION 0
#define INCLUSION_UNMERGEABLE 1
#define INCLUSION_CONTAINS_EMPTY 2
#define PROCNUM_EMPTY 14 /* optional support function to manage empty elements */

typedef struct InclusionOpaque
{
FmgrInfo extra_procinfos[INCLUSION_MAX_PROCNUMS];
bool extra_proc_missing[INCLUSION_MAX_PROCNUMS];
Oid cached_subtype;
FmgrInfo strategy_procinfos[RTMaxStrategyNumber];
} InclusionOpaque;

0 comments on commit 8ad5c75

Please sign in to comment.