PostGIS  3.7.0dev-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 
15  BrinDesc *bdesc, BrinValues *column,
16  Datum newval, bool isnull, int max_dims);
17 
18 static GIDX * gidx_brin_inclusion_merge(
19  GIDX *gidx_key, GIDX *gidx_geom);
20 
21 /*
22  * As for the GiST case, geographies are converted into GIDX before
23  * they are added to the other index keys
24  */
26 Datum
28 {
29  BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
30  BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
31  Datum newval = PG_GETARG_DATUM(2);
32  bool isnull = PG_GETARG_BOOL(3);
33 
34  PG_RETURN_DATUM(gidx_brin_inclusion_add_value(bdesc, column, newval, isnull,
35  2));
36 }
37 
38 
40 Datum
42 {
43  BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
44  BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
45  Datum newval = PG_GETARG_DATUM(2);
46  bool isnull = PG_GETARG_BOOL(3);
47 
48  PG_RETURN_DATUM(gidx_brin_inclusion_add_value(bdesc, column, newval, isnull,
49  3));
50 }
51 
53 Datum
55 {
56  BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0);
57  BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1);
58  Datum newval = PG_GETARG_DATUM(2);
59  bool isnull = PG_GETARG_BOOL(3);
60 
61  PG_RETURN_DATUM(gidx_brin_inclusion_add_value(bdesc, column, newval, isnull,
62  4));
63 }
64 
65 static Datum
66 gidx_brin_inclusion_add_value(__attribute__((__unused__)) BrinDesc *bdesc,
67  BrinValues *column, Datum newval, bool isnull, int max_dims)
68 {
69  char gboxmem[GIDX_MAX_SIZE];
70  GIDX *gidx_geom, *gidx_key;
71  int dims_geom, dims_key, i;
72 
73  Assert(max_dims <= GIDX_MAX_DIM);
74 
75  /*
76  * If the new value is null, we record that we saw it if it's the first
77  * one; otherwise, there's nothing to do.
78  */
79  if (isnull)
80  {
81  if (column->bv_hasnulls)
82  PG_RETURN_BOOL(false);
83 
84  column->bv_hasnulls = true;
85  PG_RETURN_BOOL(true);
86  }
87 
88  /*
89  * No need for further processing if the block range is already initialized
90  * and is marked as containing unmergeable values.
91  */
92  if (!column->bv_allnulls &&
93  DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE]))
94  PG_RETURN_BOOL(false);
95 
96  /* create a new GIDX in stack memory, maximum dimensions */
97  gidx_geom = (GIDX *) gboxmem;
98 
99  /*
100  * check other cases where it is not possible to retrieve a box
101  */
102  if (gserialized_datum_get_gidx_p(newval, gidx_geom) == LW_FAILURE)
103  {
104  /*
105  * Empty entries have to be supported in the opclass: test the passed
106  * new value for emptiness; if it returns true, we need to set the
107  * "contains empty" flag in the element (unless already set).
108  */
110  {
111  if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
112  {
113  column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(true);
114  PG_RETURN_BOOL(true);
115  }
116 
117  PG_RETURN_BOOL(false);
118  } else
119  {
120  /*
121  * in case the entry is not empty and it is not possible to
122  * retrieve a box, raise an error
123  */
124  elog(ERROR, "Error while extracting the gidx from the geom");
125  }
126  }
127 
128  /* Get the actual dimension of the geometry */
129  dims_geom = GIDX_NDIMS(gidx_geom);
130 
131  /* if the recorded value is null, we just need to store the GIDX */
132  if (column->bv_allnulls)
133  {
134  /*
135  * It's not safe to summarize geometries of different number of
136  * dimensions in the same range. We therefore fix the number of
137  * dimension for this range by storing the bounding box of the first
138  * geometry found as is, being careful not to store more dimension than
139  * defined in the opclass.
140  */
141  if (dims_geom > max_dims)
142  {
143  /*
144  * Diminush the varsize to only store the maximum number of
145  * dimensions allowed by the opclass
146  */
147  SET_VARSIZE(gidx_geom, VARHDRSZ + max_dims * 2 * sizeof(float));
148  dims_geom = max_dims;
149  }
150 
151  column->bv_values[INCLUSION_UNION] = datumCopy((Datum) gidx_geom, false,
152  GIDX_SIZE(dims_geom));
153  column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false);
154  column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false);
155  column->bv_allnulls = false;
156  PG_RETURN_BOOL(true);
157  }
158 
159  gidx_key = (GIDX *) column->bv_values[INCLUSION_UNION];
160  dims_key = GIDX_NDIMS(gidx_key);
161 
162  /*
163  * Mark the datum as unmergeable if its number of dimension is not the same
164  * as the one stored in the key of the current range
165  */
166  if (dims_key != dims_geom)
167  {
168  column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(true);
169  PG_RETURN_BOOL(true);
170  }
171 
172  /* Check if the stored bounding box already contains the geometry's one */
173  if (gidx_contains(gidx_key, gidx_geom))
174  PG_RETURN_BOOL(false);
175 
176  /*
177  * Otherwise, we need to enlarge the stored GIDX to make it contains the
178  * current geometry. As we store a GIDX with a fixed number of dimensions,
179  * we just need adjust min and max
180  */
181  for ( i = 0; i < dims_key; i++ )
182  {
183  /* Adjust minimums */
184  GIDX_SET_MIN(gidx_key, i,
185  Min(GIDX_GET_MIN(gidx_key,i),GIDX_GET_MIN(gidx_geom,i)));
186  /* Adjust maximums */
187  GIDX_SET_MAX(gidx_key, i,
188  Max(GIDX_GET_MAX(gidx_key,i),GIDX_GET_MAX(gidx_geom,i)));
189  }
190 
191  PG_RETURN_BOOL(true);
192 }
193 
194 
195 static GIDX *
196 gidx_brin_inclusion_merge(GIDX *gidx_key, GIDX *gidx_geom)
197 {
198  if (!gidx_contains(gidx_key, gidx_geom))
199  {
200  for (uint32_t i = 0; i < GIDX_NDIMS(gidx_key); i++)
201  {
202  /* Adjust minimums */
203  GIDX_SET_MIN(gidx_key, i,
204  Min(GIDX_GET_MIN(gidx_key,i),GIDX_GET_MIN(gidx_geom,i)));
205  /* Adjust maximums */
206  GIDX_SET_MAX(gidx_key, i,
207  Max(GIDX_GET_MAX(gidx_key,i),GIDX_GET_MAX(gidx_geom,i)));
208  }
209  }
210 
211  return gidx_key;
212 }
213 
215 Datum geog_brin_inclusion_merge(PG_FUNCTION_ARGS)
216 {
217  GIDX *key = (GIDX *) PG_GETARG_POINTER(0);
218  GIDX *geom = (GIDX *) PG_GETARG_POINTER(1);
219 
220  PG_RETURN_POINTER(gidx_brin_inclusion_merge(key, geom));
221 }
222 
224 Datum geom3d_brin_inclusion_merge(PG_FUNCTION_ARGS)
225 {
226  GIDX *key = (GIDX *) PG_GETARG_POINTER(0);
227  GIDX *geom = (GIDX *) PG_GETARG_POINTER(1);
228 
229  PG_RETURN_POINTER(gidx_brin_inclusion_merge(key, geom));
230 }
231 
233 Datum geom4d_brin_inclusion_merge(PG_FUNCTION_ARGS)
234 {
235  GIDX *key = (GIDX *) PG_GETARG_POINTER(0);
236  GIDX *geom = (GIDX *) PG_GETARG_POINTER(1);
237 
238  PG_RETURN_POINTER(gidx_brin_inclusion_merge(key, geom));
239 }
240 
241 
bool is_gserialized_from_datum_empty(Datum the_datum)
Definition: brin_common.c:4
static Datum gidx_brin_inclusion_add_value(BrinDesc *bdesc, BrinValues *column, Datum newval, bool isnull, int max_dims)
Datum geom3d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
Definition: brin_nd.c:41
Datum geom4d_brin_inclusion_merge(PG_FUNCTION_ARGS)
Definition: brin_nd.c:233
Datum geom4d_brin_inclusion_add_value(PG_FUNCTION_ARGS)
Definition: brin_nd.c:54
Datum geom3d_brin_inclusion_merge(PG_FUNCTION_ARGS)
Definition: brin_nd.c:224
static GIDX * gidx_brin_inclusion_merge(GIDX *gidx_key, GIDX *gidx_geom)
Definition: brin_nd.c:196
PG_FUNCTION_INFO_V1(geog_brin_inclusion_add_value)
Datum geog_brin_inclusion_add_value(PG_FUNCTION_ARGS)
Definition: brin_nd.c:27
Datum geog_brin_inclusion_merge(PG_FUNCTION_ARGS)
Definition: brin_nd.c:215
bool gidx_contains(GIDX *a, GIDX *b)
#define LW_FAILURE
Definition: liblwgeom.h:96
#define __attribute__(x)
Definition: liblwgeom.h:228
#define INCLUSION_UNMERGEABLE
Definition: postgis_brin.h:20
#define INCLUSION_UNION
Definition: postgis_brin.h:19
#define INCLUSION_CONTAINS_EMPTY
Definition: postgis_brin.h:21