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

estebanzimanyi / MobilityDB / 10425478761

16 Aug 2024 07:54PM UTC coverage: 95.193% (-0.008%) from 95.201%
10425478761

push

github

estebanzimanyi
Uniformize tiling algorithms for 1D -> 4D

240 of 254 new or added lines in 20 files covered. (94.49%)

115 existing lines in 10 files now uncovered.

32355 of 33989 relevant lines covered (95.19%)

752444.01 hits per line

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

95.81
/mobilitydb/src/general/temporal_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 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
/* MobilityDB */
53
#include "pg_general/meos_catalog.h"
54
#include "pg_general/type_util.h"
55

56
/*****************************************************************************/
57

58
/**
59
 * @brief Return the bins of a span
60
 */
61
Datum
62
Span_spans_ext(FunctionCallInfo fcinfo, bool valuelist)
2,193✔
63
{
64
  FuncCallContext *funcctx;
65
  bool isnull[2] = {0,0}; /* needed to say no value is null */
2,193✔
66

67
  /* If the function is being called for the first time */
68
  if (SRF_IS_FIRSTCALL())
2,193✔
69
  {
70
    /* Get input parameters */
71
    Span *bounds = PG_GETARG_SPAN_P(0);
600✔
72
    Datum size, origin;
73
    if (valuelist)
600✔
74
    {
75
      size = PG_GETARG_DATUM(1);
400✔
76
      origin = PG_GETARG_DATUM(2);
400✔
77
      meosType basetype = oid_type(get_fn_expr_argtype(fcinfo->flinfo, 1));
400✔
78
      ensure_positive_datum(size, basetype);
400✔
79
    }
80
    else
81
    {
82
      Interval *duration = PG_GETARG_INTERVAL_P(1);
200✔
83
      TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(2);
200✔
84
      origin = TimestampTzGetDatum(torigin);
85
      ensure_valid_duration(duration);
200✔
86
      size = Int64GetDatum(interval_units(duration));
200✔
87
    }
88

89
    /* Initialize the FuncCallContext */
90
    funcctx = SRF_FIRSTCALL_INIT();
600✔
91
    /* Switch to memory context appropriate for multiple function calls */
92
    MemoryContext oldcontext =
93
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
600✔
94
    /* Create function state */
95
    funcctx->user_fctx = span_bin_state_make(NULL, bounds, size, origin);
600✔
96
    /* Build a tuple description for the function output */
97
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
600✔
98
    BlessTupleDesc(funcctx->tuple_desc);
600✔
99
    MemoryContextSwitchTo(oldcontext);
100
  }
101

102
  /* Stuff done on every call of the function */
103
  funcctx = SRF_PERCALL_SETUP();
2,193✔
104
  /* Get state */
105
  SpanBinState *state = funcctx->user_fctx;
2,193✔
106
  /* Stop when we've used up all bins */
107
  if (state->done)
2,193✔
108
  {
109
    /* Switch to memory context appropriate for multiple function calls */
110
    MemoryContext oldcontext =
111
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
594✔
112
    pfree(state);
594✔
113
    MemoryContextSwitchTo(oldcontext);
114
    SRF_RETURN_DONE(funcctx);
594✔
115
  }
116

117
  /* Allocate span */
118
  Span *span = palloc(sizeof(Span));
1,599✔
119
  /* Used to construct the composite return value */
120
  Datum tuple_arr[2];
121
  /* Store index */
122
  tuple_arr[0] = Int32GetDatum(state->i);
1,599✔
123
  /* Generate bin */
124
  span_bin_state_set(state->value, state->size, state->span.basetype,
1,599✔
125
    state->span.spantype, span);
1,599✔
126
  tuple_arr[1] = PointerGetDatum(span);
1,599✔
127
  /* Advance state */
128
  span_bin_state_next(state);
1,599✔
129
  /* Form tuple and return */
130
  HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
1,599✔
131
  Datum result = HeapTupleGetDatum(tuple);
1,599✔
132
  SRF_RETURN_NEXT(funcctx, result);
1,599✔
133
}
134

135
/*****************************************************************************/
136

137
PGDLLEXPORT Datum Numberspan_spans(PG_FUNCTION_ARGS);
138
PG_FUNCTION_INFO_V1(Numberspan_spans);
6✔
139
/**
140
 * @ingroup mobilitydb_temporal_analytics_tile
141
 * @brief Return the bins of a number span
142
 * @sqlfn valueSpans()
143
 */
144
Datum
145
Numberspan_spans(PG_FUNCTION_ARGS)
1,791✔
146
{
147
  return Span_spans_ext(fcinfo, true);
1,791✔
148
}
149

150
PGDLLEXPORT Datum Tstzspan_spans(PG_FUNCTION_ARGS);
151
PG_FUNCTION_INFO_V1(Tstzspan_spans);
3✔
152
/**
153
 * @ingroup mobilitydb_temporal_analytics_tile
154
 * @brief Return the bins of a timestamptz span
155
 * @sqlfn timeSpans()
156
 */
157
Datum
158
Tstzspan_spans(PG_FUNCTION_ARGS)
402✔
159
{
160
  return Span_spans_ext(fcinfo, false);
402✔
161
}
162

163
/*****************************************************************************/
164

165
PGDLLEXPORT Datum Value_span(PG_FUNCTION_ARGS);
166
PG_FUNCTION_INFO_V1(Value_span);
6✔
167
/**
168
 * @ingroup mobilitydb_temporal_analytics_tile
169
 * @brief Return a span bin in a bin list for number spans
170
 * @sqlfn getValueSpan()
171
 */
172
Datum
173
Value_span(PG_FUNCTION_ARGS)
406✔
174
{
175
  Datum value = PG_GETARG_DATUM(0);
406✔
176
  Datum size = PG_GETARG_DATUM(1);
406✔
177
  Datum origin = PG_GETARG_DATUM(2);
406✔
178
  meosType basetype = oid_type(get_fn_expr_argtype(fcinfo->flinfo, 1));
406✔
179
  meosType spantype = basetype_spantype(basetype);
406✔
180
  Datum value_bin = datum_bin(value, size, origin, basetype);
406✔
181
  Span *result = palloc(sizeof(Span));
402✔
182
  span_bin_state_set(value_bin, size, basetype, spantype, result);
402✔
183
  PG_RETURN_SPAN_P(result);
402✔
184
}
185

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

207
/*****************************************************************************/
208

209
PGDLLEXPORT Datum Tbox_value_time_tiles(PG_FUNCTION_ARGS);
210
PG_FUNCTION_INFO_V1(Tbox_value_time_tiles);
3✔
211
/**
212
 * @ingroup mobilitydb_temporal_analytics_tile
213
 * @brief Return the tile list of a temporal box
214
 * @sqlfn valueTimeTiles()
215
 */
216
Datum
217
Tbox_value_time_tiles(PG_FUNCTION_ARGS)
1,281✔
218
{
219
  FuncCallContext *funcctx;
220
  bool isnull[2] = {0,0}; /* needed to say no value is null */
1,281✔
221

222
  /* If the function is being called for the first time */
223
  if (SRF_IS_FIRSTCALL())
1,281✔
224
  {
225
    /* Get input parameters */
226
    TBox *bounds = PG_GETARG_TBOX_P(0);
300✔
227
    double xsize = PG_GETARG_FLOAT8(1);
300✔
228
    Interval *duration = PG_GETARG_INTERVAL_P(2);
300✔
229
    double xorigin = PG_GETARG_FLOAT8(3);
300✔
230
    TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(4);
300✔
231

232
    /* Ensure parameter validity */
233
    ensure_has_X_tbox(bounds);
300✔
234
    ensure_has_T_tbox(bounds);
300✔
235
    ensure_positive_datum(Float8GetDatum(xsize), T_FLOAT8);
300✔
236
    ensure_valid_duration(duration);
300✔
237

238
    /* Initialize the FuncCallContext */
239
    funcctx = SRF_FIRSTCALL_INIT();
300✔
240
    /* Switch to memory context appropriate for multiple function calls */
241
    MemoryContext oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
300✔
242
    /* Create function state */
243
    funcctx->user_fctx = tbox_tile_state_make(NULL, bounds, 
300✔
244
      Float8GetDatum(xsize), duration, Float8GetDatum(xorigin), torigin);
245
    /* Build a tuple description for the function output */
246
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
300✔
247
    BlessTupleDesc(funcctx->tuple_desc);
300✔
248
    MemoryContextSwitchTo(oldcontext);
249
  }
250

251
  /* Stuff done on every call of the function */
252
  funcctx = SRF_PERCALL_SETUP();
1,281✔
253
  /* Get state */
254
  TboxGridState *state = funcctx->user_fctx;
1,281✔
255
  /* Stop when we've used up all tiles */
256
  if (state->done)
1,281✔
257
  {
258
    /* Switch to memory context appropriate for multiple function calls */
259
    MemoryContext oldcontext =
260
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
297✔
261
    pfree(state);
297✔
262
    MemoryContextSwitchTo(oldcontext);
263
    SRF_RETURN_DONE(funcctx);
297✔
264
  }
265

266
  /* Allocate box */
267
  TBox *box = palloc(sizeof(STBox));
984✔
268
  /* Store tile value and time */
269
  Datum tuple_arr[2]; /* used to construct the composite return value */
270
  tuple_arr[0] = Int32GetDatum(state->i);
984✔
271
  /* Generate box */
272
  tbox_tile_state_set(state->value, state->t, state->vsize, state->tunits,
984✔
273
    state->box.span.basetype, state->box.span.spantype, box);
984✔
274
  tuple_arr[1] = PointerGetDatum(box);
984✔
275
  /* Advance state */
276
  tbox_tile_state_next(state);
984✔
277
  /* Form tuple and return */
278
  HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
984✔
279
  Datum result = HeapTupleGetDatum(tuple);
984✔
280
  SRF_RETURN_NEXT(funcctx, result);
984✔
281
}
282

283
/*****************************************************************************/
284

285
PGDLLEXPORT Datum Tbox_value_time_tile(PG_FUNCTION_ARGS);
286
PG_FUNCTION_INFO_V1(Tbox_value_time_tile);
3✔
287
/**
288
 * @ingroup mobilitydb_temporal_analytics_tile
289
 * @brief Return a tile in a multidimensional grid for temporal numbers
290
 * @sqlfn tile()
291
 */
292
Datum
293
Tbox_value_time_tile(PG_FUNCTION_ARGS)
202✔
294
{
295
  Datum value = PG_GETARG_DATUM(0);
202✔
296
  TimestampTz t = PG_GETARG_TIMESTAMPTZ(1);
202✔
297
  Datum vsize = PG_GETARG_DATUM(2);
202✔
298
  Interval *duration = PG_GETARG_INTERVAL_P(3);
202✔
299
  Datum vorigin = PG_GETARG_DATUM(4);
202✔
300
  TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(5);
202✔
301
  meosType basetype = oid_type(get_fn_expr_argtype(fcinfo->flinfo, 0));
202✔
302
  meosType spantype = basetype_spantype(basetype);
202✔
303
  PG_RETURN_TBOX_P(tbox_value_time_tile(value, t, vsize, duration, vorigin,
202✔
304
    torigin, basetype, spantype));
305
}
306

307
/*****************************************************************************
308
 * Boxes functions
309
 *****************************************************************************/
310

311
PGDLLEXPORT Datum Tnumber_value_time_boxes(PG_FUNCTION_ARGS);
312
PG_FUNCTION_INFO_V1(Tnumber_value_time_boxes);
6✔
313
/**
314
 * @ingroup mobilitydb_temporal_analytics_tile
315
 * @brief Return the temporal boxes of a temporal number split with respect to
316
 * a value and time grid
317
 * @sqlfn valueTimeBoxes()
318
 */
319
Datum
320
Tnumber_value_time_boxes(PG_FUNCTION_ARGS)
586✔
321
{
322
  /* Get input parameters */
323
  Temporal *temp = PG_GETARG_TEMPORAL_P(0);
586✔
324
  Datum vsize = PG_GETARG_DATUM(1);
586✔
325
  Interval *duration = PG_GETARG_INTERVAL_P(2);
586✔
326
  Datum vorigin = PG_GETARG_DATUM(3);
586✔
327
  TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(4);
586✔
328

329
  /* Get the tiles */
330
  int count;
331
  TBox *boxes = tnumber_value_time_boxes(temp, vsize, duration, vorigin,
586✔
332
    torigin, &count);
333
  ArrayType *result = tboxarr_to_array(boxes, count);
586✔
334
  pfree(boxes);
586✔
335
  PG_FREE_IF_COPY(temp, 0);
586✔
336
  PG_RETURN_ARRAYTYPE_P(result);
586✔
337
}
338

339
/*****************************************************************************/
340

341
PGDLLEXPORT Datum Temporal_time_split(PG_FUNCTION_ARGS);
342
PG_FUNCTION_INFO_V1(Temporal_time_split);
17✔
343
/**
344
 * @ingroup mobilitydb_temporal_analytics_tile
345
 * @brief Return the fragments of a temporal value split according to
346
 * time bins
347
 * @sqlfn timeSplit()
348
 */
349
Datum
350
Temporal_time_split(PG_FUNCTION_ARGS)
2,920✔
351
{
352
  FuncCallContext *funcctx;
353

354
  /* If the function is being called for the first time */
355
  if (SRF_IS_FIRSTCALL())
2,920✔
356
  {
357
    /* Initialize the FuncCallContext */
358
    funcctx = SRF_FIRSTCALL_INIT();
883✔
359
    /* Switch to memory context appropriate for multiple function calls */
360
    MemoryContext oldcontext =
361
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
883✔
362

363
    /* Get input parameters */
364
    Temporal *temp = PG_GETARG_TEMPORAL_P(0);
883✔
365
    Interval *duration = PG_GETARG_INTERVAL_P(1);
883✔
366
    TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(2);
883✔
367

368
    /* Initialize state and verify parameter validity */
369
    int nbins;
370
    SpanBinState *state = temporal_time_bin_init(temp, duration, torigin,
883✔
371
      &nbins);
372

373
    /* Create function state */
374
    funcctx->user_fctx = state;
882✔
375

376
    /* Build a tuple description for a multidimensional grid tuple */
377
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
882✔
378
    BlessTupleDesc(funcctx->tuple_desc);
882✔
379
    MemoryContextSwitchTo(oldcontext);
380
  }
381

382
  /* Stuff done on every call of the function */
383
  funcctx = SRF_PERCALL_SETUP();
2,919✔
384
  /* State that no value is null */
385
  bool isnull[2] = {0,0};
2,919✔
386
  /* Get state */
387
  SpanBinState *state = funcctx->user_fctx;
2,919✔
388
  /* We need to loop since atTbox may be NULL */
389
  while (true)
390
  {
391
    /* Stop when we have used up all the grid tiles */
392
    if (state->done)
3,054✔
393
    {
394
      /* Switch to memory context appropriate for multiple function calls */
395
      MemoryContext oldcontext =
396
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
882✔
397
      pfree(state);
882✔
398
      MemoryContextSwitchTo(oldcontext);
399
      SRF_RETURN_DONE(funcctx);
882✔
400
    }
401

402
    /* Get current tile (if any) and advance state */
403
    Span span;
404
    if (! span_bin_state_get(state, &span))
2,172✔
405
    {
406
      /* Switch to memory context appropriate for multiple function calls */
407
      MemoryContext oldcontext =
NEW
408
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
×
NEW
409
      pfree(state);
×
410
      MemoryContextSwitchTo(oldcontext);
NEW
411
      SRF_RETURN_DONE(funcctx);
×
412
    }
413
    span_bin_state_next(state);
2,172✔
414

415
    /* Restrict the temporal point to the span */
416
    Temporal *atspan = temporal_restrict_tstzspan(state->temp, &span, REST_AT);
2,172✔
417
    if (atspan == NULL)
2,172✔
418
      continue;
135✔
419

420
    /* Form tuple and return */
421
    Datum tuple_arr[2]; /* used to construct the composite return value */
422
    tuple_arr[0] = span.lower;
2,037✔
423
    tuple_arr[1] = PointerGetDatum(atspan);
2,037✔
424
    HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
2,037✔
425
    Datum result = HeapTupleGetDatum(tuple);
2,037✔
426
    SRF_RETURN_NEXT(funcctx, result);
2,037✔
427
  }
428
}
429

430
PGDLLEXPORT Datum Tnumber_value_split(PG_FUNCTION_ARGS);
431
PG_FUNCTION_INFO_V1(Tnumber_value_split);
8✔
432
/**
433
 * @ingroup mobilitydb_temporal_analytics_tile
434
 * @brief Return the fragments of a temporal number split according to value
435
 * bins
436
 * @sqlfn valueSplit()
437
 */
438
Datum
439
Tnumber_value_split(PG_FUNCTION_ARGS)
5,772✔
440
{
441
  FuncCallContext *funcctx;
442

443
  /* If the function is being called for the first time */
444
  if (SRF_IS_FIRSTCALL())
5,772✔
445
  {
446
    /* Initialize the FuncCallContext */
447
    funcctx = SRF_FIRSTCALL_INIT();
490✔
448
    /* Switch to memory context appropriate for multiple function calls */
449
    MemoryContext oldcontext =
450
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
490✔
451

452
    /* Get input parameters */
453
    Temporal *temp = PG_GETARG_TEMPORAL_P(0);
490✔
454
    Datum size = PG_GETARG_DATUM(1);
490✔
455
    Datum origin = PG_GETARG_DATUM(2);
490✔
456

457
    /* Initialize state and verify parameter validity */
458
    int nbins;
459
    SpanBinState *state = tnumber_value_bin_init(temp, size, origin, &nbins);
490✔
460

461
    /* Create function state */
462
    funcctx->user_fctx = state;
490✔
463

464
    /* Build a tuple description for a multidimensional grid tuple */
465
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
490✔
466
    BlessTupleDesc(funcctx->tuple_desc);
490✔
467
    MemoryContextSwitchTo(oldcontext);
468
  }
469

470
  /* Stuff done on every call of the function */
471
  funcctx = SRF_PERCALL_SETUP();
5,772✔
472
  /* State that no value is null */
473
  bool isnull[2] = {0,0};
5,772✔
474
  /* Get state */
475
  SpanBinState *state = funcctx->user_fctx;
5,772✔
476
  /* We need to loop since atTbox may be NULL */
477
  while (true)
478
  {
479
    /* Stop when we have used up all the grid tiles */
480
    if (state->done)
10,227✔
481
    {
482
      /* Switch to memory context appropriate for multiple function calls */
483
      MemoryContext oldcontext =
484
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
490✔
485
      pfree(state);
490✔
486
      MemoryContextSwitchTo(oldcontext);
487
      SRF_RETURN_DONE(funcctx);
490✔
488
    }
489

490
    /* Get current tile (if any) and advance state */
491
    Span span;
492
    if (! span_bin_state_get(state, &span))
9,737✔
493
    {
494
      /* Switch to memory context appropriate for multiple function calls */
495
      MemoryContext oldcontext =
NEW
496
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
×
NEW
497
      pfree(state);
×
498
      MemoryContextSwitchTo(oldcontext);
NEW
499
      SRF_RETURN_DONE(funcctx);
×
500
    }
501
    span_bin_state_next(state);
9,737✔
502

503
    /* Restrict the temporal point to the span */
504
    Temporal *atspan = tnumber_restrict_span(state->temp, &span, REST_AT);
9,737✔
505
    if (atspan == NULL)
9,737✔
506
      continue;
4,455✔
507

508
    /* Form tuple and return */
509
    Datum tuple_arr[2]; /* used to construct the composite return value */
510
    tuple_arr[0] = span.lower;
5,282✔
511
    tuple_arr[1] = PointerGetDatum(atspan);
5,282✔
512
    HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
5,282✔
513
    Datum result = HeapTupleGetDatum(tuple);
5,282✔
514
    SRF_RETURN_NEXT(funcctx, result);
5,282✔
515
  }
516
}
517

518
PGDLLEXPORT Datum Tnumber_value_time_split(PG_FUNCTION_ARGS);
519
PG_FUNCTION_INFO_V1(Tnumber_value_time_split);
8✔
520
/**
521
 * @ingroup mobilitydb_temporal_analytics_tile
522
 * @brief Return the fragments of a temporal number split according to value
523
 * and time bins
524
 * @sqlfn valueTimeSplit()
525
 */
526
Datum
527
Tnumber_value_time_split(PG_FUNCTION_ARGS)
9,811✔
528
{
529
  FuncCallContext *funcctx;
530

531
  /* If the function is being called for the first time */
532
  if (SRF_IS_FIRSTCALL())
9,811✔
533
  {
534
    /* Initialize the FuncCallContext */
535
    funcctx = SRF_FIRSTCALL_INIT();
490✔
536
    /* Switch to memory context appropriate for multiple function calls */
537
    MemoryContext oldcontext =
538
      MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
490✔
539

540
    /* Get input parameters */
541
    Temporal *temp = PG_GETARG_TEMPORAL_P(0);
490✔
542
    Datum vsize = PG_GETARG_DATUM(1);
490✔
543
    Interval *duration = PG_GETARG_INTERVAL_P(2);
490✔
544
    Datum vorigin = PG_GETARG_DATUM(3);
490✔
545
    TimestampTz torigin = PG_GETARG_TIMESTAMPTZ(4);
490✔
546

547
    /* Initialize state and verify parameter validity */
548
    int ntiles;
549
    TboxGridState *state = tnumber_value_time_tile_init(temp, vsize, duration,
490✔
550
      vorigin, torigin, &ntiles);
551

552
    /* Create function state */
553
    funcctx->user_fctx = state;
490✔
554

555
    /* Build a tuple description for a multidimensional grid tuple */
556
    get_call_result_type(fcinfo, 0, &funcctx->tuple_desc);
490✔
557
    BlessTupleDesc(funcctx->tuple_desc);
490✔
558
    MemoryContextSwitchTo(oldcontext);
559
  }
560

561
  /* Stuff done on every call of the function */
562
  funcctx = SRF_PERCALL_SETUP();
9,811✔
563
  /* State that no value is null */
564
  bool isnull[3] = {0,0,0};
9,811✔
565
  /* Get state */
566
  TboxGridState *state = funcctx->user_fctx;
9,811✔
567
  /* We need to loop since atTbox may be NULL */
568
  while (true)
569
  {
570
    /* Stop when we have used up all the grid tiles */
571
    if (state->done)
28,815✔
572
    {
573
      /* Switch to memory context appropriate for multiple function calls */
574
      MemoryContext oldcontext =
575
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
490✔
576
      pfree(state);
490✔
577
      MemoryContextSwitchTo(oldcontext);
578
      SRF_RETURN_DONE(funcctx);
490✔
579
    }
580

581
    /* Get current tile (if any) and advance state */
582
    TBox box;
583
    if (! tbox_tile_state_get(state, &box))
28,325✔
584
    {
585
      /* Switch to memory context appropriate for multiple function calls */
586
      MemoryContext oldcontext =
NEW
587
        MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
×
NEW
588
      pfree(state);
×
589
      MemoryContextSwitchTo(oldcontext);
NEW
590
      SRF_RETURN_DONE(funcctx);
×
591
    }
592
    tbox_tile_state_next(state);
28,325✔
593

594
    /* Restrict the temporal point to the box */
595
    Temporal *attbox = tnumber_at_tbox(state->temp, &box);
28,325✔
596
    if (attbox == NULL)
28,325✔
597
      continue;
19,004✔
598

599
    /* Form tuple and return */
600
    Datum tuple_arr[3]; /* used to construct the composite return value */
601
    tuple_arr[0] = box.span.lower;
9,321✔
602
    tuple_arr[1] = box.period.lower;
9,321✔
603
    tuple_arr[2] = PointerGetDatum(attbox);
9,321✔
604
    HeapTuple tuple = heap_form_tuple(funcctx->tuple_desc, tuple_arr, isnull);
9,321✔
605
    Datum result = HeapTupleGetDatum(tuple);
9,321✔
606
    SRF_RETURN_NEXT(funcctx, result);
9,321✔
607
  }
608
}
609

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