return;
}
+/* An "unknown" GIDX is used to represent the bounds of an EMPTY
+ geometry or other-wise unindexable geometry (like one with NaN
+ or Inf bounds) */
+static inline bool gidx_is_unknown(const GIDX *a)
+{
+ size_t size = VARSIZE(a) - VARHDRSZ;
+ /* "unknown" gidx objects have a too-small size of one float */
+ if ( size <= 0.0 )
+ return TRUE;
+ return FALSE;
+}
+
+static inline void gidx_set_unknown(GIDX *a)
+{
+ SET_VARSIZE(a, VARHDRSZ);
+}
+
/* Enlarge b_union to contain b_new. If b_new contains more
dimensions than b_union, expand b_union to contain those dimensions. */
static void gidx_merge(GIDX **b_union, GIDX *b_new)
Assert(*b_union);
Assert(b_new);
+ /* Can't merge an unknown into any thing */
+ if( gidx_is_unknown(b_new) )
+ return;
+
+ /* Merge of unknown and known is known */
+ if( gidx_is_unknown(*b_union) )
+ {
+ *b_union = b_new;
+ return;
+ }
+
dims_union = GIDX_NDIMS(*b_union);
dims_new = GIDX_NDIMS(b_new);
{
float result;
int i;
- if ( a == NULL )
+ if ( a == NULL || gidx_is_unknown(a) )
{
- /* elog(ERROR, "gidx_volume received a null argument"); */
+ /* elog(ERROR, "gidx_volume received a null argument"); */
return 0.0;
}
result = GIDX_GET_MAX(a,0) - GIDX_GET_MIN(a,0);
/* Ensure the first argument has the higher dimensionality. */
static void gidx_dimensionality_check(GIDX **a, GIDX **b)
-{
+{
if ( GIDX_NDIMS(*a) < GIDX_NDIMS(*b) )
{
GIDX *tmp = *b;
elog(ERROR, "gidx_union_volume received two null arguments");
return 0.0;
}
- if ( a == NULL )
+
+ if ( gidx_is_unknown(a) && gidx_is_unknown(b) )
+ {
+ return 0.0;
+ }
+
+ if ( a == NULL || gidx_is_unknown(a) )
return gidx_volume(b);
- if ( b == NULL )
+ if ( b == NULL || gidx_is_unknown(b) )
return gidx_volume(a);
/* Ensure 'a' has the most dimensions. */
return 0.0;
}
+ if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+ {
+ return 0.0;
+ }
+
/* Ensure 'a' has the most dimensions. */
gidx_dimensionality_check(&a, &b);
int i;
int ndims_b;
POSTGIS_DEBUG(5, "entered function");
+
if ( (a == NULL) || (b == NULL) ) return FALSE;
+ if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+ return FALSE;
+
/* Ensure 'a' has the most dimensions. */
gidx_dimensionality_check(&a, &b);
if ( (a == NULL) || (b == NULL) ) return FALSE;
+ if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+ return FALSE;
+
dims_a = GIDX_NDIMS(a);
dims_b = GIDX_NDIMS(b);
if ( (a == NULL) && (b == NULL) ) return TRUE;
if ( (a == NULL) || (b == NULL) ) return FALSE;
+ if ( gidx_is_unknown(a) && gidx_is_unknown(b) )
+ return TRUE;
+
+ if ( gidx_is_unknown(a) || gidx_is_unknown(b) )
+ return FALSE;
+
/* Ensure 'a' has the most dimensions. */
gidx_dimensionality_check(&a, &b);
char gidxmem[GIDX_MAX_SIZE];
GIDX *bbox_out = (GIDX*)gidxmem;
int result = LW_SUCCESS;
-
int i;
-
+
POSTGIS_DEBUG(4, "[GIST] 'compress' function called");
/*
/* Extract our index key from the GiST entry. */
result = gserialized_datum_get_gidx_p(entry_in->key, bbox_out);
- /* Is the bounding box valid (non-empty, non-infinite)? If not, return input uncompressed. */
+ /* Is the bounding box valid (non-empty, non-infinite) ?
+ * If not, use the "unknown" GIDX. */
if ( result == LW_FAILURE )
{
POSTGIS_DEBUG(4, "[GIST] empty geometry!");
- PG_RETURN_POINTER(entry_in);
+ gidx_set_unknown(bbox_out);
+ gistentryinit(*entry_out, PointerGetDatum(gidx_copy(bbox_out)),
+ entry_in->rel, entry_in->page,
+ entry_in->offset, FALSE);
+ PG_RETURN_POINTER(entry_out);
}
POSTGIS_DEBUGF(4, "[GIST] got entry_in->key: %s", gidx_to_string(bbox_out));
- /* Check all the dimensions for finite values */
+ /* Check all the dimensions for finite values.
+ * If not, use the "unknown" GIDX as a key */
for ( i = 0; i < GIDX_NDIMS(bbox_out); i++ )
{
- if ( ! finite(GIDX_GET_MAX(bbox_out, i)) || ! finite(GIDX_GET_MIN(bbox_out, i)) )
+ if ( ! finite(GIDX_GET_MAX(bbox_out, i))
+ || ! finite(GIDX_GET_MIN(bbox_out, i)) )
{
- POSTGIS_DEBUG(4, "[GIST] infinite geometry!");
- PG_RETURN_POINTER(entry_in);
+ gidx_set_unknown(bbox_out);
+ gistentryinit(*entry_out,
+ PointerGetDatum(gidx_copy(bbox_out)),
+ entry_in->rel, entry_in->page,
+ entry_in->offset, FALSE);
+ PG_RETURN_POINTER(entry_out);
}
}