Skip to content

Commit 414095b

Browse files
df7cbmsdemlei
authored andcommitted
Implement smoc_intersection aka *
1 parent 2fd90cf commit 414095b

File tree

6 files changed

+119
-6
lines changed

6 files changed

+119
-6
lines changed

expected/moc.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,3 +505,21 @@ SELECT '1/1'::smoc || '1/2' AS union;
505505
1/1-2
506506
(1 row)
507507

508+
SELECT smoc_intersection('1/1,4-6', '1/3-5 2/8');
509+
smoc_intersection
510+
-------------------
511+
1/4-5
512+
(1 row)
513+
514+
SELECT '0/1'::smoc * '1/3,5,7,9' AS intersection;
515+
intersection
516+
--------------
517+
1/5,7
518+
(1 row)
519+
520+
SELECT '1/9,11,13,15'::smoc * '0/1,2' AS intersection;
521+
intersection
522+
--------------
523+
1/9,11
524+
(1 row)
525+

moc.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ PG_FUNCTION_INFO_V1(spoint_not_subset_smoc);
1919
PG_FUNCTION_INFO_V1(smoc_superset_spoint);
2020
PG_FUNCTION_INFO_V1(smoc_not_superset_spoint);
2121
PG_FUNCTION_INFO_V1(smoc_union);
22+
PG_FUNCTION_INFO_V1(smoc_intersection);
2223

2324
int32 smoc_output_type = 0;
2425

@@ -604,7 +605,35 @@ smoc_union(PG_FUNCTION_ARGS)
604605
void* moc_in_context = create_moc_in_context(moc_error_out);
605606
int32 moc_size;
606607

607-
moc_in_context_union(moc_in_context, moc_a, VARSIZE(moc_a) - VARHDRSZ, moc_b, VARSIZE(moc_b) - VARHDRSZ, moc_error_out);
608+
moc_union(moc_in_context, moc_a, VARSIZE(moc_a) - VARHDRSZ, moc_b, VARSIZE(moc_b) - VARHDRSZ, moc_error_out);
609+
610+
moc_size = VARHDRSZ + get_moc_size(moc_in_context, moc_error_out);
611+
/* palloc() will leak the moc_in_context if it fails :-/ */
612+
moc_ret = (Smoc*) palloc0(moc_size);
613+
SET_VARSIZE(moc_ret, moc_size);
614+
615+
if (create_moc_release_context(moc_in_context, moc_ret, moc_error_out))
616+
{
617+
PG_RETURN_POINTER(moc_ret);
618+
}
619+
else
620+
{
621+
ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR),
622+
errmsg("Internal error in creation of MOC from text input.")));
623+
PG_RETURN_NULL();
624+
}
625+
}
626+
627+
Datum
628+
smoc_intersection(PG_FUNCTION_ARGS)
629+
{
630+
Smoc* moc_a = (Smoc *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
631+
Smoc* moc_b = (Smoc *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
632+
Smoc* moc_ret;
633+
void* moc_in_context = create_moc_in_context(moc_error_out);
634+
int32 moc_size;
635+
636+
moc_intersection(moc_in_context, moc_a, VARSIZE(moc_a) - VARHDRSZ, moc_b, VARSIZE(moc_b) - VARHDRSZ, moc_error_out);
608637

609638
moc_size = VARHDRSZ + get_moc_size(moc_in_context, moc_error_out);
610639
/* palloc() will leak the moc_in_context if it fails :-/ */

pgs_moc_ops.sql.in

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,20 @@ CREATE FUNCTION smoc_union (smoc, smoc)
44
LANGUAGE C
55
STRICT;
66

7+
CREATE FUNCTION smoc_intersection (smoc, smoc)
8+
RETURNS smoc
9+
AS 'MODULE_PATHNAME'
10+
LANGUAGE C
11+
STRICT;
12+
713
CREATE OPERATOR || (
814
LEFTARG = smoc,
915
RIGHTARG = smoc,
1016
PROCEDURE = smoc_union
1117
);
18+
19+
CREATE OPERATOR * (
20+
LEFTARG = smoc,
21+
RIGHTARG = smoc,
22+
PROCEDURE = smoc_intersection
23+
);

pgs_process_moc.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ moc_interval*
139139
interval_lower_bound(moc_interval*, moc_interval*, hpint64);
140140

141141
void
142-
moc_in_context_union(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* moc_b, int32 moc_b_end,
142+
moc_union(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* moc_b, int32 moc_b_end,
143+
pgs_error_handler error_out);
144+
145+
void
146+
moc_intersection(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* moc_b, int32 moc_b_end,
143147
pgs_error_handler error_out);
144148

145149
#ifdef __cplusplus

process_moc.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,13 @@ release_moc_in_context(void* moc_in_context, pgs_error_handler error_out)
380380
void
381381
add_to_map(moc_map & input_map, hpint64 first, hpint64 last)
382382
{
383-
map_iterator lower = input_map.lower_bound(first);
384-
map_iterator upper = input_map.upper_bound(last);
383+
map_iterator lower = input_map.lower_bound(first); // first element not less than 'first'
384+
map_iterator upper = input_map.upper_bound(last); // first element greater than 'last'
385385

386386
if (lower != input_map.begin())
387387
{
388388
map_iterator before = lower;
389-
--before;
389+
--before; // element actually less than 'first'
390390
if (before->second >= first)
391391
{
392392
if (before->second >= last)
@@ -841,7 +841,7 @@ interval_lower_bound(moc_interval* first, moc_interval* last, hpint64 value)
841841
}
842842

843843
void
844-
moc_in_context_union(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* moc_b, int32 moc_b_end,
844+
moc_union(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* moc_b, int32 moc_b_end,
845845
pgs_error_handler error_out)
846846
{
847847
int32 begin = moc_a->data_begin;
@@ -875,3 +875,49 @@ moc_in_context_union(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* m
875875
}
876876
PGS_CATCH
877877
};
878+
879+
void
880+
moc_intersection(void* moc_in_context, Smoc* moc_a, int32 moc_a_end, Smoc* moc_b, int32 moc_b_end,
881+
pgs_error_handler error_out)
882+
{
883+
int32 a = moc_a->data_begin;
884+
int32 b = moc_b->data_begin;
885+
int32 entry_size = MOC_INTERVAL_SIZE;
886+
moc_input* p = static_cast<moc_input*>(moc_in_context);
887+
PGS_TRY
888+
moc_input & m = *p;
889+
890+
for (; a < moc_a_end && b < moc_b_end; ) // iterate over both in parallel
891+
{
892+
// page bumps
893+
int32 mod = (a + entry_size) % PG_TOAST_PAGE_FRAGMENT;
894+
if (mod > 0 && mod < entry_size)
895+
a += entry_size - mod;
896+
moc_interval & x = *interval_ptr(moc_a, a);
897+
898+
mod = (b + entry_size) % PG_TOAST_PAGE_FRAGMENT;
899+
if (mod > 0 && mod < entry_size)
900+
b += entry_size - mod;
901+
moc_interval & y = *interval_ptr(moc_b, b);
902+
903+
if (x.second <= y.first) // a entirely left of b, advance a
904+
{
905+
a += entry_size;
906+
continue;
907+
}
908+
if (y.second <= x.first) // b entirely left of a, advance b
909+
{
910+
b += entry_size;
911+
continue;
912+
}
913+
914+
// add intersection of the two intervals we are at now
915+
add_to_map(m.input_map, std::max(x.first, y.first), std::min(x.second, y.second));
916+
917+
if (x.second <= y.second) // advance interval that has the lowest end (there might be more overlaps)
918+
a += entry_size;
919+
else
920+
b += entry_size;
921+
}
922+
PGS_CATCH
923+
}

sql/moc.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,7 @@ SELECT smoc('28/1101-1103');
113113

114114
SELECT smoc_union('1/1,4-6', '1/3-5 2/8');
115115
SELECT '1/1'::smoc || '1/2' AS union;
116+
117+
SELECT smoc_intersection('1/1,4-6', '1/3-5 2/8');
118+
SELECT '0/1'::smoc * '1/3,5,7,9' AS intersection;
119+
SELECT '1/9,11,13,15'::smoc * '0/1,2' AS intersection;

0 commit comments

Comments
 (0)