Skip to content

Commit

Permalink
Fix numrange handling in no_gaps
Browse files Browse the repository at this point in the history
  • Loading branch information
jhf committed Nov 8, 2023
1 parent 78bf5d6 commit 7f9abdc
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 12 deletions.
20 changes: 20 additions & 0 deletions expected/33_no_gaps_numeric_test.out
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ WHERE job_id = 1;
SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(1.5, 12.5))
FROM numeric_shifts
WHERE job_id = 1;
no_gaps
---------
t
(1 row)

-- Test 3: Range with Extra at the Beginning
-- Expected: TRUE
Expand All @@ -72,18 +76,30 @@ WHERE job_id = 1;
SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(1.5, 11.5))
FROM numeric_shifts
WHERE job_id = 1;
no_gaps
---------
t
(1 row)

-- Test 5: Range with Extra on Both Sides
-- Expected: TRUE
SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(2.5, 11.5))
FROM numeric_shifts
WHERE job_id = 1;
no_gaps
---------
t
(1 row)

-- Test 6: Range that Misses Completely
-- Expected: FALSE
SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(20.5, 25.5))
FROM numeric_shifts
WHERE job_id = 1;
no_gaps
---------
f
(1 row)

-- Test 7: Range with Uncovered Time at the Beginning
-- Expected: FALSE
Expand All @@ -100,6 +116,10 @@ WHERE job_id = 1;
SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(1.5, 15.5))
FROM numeric_shifts
WHERE job_id = 1;
no_gaps
---------
f
(1 row)

SELECT sql_saga.drop_unique_key('numeric_shifts', 'numeric_shifts_job_id_worker_id_valid');
drop_unique_key
Expand Down
73 changes: 65 additions & 8 deletions no_gaps.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <pg_config.h>
#include <miscadmin.h>
#include <utils/array.h>
#include <utils/datum.h>
#include <utils/guc.h>
#include <utils/acl.h>
#include <utils/lsyscache.h>
Expand All @@ -41,6 +42,7 @@


// Declarations/Prototypes
char *DatumGetString(TypeCacheEntry *typcache, RangeBound bound);
Datum DatumGet(TypeCacheEntry *typcache, RangeBound bound);
Datum DatumNegativeInfinity(TypeCacheEntry *typcache);

Expand All @@ -65,7 +67,7 @@ typedef struct no_gaps_state {
// Implementations
Datum no_gaps_transfn(PG_FUNCTION_ARGS)
{
MemoryContext aggContext;
MemoryContext aggContext, oldContext;
no_gaps_state *state;
RangeType *current_range,
*target_range;
Expand Down Expand Up @@ -107,7 +109,9 @@ Datum no_gaps_transfn(PG_FUNCTION_ARGS)
ereport(DEBUG1, (errmsg("target is [%ld, %ld)", DatumGet(typcache, state->target_start), DatumGet(typcache, state->target_end))));

// Initialize covered_to to negative infinity bound
oldContext = MemoryContextSwitchTo(aggContext);
state->covered_to.val = DatumNegativeInfinity(typcache);
MemoryContextSwitchTo(oldContext);
state->covered_to.infinite = true;
state->covered_to.inclusive = true;
state->covered_to.lower = true;
Expand Down Expand Up @@ -181,15 +185,25 @@ Datum no_gaps_transfn(PG_FUNCTION_ARGS)

// Update the covered range if the current range extends beyond it
if (range_cmp_bounds(typcache, &current_end, &state->covered_to) > 0) {
Oid datum_oid = typcache->rngelemtype->type_id;
TypeCacheEntry *datumtypcache;

state->covered_to = current_end;

//if (!typcache->typbyval && typcache->typlen == -1) {
// Size datumSize = VARSIZE_ANY(DatumGetPointer(current_end.val));
// MemoryContext oldContext = MemoryContextSwitchTo(aggContext);
// state->covered_to.val = PointerGetDatum(palloc(datumSize));
// memcpy(DatumGetPointer(state->covered_to.val), DatumGetPointer(current_end.val), datumSize);
// MemoryContextSwitchTo(oldContext);
//}
datumtypcache = lookup_type_cache(datum_oid, 0);
if (!datumtypcache->typbyval && datumtypcache->typlen == -1) {
MemoryContext oldContext;
ereport(DEBUG1, (errmsg("Performing memory copy.")));
//ereport(DEBUG1, (errmsg("Before pfree(state->covered_to.val)")));
//pfree(state->covered_to.val);
oldContext = MemoryContextSwitchTo(aggContext);
ereport(DEBUG1, (errmsg("Before datumCopy.")));
state->covered_to.val = datumCopy(current_end.val, /*pass by reference when false*/ false, /*dynamic length when -1*/ -1);
ereport(DEBUG1, (errmsg("After datumCopy.")));
MemoryContextSwitchTo(oldContext);
} else {
ereport(DEBUG1, (errmsg("Skipping memory copy.")));
}

// Notice that the previous non-inclusive end is included in the next start.
state->covered_to.inclusive = true;
Expand Down Expand Up @@ -264,3 +278,46 @@ Datum DatumNegativeInfinity(TypeCacheEntry *typcache)
return (Datum) 0; // This line will not be reached due to the elog(ERROR) above
}
}


char *DatumGetString(TypeCacheEntry *typcache, RangeBound bound) {
Oid elem_type_id = typcache->rngelemtype->type_id;
char *result;

switch (elem_type_id) {
case INT4OID:
result = psprintf("%d", DatumGetInt32(bound.val));
break;
case INT8OID:
result = psprintf("%ld", DatumGetInt64(bound.val));
break;
case DATEOID: {
char *dateStr = DatumGetCString(DirectFunctionCall1(date_out, bound.val));
result = psprintf("%s", dateStr);
pfree(dateStr);
break;
}
case NUMERICOID: {
char *numericStr = DatumGetCString(DirectFunctionCall1(numeric_out, bound.val));
result = psprintf("%s", numericStr);
pfree(numericStr);
break;
}
case TIMESTAMPOID: {
char *timestampStr = DatumGetCString(DirectFunctionCall1(timestamp_out, bound.val));
result = psprintf("%s", timestampStr);
pfree(timestampStr);
break;
}
case TIMESTAMPTZOID: {
char *timestamptzStr = DatumGetCString(DirectFunctionCall1(timestamptz_out, bound.val));
result = psprintf("%s", timestamptzStr);
pfree(timestamptzStr);
break;
}
default:
elog(ERROR, "Unsupported element type id: %u", elem_type_id);
return NULL; // This line will not be reached due to the elog(ERROR) above
}
return result;
}
4 changes: 0 additions & 4 deletions sql/33_no_gaps_numeric_test.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ INSERT INTO numeric_shifts(job_id, worker_id, valid_from, valid_to) VALUES

TABLE numeric_shifts;

SET client_min_messages TO DEBUG1;

-- This test checks for an exact match with one range
-- Expected: TRUE
SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(1.5, 6.5))
Expand Down Expand Up @@ -70,8 +68,6 @@ SELECT sql_saga.no_gaps(numrange(valid_from, valid_to), numrange(1.5, 15.5))
FROM numeric_shifts
WHERE job_id = 1;

SET client_min_messages TO NOTICE;

SELECT sql_saga.drop_unique_key('numeric_shifts', 'numeric_shifts_job_id_worker_id_valid');
SELECT sql_saga.drop_era('numeric_shifts');

Expand Down

0 comments on commit 7f9abdc

Please sign in to comment.