Skip to content

oglego/duckdb_clamp

Repository files navigation

Clamp

This repository is based on the official DuckDB extension-template: https://github.com/duckdb/extension-template

If you’re interested in building and distributing your own DuckDB extension, that repository is a great starting point.


DuckDB Clamp Extension

The Clamp extension introduces range-clamping scalar functions to DuckDB. Initial development focuses on saturation arithmetic, with future plans to expand into additional math-based functions.

It currently provides:

  • clamp(value, min, max) — clamp to an arbitrary range
  • clip(value, min, max) - alias for clamp
  • saturate(value) — clamp to the [0, 1] range
  • clamp01(value) — alias for saturate, common in graphics and ML
  • wrap(value, min, max) - Wrap a value x into the range [min_val, max_val) using modular arithmetic
  • pingpong(value, min, max) - Return a value that "bounces" back and forth between the minimum and maximum
  • fract(value) - Return the fractional (decimal) part of a number

All functions are implemented as native DuckDB scalar functions with vectorized execution for high performance.


Features

  • Native DuckDB scalar functions (ScalarFunctionSet)
  • Vectorized execution via DuckDB executors
    • TernaryExecutor for clamp / clip / wrap / pingpong
    • UnaryExecutor for saturate / clamp01 / fract
  • Supports:
    • BIGINT (int64_t) — clamp, saturate1, clamp01, clip, wrap, pingpong, fract
    • DOUBLEclamp, saturate, clamp01, clip, wrap, pingpong, fract
  • NULL-safe:
    • returns NULL if any input argument is NULL
  • Strict validation:
    • clamp / clip throws an error if min > max
    • wrap throws an error if min >= max
    • pingpong throws an error if min>=max

Installation

From source

  1. Build the extension using DuckDB’s extension build system (see Building below).
  2. Place the compiled clamp.duckdb_extension binary in DuckDB’s extension directory or load it explicitly.

Tips for speedy builds

DuckDB extensions currently rely on DuckDB's build system to provide easy testing and distributing. This does however come at the downside of requiring the template to build DuckDB and its unittest binary every time you build your extension. To mitigate this, we highly recommend installing ccache and ninja. This will ensure you only need to build core DuckDB once and allows for rapid rebuilds.

To clean build using ninja and ccache ensure both are installed and run:

rm -rf build
GEN=ninja make

To load the extension:

LOAD 'build/release/extension/clamp/clamp.duckdb_extension';
SELECT clamp(15, 10, 20);

Usage

Load the extension:

INSTALL clamp;
LOAD clamp;

clamp(value, min, max)

Restricts a value to an inclusive minimum and maximum bound.

-- Value within bounds
SELECT clamp(15, 10, 20);
-- 15

-- Below minimum
SELECT clamp(5, 10, 20);
-- 10

-- Above maximum
SELECT clamp(25, 10, 20);
-- 20

-- Floating point support
SELECT clamp(3.14, 2.71, 4.0);
-- 3.14

-- NULL propagation
SELECT clamp(NULL, 10, 20);
-- NULL

If the minimum bound is greater than the maximum bound, the function throws an error:

SELECT clamp(15, 20, 10);
-- CLAMP error: Minimum bound (20) cannot be greater than maximum bound (10).

clip(value, min, max)

Alias for clamp - restricts a value to an inclusive minimum and maximum bound.

-- Value within bounds
SELECT clip(15, 10, 20);
-- 15

-- Below minimum
SELECT clip(5, 10, 20);
-- 10

-- Above maximum
SELECT clip(25, 10, 20);
-- 20

saturate(value)

A specialized clamp that restricts a value to the [0, 1] range.

This function is commonly used in graphics, normalization, and machine learning workflows.

SELECT saturate(-0.25);
-- 0.0

SELECT saturate(0.5);
-- 0.5

SELECT saturate(1.75);
-- 1.0

SELECT saturate(NULL);
-- NULL

clamp01(value)

An alias for saturate(value).

This name is widely used in graphics and shader languages and is provided for familiarity and readability.

SELECT clamp01(-1.0);
-- 0.0

SELECT clamp01(0.25);
-- 0.25

SELECT clamp01(2.0);
-- 1.0

wrap(value, min, max)

Wrap a value x into the range [min_val, max_val) using modular arithmetic.

Definition:

WRAP(x, min_val, max_val) = min_val + ((x - min_val) % (max_val - min_val))

SELECT wrap(11, 0, 10);
-- 1

SELECT wrap(25, 10, 20);
--15

SELECT wrap(45, 10, 20);
--15

SELECT wrap(5, 10, 20);
--15

SELECT wrap(-15, 10, 20);
--15

SELECT wrap(370, 0, 360), wrap(-10, 0, 360), wrap(720, 0, 360);

-- 10.0	350.0	0.0

pingpong(value, min, max)

Returns a value that "bounces" back and forth between the minimum and maximum boundaries. This creates a triangle wave pattern, commonly used for smooth oscillations in animations and procedural generation.

When value is at min, the result is min. As value increases toward max, the result increases linearly. Upon hitting max, the result reverses direction and decreases back toward min. The output is periodic with a full "round-trip" period of 2 * (max-min).

SELECT pingpong(11, 0, 10);
-- 9

-- Oscillation between 10 and 20
SELECT pingpong(12, 10, 20);
-- 12.0

-- 2 past the max (20), so it bounces back to 18
SELECT pingpong(22, 10, 20);
-- 18.0

-- 8 past the max (20), so it bounces back to 12
SELECT pingpong(28, 10, 20);
-- 12.0

fract(val)

Returns the fractional (decimal) part of a number. This is defined as x - floor(x).

Isolates the digits following the decimal point. For negative numbers, fract returns the positive remainder required to reach the next lower integer.

-- Standard use
SELECT fract(1.75);
-- 0.75

-- Integer inputs always return 0
SELECT fract(10);
-- 0.0

-- Negative wrapping (Blender/Shader style)
SELECT fract(-0.1);
-- 0.9

Function Signatures

clamp(value, min, max)
clip(value, min, max)
saturate(value)
clamp01(value)
wrap(value, min, max)
pingpong(value, min, max)
fract(value)

Parameters

  • value The value to restrict.

  • min Lower bound (inclusive). Used only by clamp.

  • max Upper bound (inclusive). Used only by clamp.

All arguments must be of the same type.


Supported Types

Function BIGINT DOUBLE
clamp
saturate
clamp01
clip
wrap
pingpong
fract

Implementation Notes

  • The core clamp logic is implemented in ClampOperator::Operation<T>.
  • saturate and clamp01 use a specialized unary operator with fixed bounds for efficiency and clarity.
  • DuckDB’s vectorized executors apply operations across data chunks, enabling efficient batch execution.
  • NULL handling uses DuckDB’s DEFAULT_NULL_HANDLING, ensuring standard SQL semantics.

Testing

SQL tests live in:

test/sql/clamp.test

Run the test suite with:

make test

Potential Future Additions

While this extension currently provides clamp, clip, wrap, saturate, and others, it intentionally leaves room for other mathematically range-based utilities that frequently appear in numerical computing, analytics, and graphics domains.

Possible future additions include:

  • IsPowerOfTwo Boolean check that returns true if a number is a power of two.

  • DeltaAngle Calculates the shortest distance between two angles.

These functions share similar characteristics:

  • Simple scalar logic
  • Deterministic and vectorizable execution
  • No external dependencies

Legal Disclaimer

THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.

IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

MIT License

Copyright (c) 2026

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

The Clamp extension introduces range-clamping scalar functions to DuckDB. Initial development focuses on saturation arithmetic, with future plans to expand into additional math-based functions.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Generated from duckdb/extension-template