PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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
18static 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 */
26Datum
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
40Datum
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
53Datum
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
65static Datum
66gidx_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
195static GIDX *
196gidx_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
215Datum 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
224Datum 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
233Datum 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
#define INCLUSION_UNION
#define INCLUSION_CONTAINS_EMPTY