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

estebanzimanyi / MobilityDB / 14260230766

04 Apr 2025 07:11AM UTC coverage: 94.496% (-0.4%) from 94.894%
14260230766

push

github

web-flow
Implementation of the tpose type (#664)

910 of 950 new or added lines in 41 files covered. (95.79%)

736 existing lines in 39 files now uncovered.

31798 of 33650 relevant lines covered (94.5%)

1243116.88 hits per line

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

96.8
/mobilitydb/src/general/temporal_tile.c
1
/***********************************************************************
2
 *
3
 * This MobilityDB code is provided under The PostgreSQL License.
4
 * Copyright (c) 2016-2025, 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-2025, 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 Bin and tile functions for temporal types
33
 *
34
 * @note The time bin functions are inspired from TimescaleDB.
35
 * https://docs.timescale.com/latest/api#time_bucket
36
 */
37

38
#include "general/temporal_tile.h"
39

40
/* C */
41
#include <assert.h>
42
/* PostgreSQL */
43
#include <postgres.h>
44
#include <utils/array.h>
45
#include <funcapi.h>
46
/* MEOS */
47
#include <meos.h>
48
#include <meos_internal.h>
49
#include "general/span.h"
50
#include "general/tbox.h"
51
#include "general/temporal.h"
52
#include "geo/tgeo_spatialfuncs.h"
53
/* MobilityDB */
54
#include "pg_general/meos_catalog.h"
55
#include "pg_general/type_util.h"
56

57
/*****************************************************************************/
58

59
PGDLLEXPORT Datum Span_bins(PG_FUNCTION_ARGS);
60
PG_FUNCTION_INFO_V1(Span_bins);
13✔
61
/**
62
 * @ingroup mobilitydb_temporal_analytics_tile
63
 * @brief Return the bins of a span
64
 * @sqlfn bins()
65
 */
66
Datum
67
Span_bins(PG_FUNCTION_ARGS)
2,206✔
68
{
69
  FuncCallContext *funcctx;
70

71
  /* If the function is being called for the first time */
72
  if (SRF_IS_FIRSTCALL())
2,206✔
73
  {
74
    /* Get input parameters */
75
    Span *bounds = PG_GETARG_SPAN_P(0);
605✔
76
    Datum size, origin;
77
    assert(numspan_type(bounds->spantype) || timespan_type(bounds->spantype));
78
    if (numspan_type(bounds->spantype))
605✔
79
    {
80
      size = PG_GETARG_DATUM(1);
402✔
81
      origin = PG_GETARG_DATUM(2);
402✔
82
      meosType basetype = oid_type(get_fn_expr_argtype(fcinfo->flinfo, 1));
402✔
83
      ensure_positive_datum(size, basetype);
402✔
84
    }
85
    else if (bounds->spantype == T_DATESPAN)
203✔
86
    {
87
      Interval *duration = PG_GETARG_INTERVAL_P(1);
3✔
88
      origin = PG_GETARG_DATUM(2);
3✔
89
      ensure_valid_day_duration(duration);
3✔
90
      size = Int32GetDatum((int)(interval_units(duration) / USECS_PER_DAY));
2✔
91
    }
92
    else /*(span->spantype == T_TSTZSPAN) */
93
    {
94
      Interval *duration = PG_GETARG_INTERVAL_P(1);
200✔
95
      origin = PG_GETARG_DATUM(2);
200✔
96
      ensure_valid_duration(duration);
200✔
97
      size = Int64GetDatum(interval_units(duration));
200✔
98
    }
99

100
    /* Initialize the FuncCallContext */
101
    funcctx = SRF_FIRSTCALL_INIT();
604✔
102
    /* Switch to memory context appropriate for multiple function calls */
103
    MemoryContext oldcontext =
104
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
604✔
105
    /* Create function state */
106
    funcctx->user_fctx = span_bin_state_make(NULL, bounds, size, origin);
604✔
107
    /* Build a tuple description for the function output */
108
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
604✔
109
    BlessTupleDesc(funcctx->tuple_desc);
604✔
110
    MemoryContextSwitchTo(oldcontext);
111
  }
112

113
  /* Stuff done on every call of the function */
114
  funcctx = SRF_PERCALL_SETUP();
2,205✔
115
  /* Get state */
116
  SpanBinState *state = funcctx->user_fctx;
2,205✔
117
  /* Stop when we've used up all bins */
118
  if (state->done)
2,205✔
119
  {
120
    /* Switch to memory context appropriate for multiple function calls */
121
    MemoryContext oldcontext =
122
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
596✔
123
    pfree(state);
596✔
124
    MemoryContextSwitchTo(oldcontext);
125
    SRF_RETURN_DONE(funcctx);
596✔
126
  }
127

128
  /* Allocate span */
129
  Span *span = palloc(sizeof(Span));
1,609✔
130
  /* Used to construct the composite return value */
131
  Datum values[2];
132
  /* Store index */
133
  values[0] = Int32GetDatum(state->i);
1,609✔
134
  /* Generate bin */
135
  span_bin_state_set(state->value, state->size, state->span.basetype,
1,609✔
136
    state->span.spantype, span);
1,609✔
137
  values[1] = PointerGetDatum(span);
1,609✔
138
  /* Advance state */
139
  span_bin_state_next(state);
1,609✔
140
  /* Form tuple and return */
141
  bool isnull[2] = {0,0}; /* needed to say no value is null */
1,609✔
142
  HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, values, isnull);
1,609✔
143
  Datum result = HeapTupleGetDatum(tuple);
144
  SRF_RETURN_NEXT(funcctx, result);
1,609✔
145
}
146

147
/*****************************************************************************/
148

149
PGDLLEXPORT Datum Value_bin(PG_FUNCTION_ARGS);
150
PG_FUNCTION_INFO_V1(Value_bin);
8✔
151
/**
152
 * @ingroup mobilitydb_temporal_analytics_tile
153
 * @brief Return a span bin in a bin list for number spans
154
 * @sqlfn getValueBin()
155
 */
156
Datum
157
Value_bin(PG_FUNCTION_ARGS)
408✔
158
{
159
  Datum value = PG_GETARG_DATUM(0);
408✔
160
  Datum size = PG_GETARG_DATUM(1);
408✔
161
  Datum origin = PG_GETARG_DATUM(2);
408✔
162
  meosType basetype = oid_type(get_fn_expr_argtype(fcinfo->flinfo, 1));
408✔
163
  meosType spantype = basetype_spantype(basetype);
408✔
164
  Datum value_bin = datum_bin(value, size, origin, basetype);
408✔
165
  Span *result = palloc(sizeof(Span));
404✔
166
  span_bin_state_set(value_bin, size, basetype, spantype, result);
404✔
167
  PG_RETURN_SPAN_P(result);
404✔
168
}
169

170
PGDLLEXPORT Datum Date_bin(PG_FUNCTION_ARGS);
171
PG_FUNCTION_INFO_V1(Date_bin);
2✔
172
/**
173
 * @ingroup mobilitydb_temporal_analytics_tile
174
 * @brief Return a span bin in a bin list for date spans
175
 * @sqlfn getTimeBin()
176
 */
177
Datum
178
Date_bin(PG_FUNCTION_ARGS)
2✔
179
{
180
  DateADT d = PG_GETARG_DATEADT(0);
2✔
181
  Interval *duration = PG_GETARG_INTERVAL_P(1);
2✔
182
  DateADT origin = PG_GETARG_DATEADT(2);
2✔
183
  DateADT date_bin = date_get_bin(d, duration, origin);
2✔
184
  Span *result = palloc(sizeof(Span));
2✔
185
  int32 ndays = (int32) (interval_units(duration) / USECS_PER_DAY);
2✔
186
  span_bin_state_set(DateADTGetDatum(date_bin), Int32GetDatum(ndays),
2✔
187
    T_DATE, T_DATESPAN, result);
188
  PG_RETURN_SPAN_P(result);
2✔
189
}
190

191
PGDLLEXPORT Datum Timestamptz_bin(PG_FUNCTION_ARGS);
192
PG_FUNCTION_INFO_V1(Timestamptz_bin);
3✔
193
/**
194
 * @ingroup mobilitydb_temporal_analytics_tile
195
 * @brief Return a span bin in a bin list for timestamptz spans
196
 * @sqlfn getTimeBin()
197
 */
198
Datum
199
Timestamptz_bin(PG_FUNCTION_ARGS)
203✔
200
{
201
  TimestampTz t = PG_GETARG_TIMESTAMPTZ(0);
203✔
202
  Interval *duration = PG_GETARG_INTERVAL_P(1);
203✔
203
  TimestampTz origin = PG_GETARG_TIMESTAMPTZ(2);
203✔
204
  TimestampTz time_bin = timestamptz_get_bin(t, duration, origin);
203✔
205
  int64 tunits = interval_units(duration);
200✔
206
  Span *result = palloc(sizeof(Span));
200✔
207
  span_bin_state_set(TimestampTzGetDatum(time_bin), Int64GetDatum(tunits),
200✔
208
    T_TIMESTAMPTZ, T_TSTZSPAN, result);
209
  PG_RETURN_SPAN_P(result);
200✔
210
}
211

212
/*****************************************************************************/
213

214
PGDLLEXPORT Datum Spanset_time_spans(PG_FUNCTION_ARGS);
215
PG_FUNCTION_INFO_V1(Spanset_time_spans);
4✔
216
/**
217
 * @ingroup mobilitydb_temporal_analytics_tile
218
 * @brief Return an array of spans obtained by splitting a spanset with respect
219
 * to time bins
220
 * @sqlfn timeSpans()
221
 */
222
Datum
223
Spanset_time_spans(PG_FUNCTION_ARGS)
4✔
224
{
225
  SpanSet *ss = PG_GETARG_SPANSET_P(0);
4✔
226
  Interval *duration = PG_GETARG_INTERVAL_P(1);
4✔
227
  Datum torigin = PG_GETARG_DATUM(2);
4✔
228
  /* Get the spans */
229
  int count;
230
  Span *spans = spanset_time_spans(ss, duration, torigin, &count);
4✔
231
  ArrayType *result = spanarr_to_array(spans, count);
4✔
232
  /* Clean up and return */
233
  pfree(spans);
4✔
234
  PG_FREE_IF_COPY(ss, 0);
4✔
235
  PG_RETURN_ARRAYTYPE_P(result);
4✔
236
}
237

238
PGDLLEXPORT Datum Spanset_value_spans(PG_FUNCTION_ARGS);
239
PG_FUNCTION_INFO_V1(Spanset_value_spans);
4✔
240
/**
241
 * @ingroup mobilitydb_temporal_analytics_tile
242
 * @brief Return an array of spans obtained by splitting a spanset with respect
243
 * to value bins
244
 * @sqlfn valueSpans()
245
 */
246
Datum
247
Spanset_value_spans(PG_FUNCTION_ARGS)
4✔
248
{
249
  SpanSet *ss = PG_GETARG_SPANSET_P(0);
4✔
250
  Datum vsize = PG_GETARG_DATUM(1);
4✔
251
  Datum vorigin = PG_GETARG_DATUM(2);
4✔
252
  /* Get the spans */
253
  int count;
254
  Span *spans = spanset_value_spans(ss, vsize, vorigin, &count);
4✔
255
  ArrayType *result = spanarr_to_array(spans, count);
4✔
256
  /* Clean up and return */
257
  pfree(spans);
4✔
258
  PG_FREE_IF_COPY(ss, 0);
4✔
259
  PG_RETURN_ARRAYTYPE_P(result);
4✔
260
}
261

262
/*****************************************************************************/
263

264
PGDLLEXPORT Datum Temporal_time_spans(PG_FUNCTION_ARGS);
265
PG_FUNCTION_INFO_V1(Temporal_time_spans);
6✔
266
/**
267
 * @ingroup mobilitydb_temporal_analytics_tile
268
 * @brief Return the value spans of a temporal number split with respect to
269
 * value bins
270
 * @sqlfn timeSpans()
271
 */
272
Datum
273
Temporal_time_spans(PG_FUNCTION_ARGS)
4✔
274
{
275
  Temporal *temp = PG_GETARG_TEMPORAL_P(0);
4✔
276
  Interval *duration = PG_GETARG_INTERVAL_P(1);
4✔
277
  TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(2);
4✔
278
  /* Get the spans */
279
  int count;
280
  Span *spans = temporal_time_spans(temp, duration, torigin, &count);
4✔
281
  ArrayType *result = spanarr_to_array(spans, count);
4✔
282
  /* Clean up and return */
283
  pfree(spans);
4✔
284
  PG_FREE_IF_COPY(temp, 0);
4✔
285
  PG_RETURN_ARRAYTYPE_P(result);
4✔
286
}
287

288
PGDLLEXPORT Datum Tnumber_value_spans(PG_FUNCTION_ARGS);
289
PG_FUNCTION_INFO_V1(Tnumber_value_spans);
4✔
290
/**
291
 * @ingroup mobilitydb_temporal_analytics_tile
292
 * @brief Return the value spans of a temporal number split with respect to
293
 * value bins
294
 * @sqlfn valueSpans()
295
 */
296
Datum
297
Tnumber_value_spans(PG_FUNCTION_ARGS)
4✔
298
{
299
  Temporal *temp = PG_GETARG_TEMPORAL_P(0);
4✔
300
  Datum vsize = PG_GETARG_DATUM(1);
4✔
301
  Datum vorigin = PG_GETARG_DATUM(2);
4✔
302
  /* Get the spans */
303
  int count;
304
  Span *spans = tnumber_value_spans(temp, vsize, vorigin, &count);
4✔
305
  ArrayType *result = spanarr_to_array(spans, count);
4✔
306
  /* Clean up and return */
307
  pfree(spans);
4✔
308
  PG_FREE_IF_COPY(temp, 0);
4✔
309
  PG_RETURN_ARRAYTYPE_P(result);
4✔
310
}
311

312
/*****************************************************************************
313
 * TBox functions
314
 *****************************************************************************/
315

316
/**
317
 * @brief Return the tiles of a temporal box
318
 */
319
Datum
320
Tbox_value_time_tiles_ext(FunctionCallInfo fcinfo, bool valuetiles,
1,293✔
321
  bool timetiles)
322
{
323
  assert(valuetiles || timetiles);
324

325
  FuncCallContext *funcctx;
326
  /* If the function is being called for the first time */
327
  if (SRF_IS_FIRSTCALL())
1,293✔
328
  {
329
    /* Initialize to 0 missing parameters */
330
    double xsize = 0, xorigin = 0;
331
    Interval *duration = NULL;
332
    TimestampTz torigin = 0;
333
    /* Get input parameters and ensure their validity */
334
    TBox *bounds = PG_GETARG_TBOX_P(0);
304✔
335
    int i = 1;
336
    if (valuetiles)
304✔
337
    {
338
      ensure_has_X(T_TBOX, bounds->flags);
302✔
339
      xsize = PG_GETARG_FLOAT8(i++);
302✔
340
      ensure_positive_datum(Float8GetDatum(xsize), T_FLOAT8);
302✔
341
    }
342
    if (timetiles)
304✔
343
    {
344
      ensure_has_T(T_TBOX, bounds->flags);
302✔
345
      duration = PG_GETARG_INTERVAL_P(i++);
302✔
346
      ensure_valid_duration(duration);
302✔
347
    }
348
    if (valuetiles)
304✔
349
      xorigin = PG_GETARG_FLOAT8(i++);
302✔
350
    if (timetiles)
304✔
351
      torigin = PG_GETARG_TIMESTAMPTZ(i++);
302✔
352

353
    /* Initialize the FuncCallContext */
354
    funcctx = SRF_FIRSTCALL_INIT();
304✔
355
    /* Switch to memory context appropriate for multiple function calls */
356
    MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
304✔
357
    /* Create function state */
358
    funcctx->user_fctx = tbox_tile_state_make(NULL, bounds,
304✔
359
      Float8GetDatum(xsize), duration, Float8GetDatum(xorigin), torigin);
360
    /* Build a tuple description for the function output */
361
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
304✔
362
    BlessTupleDesc(funcctx->tuple_desc);
304✔
363
    MemoryContextSwitchTo(oldcontext);
364
  }
365

366
  /* Stuff done on every call of the function */
367
  funcctx = SRF_PERCALL_SETUP();
1,293✔
368
  /* Get state */
369
  TboxGridState *state = funcctx->user_fctx;
1,293✔
370
  /* Stop when we've used up all tiles */
371
  if (state->done)
1,293✔
372
  {
373
    /* Switch to memory context appropriate for multiple function calls */
374
    MemoryContext oldcontext =
375
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
297✔
376
    pfree(state);
297✔
377
    MemoryContextSwitchTo(oldcontext);
378
    SRF_RETURN_DONE(funcctx);
297✔
379
  }
380

381
  /* Allocate box */
382
  TBox *box = palloc(sizeof(STBox));
996✔
383
  /* Store tile value and time */
384
  Datum values[2]; /* used to construct the composite return value */
385
  values[0] = Int32GetDatum(state->i);
996✔
386
  /* Generate box */
387
  tbox_tile_state_set(state->value, state->t, state->vsize, state->tunits,
996✔
388
    state->box.span.basetype, state->box.span.spantype, box);
996✔
389
  values[1] = PointerGetDatum(box);
996✔
390
  /* Advance state */
391
  tbox_tile_state_next(state);
996✔
392
  /* Form tuple and return */
393
  bool isnull[2] = {0,0}; /* needed to say no value is null */
996✔
394
  HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, values, isnull);
996✔
395
  Datum result = HeapTupleGetDatum(tuple);
396
  SRF_RETURN_NEXT(funcctx, result);
996✔
397
}
398

399
PGDLLEXPORT Datum Tbox_value_tiles(PG_FUNCTION_ARGS);
400
PG_FUNCTION_INFO_V1(Tbox_value_tiles);
2✔
401
/**
402
 * @ingroup mobilitydb_temporal_analytics_tile
403
 * @brief Return the tile list of a temporal box
404
 * @sqlfn valueTimeTiles()
405
 */
406
inline Datum
407
Tbox_value_tiles(PG_FUNCTION_ARGS)
6✔
408
{
409
  return Tbox_value_time_tiles_ext(fcinfo, true, false);
6✔
410
}
411

412
PGDLLEXPORT Datum Tbox_time_tiles(PG_FUNCTION_ARGS);
413
PG_FUNCTION_INFO_V1(Tbox_time_tiles);
2✔
414
/**
415
 * @ingroup mobilitydb_temporal_analytics_tile
416
 * @brief Return the tile list of a temporal box
417
 * @sqlfn valueTimeTiles()
418
 */
419
inline Datum
420
Tbox_time_tiles(PG_FUNCTION_ARGS)
6✔
421
{
422
  return Tbox_value_time_tiles_ext(fcinfo, false, true);
6✔
423
}
424

425
PGDLLEXPORT Datum Tbox_value_time_tiles(PG_FUNCTION_ARGS);
426
PG_FUNCTION_INFO_V1(Tbox_value_time_tiles);
3✔
427
/**
428
 * @ingroup mobilitydb_temporal_analytics_tile
429
 * @brief Return the tile list of a temporal box
430
 * @sqlfn valueTimeTiles()
431
 */
432
inline Datum
433
Tbox_value_time_tiles(PG_FUNCTION_ARGS)
1,281✔
434
{
435
  return Tbox_value_time_tiles_ext(fcinfo, true, true);
1,281✔
436
}
437

438
/*****************************************************************************/
439

440
/**
441
 * @brief Return a tile in a multidimensional grid for temporal numbers
442
 * (external function)
443
 */
444
Datum
445
Tbox_get_value_time_tile_ext(FunctionCallInfo fcinfo, bool valuetile,
226✔
446
  bool timetile)
447
{
448
  assert(valuetile || timetile);
449

450
  /* Initialize to 0 missing dimensions */
451
  Datum value = (Datum) 0, vsize = (Datum) 0, vorigin = (Datum) 0;
452
  Interval *duration = NULL;
453
  TimestampTz t = 0, torigin = 0;
454
  /* Get input parameters */
455
  int i = 0;
456
  if (valuetile)
226✔
457
    value = PG_GETARG_DATUM(i++);
204✔
458
  if (timetile)
226✔
459
    t = PG_GETARG_TIMESTAMPTZ(i++);
224✔
460
  if (valuetile)
226✔
461
    vsize = PG_GETARG_DATUM(i++);
204✔
462
  if (timetile)
226✔
463
    duration = PG_GETARG_INTERVAL_P(i++);
224✔
464
  if (valuetile)
226✔
465
    vorigin = PG_GETARG_DATUM(i++);
204✔
466
  if (timetile)
226✔
467
    torigin = PG_GETARG_TIMESTAMPTZ(i++);
224✔
468
  meosType basetype = oid_type(get_fn_expr_argtype(fcinfo->flinfo, 0));
226✔
469
  meosType spantype = basetype_spantype(basetype);
226✔
470
  PG_RETURN_TBOX_P(tbox_get_value_time_tile(value, t, vsize, duration, vorigin,
226✔
471
    torigin, basetype, spantype));
472
}
473

474
PGDLLEXPORT Datum Tbox_get_value_tile(PG_FUNCTION_ARGS);
475
PG_FUNCTION_INFO_V1(Tbox_get_value_tile);
2✔
476
/**
477
 * @ingroup mobilitydb_temporal_analytics_tile
478
 * @brief Return a tile in a multidimensional grid for temporal numbers
479
 * @sqlfn tile()
480
 */
481
inline Datum
482
Tbox_get_value_tile(PG_FUNCTION_ARGS)
2✔
483
{
484
  return Tbox_get_value_time_tile_ext(fcinfo, true, false);
2✔
485
}
486

487
PGDLLEXPORT Datum Tbox_get_time_tile(PG_FUNCTION_ARGS);
488
PG_FUNCTION_INFO_V1(Tbox_get_time_tile);
3✔
489
/**
490
 * @ingroup mobilitydb_temporal_analytics_tile
491
 * @brief Return a tile in a multidimensional grid for temporal numbers
492
 * @sqlfn tile()
493
 */
494
inline Datum
495
Tbox_get_time_tile(PG_FUNCTION_ARGS)
22✔
496
{
497
  return Tbox_get_value_time_tile_ext(fcinfo, false, true);
22✔
498
}
499

500
PGDLLEXPORT Datum Tbox_get_value_time_tile(PG_FUNCTION_ARGS);
501
PG_FUNCTION_INFO_V1(Tbox_get_value_time_tile);
3✔
502
/**
503
 * @ingroup mobilitydb_temporal_analytics_tile
504
 * @brief Return a tile in a multidimensional grid for temporal numbers
505
 * @sqlfn tile()
506
 */
507
inline Datum
508
Tbox_get_value_time_tile(PG_FUNCTION_ARGS)
202✔
509
{
510
  return Tbox_get_value_time_tile_ext(fcinfo, true, true);
202✔
511
}
512

513
/*****************************************************************************
514
 * Boxes functions
515
 *****************************************************************************/
516

517
/**
518
 * @brief Return the temporal boxes of a temporal number split with respect to
519
 * a value and/or time grid (external function)
520
 */
521
Datum
522
Tnumber_value_time_boxes_ext(FunctionCallInfo fcinfo, bool valueboxes,
610✔
523
  bool timeboxes)
524
{
525
  assert(valueboxes || timeboxes);
526

527
  /* Initialize to 0 missing dimensions */
528
  Datum vsize = (Datum) 0, vorigin = (Datum) 0;
529
  Interval *duration = NULL;
530
  TimestampTz torigin = 0;
531
  /* Get input parameters */
532
  Temporal *temp = PG_GETARG_TEMPORAL_P(0);
610✔
533
  int i = 1;
534
  if (valueboxes)
610✔
535
    vsize = PG_GETARG_DATUM(i++);
600✔
536
  if (timeboxes)
610✔
537
    duration = PG_GETARG_INTERVAL_P(i++);
596✔
538
  if (valueboxes)
610✔
539
    vorigin = PG_GETARG_DATUM(i++);
600✔
540
  if (timeboxes)
610✔
541
    torigin = PG_GETARG_TIMESTAMPTZ(i++);
596✔
542
  /* Get the tiles */
543
  int count;
544
  TBox *boxes = tnumber_value_time_boxes(temp, vsize, duration, vorigin,
610✔
545
    torigin, &count);
546
  ArrayType *result = tboxarr_to_array(boxes, count);
600✔
547
  /* Clean up and return */
548
  pfree(boxes);
600✔
549
  PG_FREE_IF_COPY(temp, 0);
600✔
550
  PG_RETURN_ARRAYTYPE_P(result);
600✔
551
}
552

553
PGDLLEXPORT Datum Tnumber_value_boxes(PG_FUNCTION_ARGS);
554
PG_FUNCTION_INFO_V1(Tnumber_value_boxes);
4✔
555
/**
556
 * @ingroup mobilitydb_temporal_analytics_tile
557
 * @brief Return the temporal boxes of a temporal number split with respect to
558
 * value bins
559
 * @sqlfn valueBoxes()
560
 */
561
inline Datum
562
Tnumber_value_boxes(PG_FUNCTION_ARGS)
14✔
563
{
564
  return Tnumber_value_time_boxes_ext(fcinfo, true, false);
14✔
565
}
566

567
PGDLLEXPORT Datum Tnumber_time_boxes(PG_FUNCTION_ARGS);
568
PG_FUNCTION_INFO_V1(Tnumber_time_boxes);
4✔
569
/**
570
 * @ingroup mobilitydb_temporal_analytics_tile
571
 * @brief Return the temporal boxes of a temporal number split with respect to
572
 * time bins
573
 * @sqlfn timeBoxes()
574
 */
575
inline Datum
576
Tnumber_time_boxes(PG_FUNCTION_ARGS)
10✔
577
{
578
  return Tnumber_value_time_boxes_ext(fcinfo, false, true);
10✔
579
}
580

581
PGDLLEXPORT Datum Tnumber_value_time_boxes(PG_FUNCTION_ARGS);
582
PG_FUNCTION_INFO_V1(Tnumber_value_time_boxes);
6✔
583
/**
584
 * @ingroup mobilitydb_temporal_analytics_tile
585
 * @brief Return the temporal boxes of a temporal number split with respect to
586
 * a value and time grid
587
 * @sqlfn valueTimeBoxes()
588
 */
589
inline Datum
590
Tnumber_value_time_boxes(PG_FUNCTION_ARGS)
586✔
591
{
592
  return Tnumber_value_time_boxes_ext(fcinfo, true, true);
586✔
593
}
594

595
/*****************************************************************************
596
 * Split functions
597
 *****************************************************************************/
598

599
PGDLLEXPORT Datum Temporal_time_split(PG_FUNCTION_ARGS);
600
PG_FUNCTION_INFO_V1(Temporal_time_split);
19✔
601
/**
602
 * @ingroup mobilitydb_temporal_analytics_tile
603
 * @brief Return the fragments of a temporal value split according to
604
 * time bins
605
 * @sqlfn timeSplit()
606
 */
607
Datum
608
Temporal_time_split(PG_FUNCTION_ARGS)
2,920✔
609
{
610
  FuncCallContext *funcctx;
611

612
  /* If the function is being called for the first time */
613
  if (SRF_IS_FIRSTCALL())
2,920✔
614
  {
615
    /* Initialize the FuncCallContext */
616
    funcctx = SRF_FIRSTCALL_INIT();
883✔
617
    /* Switch to memory context appropriate for multiple function calls */
618
    MemoryContext oldcontext =
619
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
883✔
620

621
    /* Get input parameters */
622
    Temporal *temp = PG_GETARG_TEMPORAL_P(0);
883✔
623
    Interval *duration = PG_GETARG_INTERVAL_P(1);
883✔
624
    TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(2);
883✔
625

626
    /* Initialize state and verify parameter validity */
627
    int nbins;
628
    SpanBinState *state = temporal_time_bin_init(temp, duration, torigin,
883✔
629
      &nbins);
630

631
    /* Create function state */
632
    funcctx->user_fctx = state;
882✔
633

634
    /* Build a tuple description for a multidimensional grid tuple */
635
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
882✔
636
    BlessTupleDesc(funcctx->tuple_desc);
882✔
637
    MemoryContextSwitchTo(oldcontext);
638
  }
639

640
  /* Stuff done on every call of the function */
641
  funcctx = SRF_PERCALL_SETUP();
2,919✔
642
  /* State that no value is null */
643
  bool isnull[2] = {0,0};
2,919✔
644
  /* Get state */
645
  SpanBinState *state = funcctx->user_fctx;
2,919✔
646
  /* We need to loop since atTbox may be NULL */
647
  while (true)
648
  {
649
    /* Stop when we have used up all the grid tiles */
650
    if (state->done)
3,054✔
651
    {
652
      /* Switch to memory context appropriate for multiple function calls */
653
      MemoryContext oldcontext =
654
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
882✔
655
      pfree(state);
882✔
656
      MemoryContextSwitchTo(oldcontext);
657
      SRF_RETURN_DONE(funcctx);
882✔
658
    }
659

660
    /* Get current tile (if any) and advance state */
661
    Span span;
662
    if (! span_bin_state_get(state, &span))
2,172✔
663
    {
664
      /* Switch to memory context appropriate for multiple function calls */
665
      MemoryContext oldcontext =
666
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
×
UNCOV
667
      pfree(state);
×
668
      MemoryContextSwitchTo(oldcontext);
UNCOV
669
      SRF_RETURN_DONE(funcctx);
×
670
    }
671
    span_bin_state_next(state);
2,172✔
672

673
    /* Restrict the temporal point to the span */
674
    Temporal *atspan = temporal_restrict_tstzspan(state->to_split, &span,
2,172✔
675
      REST_AT);
676
    if (atspan == NULL)
2,172✔
677
      continue;
135✔
678

679
    /* Form tuple and return */
680
    Datum tuple_arr[2]; /* used to construct the composite return value */
681
    tuple_arr[0] = span.lower;
2,037✔
682
    tuple_arr[1] = PointerGetDatum(atspan);
2,037✔
683
    HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
2,037✔
684
    Datum result = HeapTupleGetDatum(tuple);
685
    SRF_RETURN_NEXT(funcctx, result);
2,037✔
686
  }
687
}
688

689
/*****************************************************************************/
690

691
/**
692
 * @brief Return the fragments of a temporal number split according to value
693
 * and time bins
694
 */
695
Datum
696
Tnumber_value_time_split_ext(FunctionCallInfo fcinfo, bool valuesplit,
15,583✔
697
  bool timesplit)
698
{
699
  FuncCallContext *funcctx;
700

701
  /* If the function is being called for the first time */
702
  if (SRF_IS_FIRSTCALL())
15,583✔
703
  {
704
    /* Initialize the FuncCallContext */
705
    funcctx = SRF_FIRSTCALL_INIT();
980✔
706
    /* Switch to memory context appropriate for multiple function calls */
707
    MemoryContext oldcontext =
708
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
980✔
709

710
    /* Initialize to 0 missing parameters */
711
    Datum vsize = (Datum) 0, vorigin = (Datum) 0;
712
    Interval *duration = NULL;
713
    TimestampTz torigin = 0;
714

715
    /* Get input parameters */
716
    Temporal *temp = PG_GETARG_TEMPORAL_P(0);
980✔
717
    int i = 1;
718
    if (valuesplit)
980✔
719
      vsize = PG_GETARG_DATUM(i++);
980✔
720
    if (timesplit)
980✔
721
      duration = PG_GETARG_INTERVAL_P(i++);
490✔
722
    if (valuesplit)
980✔
723
      vorigin = PG_GETARG_DATUM(i++);
980✔
724
    if (timesplit)
980✔
725
      torigin = PG_GETARG_TIMESTAMPTZ(i++);
490✔
726

727
    /* Initialize state and verify parameter validity */
728
    int ntiles;
729
    TboxGridState *state = tnumber_value_time_tile_init(temp, vsize, duration,
980✔
730
      vorigin, torigin, &ntiles);
731

732
    /* Create function state */
733
    funcctx->user_fctx = state;
980✔
734

735
    /* Build a tuple description for a multidimensional grid tuple */
736
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
980✔
737
    BlessTupleDesc(funcctx->tuple_desc);
980✔
738
    MemoryContextSwitchTo(oldcontext);
739
  }
740

741
  /* Stuff done on every call of the function */
742
  funcctx = SRF_PERCALL_SETUP();
15,583✔
743
  /* State that no value is null */
744
  bool isnull[3] = {0,0,0};
15,583✔
745
  /* Get state */
746
  TboxGridState *state = funcctx->user_fctx;
15,583✔
747
  /* We need to loop since atTbox may be NULL */
748
  while (true)
749
  {
750
    /* Stop when we have used up all the grid tiles */
751
    if (state->done)
39,042✔
752
    {
753
      /* Switch to memory context appropriate for multiple function calls */
754
      MemoryContext oldcontext =
755
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
980✔
756
      pfree(state);
980✔
757
      MemoryContextSwitchTo(oldcontext);
758
      SRF_RETURN_DONE(funcctx);
980✔
759
    }
760

761
    /* Get current tile (if any) and advance state */
762
    TBox box;
763
    if (! tbox_tile_state_get(state, &box))
38,062✔
764
    {
765
      /* Switch to memory context appropriate for multiple function calls */
766
      MemoryContext oldcontext =
767
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
×
UNCOV
768
      pfree(state);
×
769
      MemoryContextSwitchTo(oldcontext);
UNCOV
770
      SRF_RETURN_DONE(funcctx);
×
771
    }
772
    tbox_tile_state_next(state);
38,062✔
773

774
    /* Restrict the temporal point to the box */
775
    Temporal *attbox = tnumber_at_tbox(state->temp, &box);
38,062✔
776
    if (attbox == NULL)
38,062✔
777
      continue;
23,459✔
778

779
    /* Form tuple and return */
780
    Datum tuple_arr[3]; /* used to construct the composite return value */
781
    int i = 0;
782
    if (valuesplit)
14,603✔
783
      tuple_arr[i++] = box.span.lower;
14,603✔
784
    if (timesplit)
14,603✔
785
      tuple_arr[i++] = box.period.lower;
9,321✔
786
    tuple_arr[i++] = PointerGetDatum(attbox);
14,603✔
787
    HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
14,603✔
788
    Datum result = HeapTupleGetDatum(tuple);
789
    SRF_RETURN_NEXT(funcctx, result);
14,603✔
790
  }
791
}
792

793
PGDLLEXPORT Datum Tnumber_value_split(PG_FUNCTION_ARGS);
794
PG_FUNCTION_INFO_V1(Tnumber_value_split);
8✔
795
/**
796
 * @ingroup mobilitydb_temporal_analytics_tile
797
 * @brief Return the fragments of a temporal number split according to value
798
 * bins
799
 * @sqlfn valueSplit()
800
 */
801
inline Datum
802
Tnumber_value_split(PG_FUNCTION_ARGS)
5,772✔
803
{
804
  return Tnumber_value_time_split_ext(fcinfo, true, false);
5,772✔
805
}
806

807
PGDLLEXPORT Datum Tnumber_time_split(PG_FUNCTION_ARGS);
UNCOV
808
PG_FUNCTION_INFO_V1(Tnumber_time_split);
×
809
/**
810
 * @ingroup mobilitydb_temporal_analytics_tile
811
 * @brief Return the fragments of a temporal number split according to value
812
 * bins
813
 * @sqlfn valueSplit()
814
 */
815
inline Datum
UNCOV
816
Tnumber_time_split(PG_FUNCTION_ARGS)
×
817
{
UNCOV
818
  return Tnumber_value_time_split_ext(fcinfo, false, true);
×
819
}
820

821
PGDLLEXPORT Datum Tnumber_value_time_split(PG_FUNCTION_ARGS);
822
PG_FUNCTION_INFO_V1(Tnumber_value_time_split);
8✔
823
/**
824
 * @ingroup mobilitydb_temporal_analytics_tile
825
 * @brief Return the fragments of a temporal number split according to value
826
 * and time bins
827
 * @sqlfn valueTimeSplit()
828
 */
829
inline Datum
830
Tnumber_value_time_split(PG_FUNCTION_ARGS)
9,811✔
831
{
832
  return Tnumber_value_time_split_ext(fcinfo, true, true);
9,811✔
833
}
834

835
/*****************************************************************************/
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