• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

estebanzimanyi / MobilityDB / 9954227796

16 Jul 2024 09:23AM UTC coverage: 95.245% (-0.04%) from 95.287%
9954227796

push

github

estebanzimanyi
Add function stboxesFromSegs

13 of 13 new or added lines in 2 files covered. (100.0%)

14 existing lines in 3 files now uncovered.

31467 of 33038 relevant lines covered (95.24%)

772326.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.09
/mobilitydb/src/point/tpoint_tile.c
1
/*****************************************************************************
2
 *
3
 * This MobilityDB code is provided under The PostgreSQL License.
4
 * Copyright (c) 2016-2024, Université libre de Bruxelles and MobilityDB
5
 * contributors
6
 *
7
 * MobilityDB includes portions of PostGIS version 3 source code released
8
 * under the GNU General Public License (GPLv2 or later).
9
 * Copyright (c) 2001-2024, PostGIS contributors
10
 *
11
 * Permission to use, copy, modify, and distribute this software and its
12
 * documentation for any purpose, without fee, and without a written
13
 * agreement is hereby granted, provided that the above copyright notice and
14
 * this paragraph and the following two paragraphs appear in all copies.
15
 *
16
 * IN NO EVENT SHALL UNIVERSITE LIBRE DE BRUXELLES BE LIABLE TO ANY PARTY FOR
17
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
18
 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
19
 * EVEN IF UNIVERSITE LIBRE DE BRUXELLES HAS BEEN ADVISED OF THE POSSIBILITY
20
 * OF SUCH DAMAGE.
21
 *
22
 * UNIVERSITE LIBRE DE BRUXELLES SPECIFICALLY DISCLAIMS ANY WARRANTIES,
23
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24
 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON
25
 * AN "AS IS" BASIS, AND UNIVERSITE LIBRE DE BRUXELLES HAS NO OBLIGATIONS TO
26
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
27
 *
28
 *****************************************************************************/
29

30
/**
31
 * @file
32
 * @brief Functions for spatial and spatiotemporal tiles
33
 */
34

35
/* C */
36
#include <assert.h>
37
/* PostgreSQL */
38
#include <postgres.h>
39
#include <funcapi.h>
40
#include <utils/timestamp.h>
41
/* PostGIS */
42
#include <liblwgeom.h>
43
/* MEOS */
44
#include <meos.h>
45
#include <meos_internal.h>
46
#include "general/temporal_tile.h"
47
#include "point/stbox.h"
48
#include "point/tpoint_spatialfuncs.h"
49
#include "point/tpoint_tile.h"
50
/* MobilityDB */
51
#include "pg_point/postgis.h"
52

53
/*****************************************************************************/
54

55
PGDLLEXPORT Datum Stbox_tile_list(PG_FUNCTION_ARGS);
56
PG_FUNCTION_INFO_V1(Stbox_tile_list);
6✔
57
/**
58
 * @brief @ingroup mobilitydb_temporal_analytics_tile
59
 * @brief Return the multidimensional grid of a spatiotemporal box
60
 * @sqlfn multidimGrid()
61
 */
62
Datum
63
Stbox_tile_list(PG_FUNCTION_ARGS)
3,513✔
64
{
65
  FuncCallContext *funcctx;
66
  STboxGridState *state;
67
  bool isnull[2] = {0,0}; /* needed to say no value is null */
3,513✔
68
  Datum tuple_arr[2]; /* used to construct the composite return value */
69
  HeapTuple tuple;
70
  Datum result; /* the actual composite return value */
71

72
  /* If the function is being called for the first time */
73
  if (SRF_IS_FIRSTCALL())
3,513✔
74
  {
75
    /* Get input parameters */
76
    STBox *bounds = PG_GETARG_STBOX_P(0);
308✔
77
    ensure_has_X_stbox(bounds);
308✔
78
    ensure_not_geodetic(bounds->flags);
308✔
79
    double xsize = PG_GETARG_FLOAT8(1);
307✔
80
    double ysize = PG_GETARG_FLOAT8(2);
307✔
81
    double zsize = PG_GETARG_FLOAT8(3);
307✔
82
    ensure_positive_datum(Float8GetDatum(xsize), T_FLOAT8);
307✔
83
    ensure_positive_datum(Float8GetDatum(ysize), T_FLOAT8);
307✔
84
    ensure_positive_datum(Float8GetDatum(zsize), T_FLOAT8);
307✔
85
    GSERIALIZED *sorigin;
86
    int64 tunits = 0; /* make compiler quiet */
87
    TimestampTz torigin = 0; /* make compiler quiet */
88
    assert(PG_NARGS() == 6 || PG_NARGS() == 8);
89
    bool border_inc;
90
    if (PG_NARGS() == 6)
307✔
91
    {
92
      sorigin = PG_GETARG_GSERIALIZED_P(4);
105✔
93
      border_inc = PG_GETARG_BOOL(5);
105✔
94
    }
95
    else /* PG_NARGS() == 8 */
96
    {
97
      /* If time arguments are given */
98
      ensure_has_T_stbox(bounds);
202✔
99
      Interval *duration = PG_GETARG_INTERVAL_P(4);
202✔
100
      ensure_valid_duration(duration);
202✔
101
      tunits = interval_units(duration);
202✔
102
      sorigin = PG_GETARG_GSERIALIZED_P(5);
202✔
103
      torigin = PG_GETARG_TIMESTAMPTZ(6);
202✔
104
      border_inc = PG_GETARG_BOOL(7);
202✔
105
    }
106
    ensure_not_empty(sorigin);
307✔
107
    ensure_point_type(sorigin);
307✔
108
    /* Since we pass by default Point(0 0 0) as origin independently of the
109
     * input STBox, we test the same spatial dimensionality only for STBox Z.
110
     * Also, since when zsize is not given we pass by default xsize, if we
111
     * don't have an STBox Z we set zsize to 0 */
112
    if (MEOS_FLAGS_GET_Z(bounds->flags))
307✔
113
      ensure_same_spatial_dimensionality_stbox_gs(bounds, sorigin);
3✔
114
    else
115
      zsize = 0;
116
    int32 srid = bounds->srid;
306✔
117
    int32 gs_srid = gserialized_get_srid(sorigin);
306✔
118
    if (gs_srid != SRID_UNKNOWN)
306✔
119
      ensure_same_srid(srid, gs_srid);
1✔
120
    POINT3DZ pt;
121
    memset(&pt, 0, sizeof(POINT3DZ));
122
    if (FLAGS_GET_Z(sorigin->gflags))
305✔
123
    {
124
      const POINT3DZ *p3d = GSERIALIZED_POINT3DZ_P(sorigin);
103✔
125
      pt.x = p3d->x;
103✔
126
      pt.y = p3d->y;
103✔
127
      pt.z = p3d->z;
103✔
128
    }
129
    else
130
    {
131
      /* Initialize to 0 the Z dimension if it is missing */
132
      memset(&pt, 0, sizeof(POINT3DZ));
133
      const POINT2D *p2d = GSERIALIZED_POINT2D_P(sorigin);
202✔
134
      pt.x = p2d->x;
202✔
135
      pt.y = p2d->y;
202✔
136
      /* Since when zsize is not given we pass by default xsize, if the box does
137
       * not have Z dimension we set zsize to 0 */
138
      zsize = 0;
139
    }
140

141
    /* Initialize the FuncCallContext */
142
    funcctx = SRF_FIRSTCALL_INIT();
305✔
143
    /* Switch to memory context appropriate for multiple function calls */
144
    MemoryContext oldcontext =
145
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
305✔
146
    /* Create function state */
147
    funcctx->user_fctx = stbox_tile_state_make(NULL, bounds, xsize, ysize,
305✔
148
      zsize, tunits, pt, torigin, border_inc);
149
    /* Build a tuple description for a multidim_grid tuple */
150
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
305✔
151
    BlessTupleDesc(funcctx->tuple_desc);
305✔
152
    MemoryContextSwitchTo(oldcontext);
153
  }
154

155
  /* Stuff done on every call of the function */
156
  funcctx = SRF_PERCALL_SETUP();
3,510✔
157
  /* Get state */
158
  state = funcctx->user_fctx;
3,510✔
159
  /* Stop when we've used up all the grid tiles */
160
  if (state->done)
3,510✔
161
  {
162
    /* Switch to memory context appropriate for multiple function calls */
163
    MemoryContext oldcontext =
164
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
300✔
165
    pfree(state);
300✔
166
    MemoryContextSwitchTo(oldcontext);
167
    SRF_RETURN_DONE(funcctx);
300✔
168
  }
169

170
  /* Allocate box */
171
  STBox *box = palloc(sizeof(STBox));
3,210✔
172
  /* Get current tile and advance state
173
   * There is no need to test if the tile is found since all tiles should be
174
   * generated and thus there is no associated bit matrix */
175
  stbox_tile_state_get(state, box);
3,210✔
176
  stbox_tile_state_next(state);
3,210✔
177
  /* Form tuple and return
178
   * The i value was incremented with the previous _next function call */
179
  tuple_arr[0] = Int32GetDatum(state->i - 1);
3,210✔
180
  tuple_arr[1] = PointerGetDatum(box);
3,210✔
181
  tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
3,210✔
182
  result = HeapTupleGetDatum(tuple);
3,210✔
183
  SRF_RETURN_NEXT(funcctx, result);
3,210✔
184
}
185

186
PGDLLEXPORT Datum Stbox_tile(PG_FUNCTION_ARGS);
187
PG_FUNCTION_INFO_V1(Stbox_tile);
6✔
188
/**
189
 * @ingroup mobilitydb_temporal_analytics_tile
190
 * @brief Return a tile in the multidimensional grid of a spatiotemporal box
191
 * @sqlfn multidimTile()
192
 */
193
Datum
194
Stbox_tile(PG_FUNCTION_ARGS)
448✔
195
{
196
  GSERIALIZED *point = PG_GETARG_GSERIALIZED_P(0);
448✔
197
  double xsize, ysize, zsize;
198
  GSERIALIZED *sorigin;
199
  TimestampTz t = 0; /* make compiler quiet */
200
  TimestampTz torigin = 0; /* make compiler quiet */
201
  Interval *duration = NULL; /* make compiler quiet */
202
  bool hast = false;
203
  assert(PG_NARGS() == 5 || PG_NARGS() == 8);
204
  if (PG_NARGS() == 5)
448✔
205
  {
206
    xsize = PG_GETARG_FLOAT8(1);
42✔
207
    ysize = PG_GETARG_FLOAT8(2);
42✔
208
    zsize = PG_GETARG_FLOAT8(3);
42✔
209
    sorigin = PG_GETARG_GSERIALIZED_P(4);
42✔
210
  }
211
  else /* PG_NARGS() == 8 */
212
  {
213
    /* If time arguments are given */
214
    t = PG_GETARG_TIMESTAMPTZ(1);
406✔
215
    xsize = PG_GETARG_FLOAT8(2);
406✔
216
    ysize = PG_GETARG_FLOAT8(3);
406✔
217
    zsize = PG_GETARG_FLOAT8(4);
406✔
218
    duration = PG_GETARG_INTERVAL_P(5);
406✔
219
    sorigin = PG_GETARG_GSERIALIZED_P(6);
406✔
220
    torigin = PG_GETARG_TIMESTAMPTZ(7);
406✔
221
    hast = true;
222
  }
223

224
  PG_RETURN_STBOX_P(stbox_tile(point, t, xsize, ysize, zsize, duration,
448✔
225
    sorigin, torigin, hast));
226
}
227

228
/*****************************************************************************
229
 * Split functions
230
 *****************************************************************************/
231

232
/**
233
 * @brief Split a temporal point with respect to a spatial and possibly a
234
 * temporal grid
235
 */
236
Datum
237
Tpoint_space_time_split_ext(FunctionCallInfo fcinfo, bool timesplit)
164✔
238
{
239
  FuncCallContext *funcctx;
240
  STboxGridState *state;
241
  bool hasz;
242
  bool isnull[3] = {0,0,0}; /* needed to say no value is null */
164✔
243
  Datum tuple_arr[3]; /* used to construct the composite return value */
244
  HeapTuple tuple;
245
  Datum result; /* the actual composite return value */
246

247
  /* If the function is being called for the first time */
248
  if (SRF_IS_FIRSTCALL())
164✔
249
  {
250
    /* Initialize the FuncCallContext */
251
    funcctx = SRF_FIRSTCALL_INIT();
52✔
252
    /* Switch to memory context appropriate for multiple function calls */
253
    MemoryContext oldcontext =
254
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
52✔
255

256
    /* Get input parameters */
257
    Temporal *temp = PG_GETARG_TEMPORAL_P(0);
52✔
258
    double xsize = PG_GETARG_FLOAT8(1);
52✔
259
    double ysize = PG_GETARG_FLOAT8(2);
52✔
260
    double zsize = PG_GETARG_FLOAT8(3);
52✔
261
    Interval *duration = NULL;
262
    TimestampTz torigin = 0;
263
    int i = 4;
264
    if (timesplit)
52✔
265
      duration = PG_GETARG_INTERVAL_P(i++);
26✔
266
    GSERIALIZED *sorigin = PG_GETARG_GSERIALIZED_P(i++);
52✔
267
    if (timesplit)
52✔
268
      torigin = PG_GETARG_TIMESTAMPTZ(i++);
26✔
269
    bool bitmatrix = PG_GETARG_BOOL(i++);
52✔
270
    if (temporal_num_instants(temp) == 1)
52✔
271
      bitmatrix = false;
272
    bool border_inc = PG_GETARG_BOOL(i++);
52✔
273

274
    /* Initialize state and verify parameter validity */
275
    int ntiles;
276
    STboxGridState *state = tpoint_space_time_split_init(temp, xsize, ysize,
52✔
277
      zsize, duration, sorigin, torigin, bitmatrix, border_inc, &ntiles);
278

279
    /* Create function state */
280
    funcctx->user_fctx = state;
50✔
281

282
    /* Build a tuple description for a multidimensional grid tuple */
283
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
50✔
284
    BlessTupleDesc(funcctx->tuple_desc);
50✔
285
    MemoryContextSwitchTo(oldcontext);
286
  }
287

288
  /* Stuff done on every call of the function */
289
  funcctx = SRF_PERCALL_SETUP();
162✔
290
  /* Get state */
291
  state = funcctx->user_fctx;
162✔
292
  /* We need to loop since atStbox may be NULL */
293
  while (true)
294
  {
295
    /* Stop when we have used up all the grid tiles */
296
    if (state->done)
381✔
297
    {
298
      /* Switch to memory context appropriate for multiple function calls */
299
      MemoryContext oldcontext =
300
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
50✔
301
      if (state->bm)
50✔
302
         pfree(state->bm);
40✔
303
      pfree(state);
50✔
304
      MemoryContextSwitchTo(oldcontext);
305
      SRF_RETURN_DONE(funcctx);
50✔
306
    }
307

308
    /* Get current tile (if any) and advance state
309
     * It is necessary to test if we found a tile since the previous tile
310
     * may be the last one set in the associated bit matrix */
311
    STBox box;
312
    bool found = stbox_tile_state_get(state, &box);
331✔
313
    if (! found)
331✔
314
    {
315
      /* Switch to memory context appropriate for multiple function calls */
316
      MemoryContext oldcontext =
UNCOV
317
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
×
UNCOV
318
      if (state->bm)
×
UNCOV
319
        pfree(state->bm);
×
UNCOV
320
      pfree(state);
×
321
      MemoryContextSwitchTo(oldcontext);
UNCOV
322
      SRF_RETURN_DONE(funcctx);
×
323
    }
324
    stbox_tile_state_next(state);
331✔
325

326
    /* Restrict the temporal point to the box */
327
    Temporal *atstbox = tpoint_restrict_stbox(state->temp, &box, BORDER_EXC,
331✔
328
      REST_AT);
329
    if (atstbox == NULL)
331✔
330
      continue;
219✔
331

332
    /* Form tuple and return */
333
    int i = 0;
334
    hasz = MEOS_FLAGS_GET_Z(state->temp->flags);
112✔
335
    tuple_arr[i++] = PointerGetDatum(geopoint_make(box.xmin, box.ymin,
112✔
336
      box.zmin, hasz, false, box.srid));
337
    if (timesplit)
112✔
338
      tuple_arr[i++] = box.period.lower;
71✔
339
    tuple_arr[i++] = PointerGetDatum(atstbox);
112✔
340
    tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
112✔
341
    result = HeapTupleGetDatum(tuple);
112✔
342
    SRF_RETURN_NEXT(funcctx, result);
112✔
343
  }
344
}
345

346
PGDLLEXPORT Datum Tpoint_space_split(PG_FUNCTION_ARGS);
347
PG_FUNCTION_INFO_V1(Tpoint_space_split);
2✔
348
/**
349
 * @ingroup mobilitydb_temporal_analytics_tile
350
 * @brief Return a temporal point split with respect to a spatial grid
351
 * @sqlfn spaceSplit()
352
 */
353
Datum
354
Tpoint_space_split(PG_FUNCTION_ARGS)
67✔
355
{
356
  return Tpoint_space_time_split_ext(fcinfo, false);
67✔
357
}
358

359
PGDLLEXPORT Datum Tpoint_space_time_split(PG_FUNCTION_ARGS);
360
PG_FUNCTION_INFO_V1(Tpoint_space_time_split);
2✔
361
/**
362
 * @ingroup mobilitydb_temporal_analytics_tile
363
 * @brief Return a temporal point split with respect to a spatiotemporal grid
364
 * @sqlfn spaceTimeSplit()
365
 */
366
Datum
367
Tpoint_space_time_split(PG_FUNCTION_ARGS)
97✔
368
{
369
  return Tpoint_space_time_split_ext(fcinfo, true);
97✔
370
}
371

372
/*****************************************************************************/
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc