ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
IntervalUnion.h
Go to the documentation of this file.
1/**
2 * @file semiring/IntervalUnion.h
3 * @brief Interval-union m-semiring over PostgreSQL @c multirange types.
4 *
5 * The interval-union m-semiring associates each gate with a finite
6 * union of pairwise-disjoint intervals over a densely-ordered linear
7 * domain (timestamp, numeric, integer, ...). Addition is multirange
8 * union, multiplication is intersection, and monus is set difference.
9 * The class is parameterised by a multirange type OID, so a single
10 * implementation covers @c tstzmultirange (the temporal instance),
11 * @c nummultirange (numeric validity ranges), and @c int4multirange
12 * (integer page/line ranges) – and any other multirange type the user
13 * happens to define.
14 *
15 * Operations:
16 * - @c zero() → <tt>'{}'</tt> (empty multirange)
17 * - @c one() → <tt>'{(,)}'</tt> (universal multirange)
18 * - @c plus() → multirange union (@c multirange_union)
19 * - @c times() → multirange intersection (@c multirange_intersect)
20 * - @c monus() → multirange set difference (@c multirange_minus)
21 * - @c delta() → identity (preserves the supporting multirange so that
22 * aggregated groups carry the actual time/parameter region
23 * of contributing rows rather than the universal range)
24 *
25 * Absorptivity: `absorptive()` returns `true`. With inputs being subsets
26 * of the universal range, @f$\mathbb{1} \oplus a = (-\infty,+\infty) \cup a
27 * = (-\infty,+\infty) = \mathbb{1}@f$.
28 *
29 * @note Requires PostgreSQL 14+ (multirange types). The polymorphic
30 * built-ins @c F_MULTIRANGE_UNION / @c F_MULTIRANGE_INTERSECT /
31 * @c F_MULTIRANGE_MINUS work for every multirange carrier and access
32 * @c fcinfo->flinfo->fn_extra for type-cache lookups, so they must be
33 * invoked through @c OidFunctionCall* (which builds a proper
34 * @c FmgrInfo) rather than @c DirectFunctionCall* (which leaves
35 * @c flinfo NULL and would crash).
36 *
37 * @see https://provsql.org/lean-docs/Provenance/Semirings/IntervalUnion.html
38 * Lean 4 verified instance: @c instSemiringWithMonusIntervalUnion,
39 * with proofs of @c IntervalUnion.absorptive and
40 * @c IntervalUnion.mul_sub_left_distributive.
41 */
42#ifndef INTERVAL_UNION_H
43#define INTERVAL_UNION_H
44
45#if PG_VERSION_NUM >= 140000 || defined(DOXYGEN)
46
47extern "C" {
48#include "fmgr.h"
49#include "catalog/pg_type.h"
50#include "utils/fmgroids.h"
51#include "utils/multirangetypes.h"
52#include "utils/lsyscache.h"
53}
54
55#include <vector>
56
57#include "Semiring.h"
58
59namespace semiring {
60/**
61 * @brief Interval-union m-semiring with @c Datum carrier, parameterised
62 * by a multirange type OID.
63 *
64 * Each gate evaluates to a multirange Datum allocated in the current
65 * memory context. The class caches the input-function OIDs in its
66 * constructor and the zero/one Datum values lazily on first use, so
67 * that operations dispatch cheaply during circuit traversal.
68 */
69class IntervalUnion : public semiring::Semiring<Datum>
70{
73/* The zero/one Datums are built lazily, on first use *during
74 * evaluation*: the semiring object itself is constructed while the
75 * SPI connection that fetched the leaf mapping is still open, and a
76 * multirange Datum allocated then would live in the SPI procedure
77 * memory context, destroyed by SPI_finish before evaluation reads
78 * it. */
79mutable Datum cached_zero = 0;
80mutable Datum cached_one = 0;
81mutable bool cached = false;
82
83void ensureCache() const {
84 if (!cached) {
85 cached_zero = OidInputFunctionCall(
86 in_func, const_cast<char *>("{}"), typioparam, -1);
87 cached_one = OidInputFunctionCall(
88 in_func, const_cast<char *>("{(,)}"), typioparam, -1);
89 cached = true;
90 }
91}
92
93public:
94explicit IntervalUnion(Oid multirange_oid) {
95 getTypeInputInfo(multirange_oid, &in_func, &typioparam);
96}
97
98virtual value_type zero() const override {
100 return cached_zero;
101}
102virtual value_type one() const override {
103 ensureCache();
104 return cached_one;
105}
106virtual value_type plus(const std::vector<value_type> &v) const override {
107 if(v.empty()) return zero();
108 Datum r = v[0];
109 for(size_t i = 1; i < v.size(); ++i)
110 r = OidFunctionCall2(F_MULTIRANGE_UNION, r, v[i]);
111 return r;
112}
113virtual value_type times(const std::vector<value_type> &v) const override {
114 if(v.empty()) return one();
115 Datum r = v[0];
116 for(size_t i = 1; i < v.size(); ++i)
117 r = OidFunctionCall2(F_MULTIRANGE_INTERSECT, r, v[i]);
118 return r;
119}
120virtual value_type monus(value_type x, value_type y) const override
121{
122 return OidFunctionCall2(F_MULTIRANGE_MINUS, x, y);
123}
124virtual value_type delta(value_type x) const override
125{
126 return x;
127}
128virtual bool absorptive() const override {
129 return true;
130}
131/**
132 * @brief A semiring homomorphism @c BoolFunc(Y) →+* IntervalUnion exists
133 * (map each variable to a fixed nonempty interval), so the
134 * safe-query Boolean rewrite preserves evaluation results.
135 *
136 * Lean: @c Provenance.Semirings.IntervalUnion.homomorphism_from_BoolFunc
137 * (provenance-lean/Provenance/Semirings/IntervalUnion.lean).
138 */
139virtual bool compatibleWithBooleanRewrite() const override {
140 return true;
141}
142
143/**
144 * @brief Parse a multirange text literal to a Datum.
145 *
146 * Used by @c pec_multirange() to build the input mapping; exposed here
147 * so the parser can share the cached @c in_func / @c typioparam.
148 */
149Datum parse_leaf(const char *str) const {
150 return OidInputFunctionCall(in_func, const_cast<char *>(str), typioparam, -1);
151}
152
153};
154}
155
156#endif /* PG_VERSION_NUM >= 140000 || defined(DOXYGEN) */
157
158#endif /* INTERVAL_UNION_H */
Abstract semiring interface for provenance evaluation.
IntervalUnion(Oid multirange_oid)
virtual value_type zero() const override
Return the additive identity .
Datum parse_leaf(const char *str) const
Parse a multirange text literal to a Datum.
virtual value_type delta(value_type x) const override
Apply the operator.
virtual value_type plus(const std::vector< value_type > &v) const override
Apply the additive operation to a list of values.
virtual bool absorptive() const override
Return true if this semiring is absorptive ( for all ).
virtual value_type times(const std::vector< value_type > &v) const override
Apply the multiplicative operation to a list of values.
virtual bool compatibleWithBooleanRewrite() const override
A semiring homomorphism BoolFunc(Y) →+* IntervalUnion exists (map each variable to a fixed nonempty i...
virtual value_type one() const override
Return the multiplicative identity .
virtual value_type monus(value_type x, value_type y) const override
Apply the monus (m-semiring difference) operation.
Abstract base class for (m-)semirings.
Definition Semiring.h:93