DRAFTThis page is not published. Only visible in development mode.
math module · Scalar Functions

Arithmetic Policies

Sometimes an arithmetic result simply does not exist: the sum is too large for the result type, or the divisor is zero. By default ReifyDB fails the statement rather than silently producing a wrong number. When failing is not what you want, each arithmetic function family - math::add, math::sub, math::mul, math::div, math::rem - comes in six policy variants that name, in the query itself, what happens instead.

The default: fail loudly

The bare operators (+, -, *, /, %) and the bare functions (math::add and friends) apply the same rule: a result that cannot be represented is an error, not a wrong answer. Overflow fails with NUMBER_002 (number out of range):

$ Overflow Is an Error by Default
$ ctrl+enter to run

and division or remainder by zero fails with NUMBER_007. The functions report it wrapped in a FUNCTION_007 execution error; the cause is the same:

$ Division by Zero Is an Error by Default
$ ctrl+enter to run

For floating-point inputs the same rule covers non-finite results: an operation that would produce infinity or NaN counts as overflow.

One family, seven spellings

Each policy is a separate function named with a suffix: math::add_saturate, math::div_none, math::mul_strict, and so on. All five families - add, sub, mul, div, rem - have all six variants. Shown here for math::add:

SignatureOn overflowOn division by zero
math::add(a, b)Fails the statement (NUMBER_002)Fails the statement (NUMBER_007)
math::add_saturate(a, b)Clamps to the result type's minimum or maximumReturns 0
math::add_wrap(a, b)Wraps around (two's complement)Returns 0
math::add_zero(a, b)Returns 0Returns 0
math::add_none(a, b)Returns noneReturns none
math::add_default(a, b, fallback)Returns fallback for that rowReturns fallback for that row
math::add_strict(a, b, message)Fails the statement with your message (FUNCTION_007)Fails the statement with your message (FUNCTION_007)

The row-level policies (_saturate, _wrap, _zero, _none, _default) affect only the offending row; every other row computes normally. The failing policies (the bare function and _strict) abort the whole statement on the first impossible result.

saturate: clamp to the type range

_saturate pins an out-of-range result to the result type's minimum or maximum. Use it when "as large as representable" is a better answer than no answer - accumulating counters, scores with a cap:

$ saturate Clamps to the Type Range
$ ctrl+enter to run

On unsigned types, subtracting below zero clamps to zero - a natural fit for "remaining quantity" arithmetic:

$ saturate Stops Unsigned Subtraction at Zero
$ ctrl+enter to run

wrap and zero

_wrap applies two's-complement wraparound, the behavior of unchecked machine arithmetic - useful for hash-style computations where wrapping is intended. _zero substitutes 0 for any result that does not exist:

$ wrap and zero on the Same Overflow
$ ctrl+enter to run

none: make the result missing

_none turns an impossible result into a missing value, which then flows through the rest of the query with the usual none semantics: filters drop it, aggregates skip it. This is the honest choice for ratios with an empty denominator - an average over nothing is not zero, it is unknown:

$ none Turns the Impossible Row Into a Missing Value
$ ctrl+enter to run

default: substitute your own value

_default takes a third argument and returns it for the rows where the real result does not exist. The fallback is coerced to the result type; a none fallback yields none:

$ default Substitutes Your Fallback Value
$ ctrl+enter to run

strict: fail with your own message

_strict also fails the statement, like the bare function, but the third argument replaces the generic diagnostic with a message that says what actually went wrong in your domain:

$ strict Fails With Your Own Message
$ ctrl+enter to run

Missing input is not a policy decision

The policies decide what happens when a result cannot exist. A missing input is different: the result is simply missing too, in every variant - even _strict does not fail on a none input, and _zero does not invent a zero for one:

$ Missing Input Propagates in Every Variant
$ ctrl+enter to run

To replace missing inputs, handle them explicitly before the arithmetic - see Working with none.

Types widen before they overflow

Arithmetic first promotes both operands to a wider result type: two int4 values add as int8, two float4 values as float8, and mixed signed/unsigned operands promote to a signed type that holds both. Promotion caps at the 128-bit types (int16, uint16), so integer overflow only occurs at the extremes of those widest types - which is why the examples above use them. Division by zero, not overflow, is the case these policies handle day to day:

$ Results Widen Before They Can Overflow
$ ctrl+enter to run
Not related to table policies
These function variants are unrelated to policies in the data model, which are row-level security rules attached to tables and other objects. Arithmetic policies are purely a naming convention for scalar functions: the behavior is chosen per call site, visible in the query text.