PostGIS  2.4.9dev-r@@SVN_REVISION@@
brin_nd.c
Go to the documentation of this file.
1 #include "postgis_brin.h"
2 
3 /*
4  * As we index geometries but store either a BOX2DF or GIDX according to the
5  * operator class, we need to overload the original brin_inclusion_add_value()
6  * function to be able to do this. Other original mandatory support functions
7  * doesn't need to be overloaded.
8  *
9  * The previous limitation might be lifted, but we also eliminate some overhead
10  * by doing it this way, namely calling different functions through the
11  * FunctionCallInvoke machinery for each heap tuple.
12  */
13 
14 Datum gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum
15  newval, bool isnull, int max_dims);
16 
17 /*
18  * As for the GiST case, geographies are converted into GIDX before
19  * they are added to the other index keys
20  */
22 Datum
24 {
25  BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
26  BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
27  Datum newval = PG_GETARG_DATUM(2);
28  bool isnull = PG_GETARG_BOOL(3);
29 
30  PG_RETURN_DATUM(gidx_brin_inclusion_add_value(bdesc, column, newval, isnull,
31  2));
32 }
33 
34 
36 Datum
38 {
39  BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
40  BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
41  Datum newval = PG_GETARG_DATUM(2);
42  bool isnull = PG_GETARG_BOOL(3);
43 
44  PG_RETURN_DATUM(gidx_brin_inclusion_add_value(bdesc, column, newval, isnull,
45  3));
46 }
47 
49 Datum
51 {
52  BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
53  BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
54  Datum newval = PG_GETARG_DATUM(2);
55  bool isnull = PG_GETARG_BOOL(3);
56 
57  PG_RETURN_DATUM(gidx_brin_inclusion_add_value(bdesc, column, newval, isnull,
58  4));
59 }
60 
61 Datum
62 gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval,
63  bool isnull, int max_dims)
64 {
65  char gboxmem[GIDX_MAX_SIZE];
66  GIDX *gidx_geom, *gidx_key;
67  int dims_geom, dims_key, i;
68 
69  Assert(max_dims <= GIDX_MAX_DIM);
70 
71  /*
72  * If the new value is null, we record that we saw it if it's the first
73  * one; otherwise, there's nothing to do.
74  */
75  if (isnull)
76  {
77  if (column->bv_hasnulls)
78  PG_RETURN_BOOL(false);
79 
80  column->bv_hasnulls = true;
81  PG_RETURN_BOOL(true);
82  }
83 
84  /*
85  * No need for further processing if the block range is already initialized
86  * and is marked as containing unmergeable values.
87  */
88  if (!column->bv_allnulls &&
89  DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
90  PG_RETURN_BOOL(false);
91 
92  /* create a new GIDX in stack memory, maximum dimensions */
93  gidx_geom = (GIDX *) gboxmem;
94 
95  /*
96  * check other cases where it is not possible to retrieve a box
97  */
98  if (gserialized_datum_get_gidx_p(newval, gidx_geom) == LW_FAILURE)
99  {
100  /*
101  * Empty entries have to be supported in the opclass: test the passed
102  * new value for emptiness; if it returns true, we need to set the
103  * "contains empty" flag in the element (unless already set).
104  */
106  {
107  if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
108  {
109  column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
110  PG_RETURN_BOOL(true);
111  }
112 
113  PG_RETURN_BOOL(false);
114  } else
115  {
116  /*
117  * in case the entry is not empty and it is not possible to
118  * retrieve a box, raise an error
119  */
120  elog(ERROR, "Error while extracting the gidx from the geom");
121  }
122  }
123 
124  /* Get the actual dimension of the geometry */
125  dims_geom = GIDX_NDIMS(gidx_geom);
126 
127  /* if the recorded value is null, we just need to store the GIDX */
128  if (column->bv_allnulls)
129  {
130  /*
131  * It's not safe to summarize geometries of different number of
132  * dimensions in the same range. We therefore fix the number of
133  * dimension for this range by storing the bounding box of the first
134  * geometry found as is, being careful not to store more dimension than
135  * defined in the opclass.
136  */
137  if (dims_geom > max_dims)
138  {
139  /*
140  * Diminush the varsize to only store the maximum number of
141  * dimensions allowed by the opclass
142  */
143  SET_VARSIZE(gidx_geom, VARHDRSZ + max_dims * 2 * sizeof(float));
144  dims_geom = max_dims;
145  }
146 
147  column->bv_values[INCLUSION_UNION] = datumCopy((Datum) gidx_geom, false,
148  GIDX_SIZE(dims_geom));
149  column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
150  column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
151  column->bv_allnulls = false;
152  PG_RETURN_BOOL(true);
153  }
154 
155  gidx_key = (GIDX *) column->bv_values[INCLUSION_UNION];
156  dims_key = GIDX_NDIMS(gidx_key);
157 
158  /*
159  * Mark the datum as unmergeable if its number of dimension is not the same
160  * as the one stored in the key of the current range
161  */
162  if (dims_key != dims_geom)
163  {
164  column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
165  PG_RETURN_BOOL(true);
166  }
167 
168  /* Check if the stored bounding box already contains the geometry's one */
169  if (gidx_contains(gidx_key, gidx_geom))
170  PG_RETURN_BOOL(false);
171 
172  /*
173  * Otherwise, we need to enlarge the stored GIDX to make it contains the
174  * current geometry. As we store a GIDX with a fixed number of dimensions,
175  * we just need adjust min and max
176  */
177  for ( i = 0; i < dims_key; i++ )
178  {
179  /* Adjust minimums */
180  GIDX_SET_MIN(gidx_key, i,
181  Min(GIDX_GET_MIN(gidx_key,i),GIDX_GET_MIN(gidx_geom,i)));
182  /* Adjust maximums */
183  GIDX_SET_MAX(gidx_key, i,
184  Max(GIDX_GET_MAX(gidx_key,i),GIDX_GET_MAX(gidx_geom,i)));
185  }
186 
187  PG_RETURN_BOOL(true);
188 }
Datum geom3d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
Definition: brin_nd.c:37
PG_FUNCTION_INFO_V1(geog_brin_inclusion_add_value)
#define INCLUSION_CONTAINS_EMPTY
Definition: postgis_brin.h:21
Datum gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval, bool isnull, int max_dims)
Definition: brin_nd.c:62
bool gidx_contains(GIDX *a, GIDX *b)
#define LW_FAILURE
Definition: liblwgeom.h:79
Datum geom4d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
Definition: brin_nd.c:50
#define INCLUSION_UNION
Definition: postgis_brin.h:19
bool is_gserialized_from_datum_empty(Datum the_datum)
Definition: brin_common.c:4
#define INCLUSION_UNMERGEABLE
Definition: postgis_brin.h:20
Datum geog_brin_inclusion_add_value(PG_FUNCTION_ARGS)
Definition: brin_nd.c:23