Physical unit conversion, unit and quantity parsing, dimensional compatibility, and measurement validation using UCUM
Compatibility Matrix
This table covers all DuckDB releases that have not reached end-of-life, including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.
| Platform | 1.4.4 | 1.4.5 | 1.5.5 | 1.5.6 | 2.0.0 |
|---|---|---|---|---|---|
| Linux AMD64 | |||||
| Linux ARM64 | |||||
| macOS AMD64 | |||||
| macOS ARM64 | |||||
| Windows AMD64 | |||||
| Windows ARM64 | |||||
| WebAssembly |
Installing and Loading
INSTALL units FROM community;
LOAD units;
Example
LOAD units;
-- Normalize mixed energy measurements. UCUM spells kilowatt-hour as kW.h.
SELECT site, round(unit_convert(value, source_unit, 'kW.h'), 6) AS kwh
FROM (VALUES
('Plant A', 3600000.0, 'J'),
('Plant B', 1250.0, 'W.h'),
('Plant C', 2.5, 'kW.h')
) AS readings(site, value, source_unit);
-- General compound expressions and dimensional compatibility.
SELECT unit_convert(1000, 'kg/m3', 'g/L') AS density_g_per_litre,
unit_compatible('Pa', 'kg/(m.s2)') AS pressure_matches;
-- Absolute temperatures and temperature differences are different operations.
SELECT unit_convert(20, 'Cel', '[degF]') AS absolute_fahrenheit,
unit_convert_delta(20, 'Cel', '[degF]') AS difference_fahrenheit;
-- Diagnostics without aborting a dirty-data scan.
SELECT unit_convert_checked(1, 'kg', 'm');
SELECT unit_parse_checked('Cel/s');
-- Parse measurement text with an explicit separator and no alias guessing.
SELECT quantity_parse('12.5 kg/m3');
SELECT quantity_parse_checked('1eV'); -- invalid_quantity; use '1 eV'
-- Discover registered units, including explicit support status.
SELECT unit, name, supported
FROM unit_search('pressure') ORDER BY unit;
About units
units is a native Rust extension for DuckDB 2.0.0 using C Extension API v2.
It provides measurement normalization with runtime unit columns, compound-unit
parsing, dimensional compatibility checks, and distinct conversion functions
for absolute temperatures and temperature differences. No worker process or
custom numeric type is required.
Unit definitions and parsing use the pinned octofhir-ucum 0.9.2 backend.
Syntax follows case-sensitive UCUM 2.2: use kW.h, kg/m3, Cel, and
[degF]. Human spellings are not guessed: C is coulomb, not Celsius;
MW and mW differ by a factor of one billion.
Strict conversion raises errors for invalid units and incompatible dimensions.
Checked conversion returns STRUCT(value, status, message); checked parsing
returns STRUCT(definition, status, message). Missing inputs have a distinct
missing_input status. This supports auditing and quarantining bad rows before
normalization. quantity_parse() parses a decimal value plus a UCUM unit;
quantity_parse_checked() returns STRUCT(quantity, status, message).
Quantity text requires a space or tab between the number and unit, rejecting
ambiguous compact forms, locale-dependent numbers, and out-of-range values.
units_catalog() exposes 312 registered UCUM atoms with definitions and support
diagnostics; 253 currently pass the extension's conversion policy. Prefixes and
compound expressions extend beyond this finite catalog. unit_search() searches
codes, names, and properties for discovery, without changing strict parsing.
Compatibility checks dimensions, not semantic quantity kinds: energy and torque are dimensionally compatible. Logarithmic and arbitrary units, affine-temperature compounds, quantity algebra, and uncertainty propagation are deliberately outside the current scope. SQL results are DOUBLE, not exact rational quantities.
This is a development version, not yet a production release. Project code is licensed under MIT; third-party dependencies and UCUM data retain their respective license terms.
See the README for the full API, numerical limits, and examples, and the roadmap for release gates.
Added Functions
| function_name | function_type | description | comment | examples |
|---|---|---|---|---|
| quantity_parse | scalar | Parse a decimal value and supported UCUM unit, separated by a space or tab. Returns STRUCT(value, unit, definition). No aliases or locale guessing. NULL stays NULL; invalid input raises an error. | NULL | [SELECT quantity_parse('12.5 kg/m3')] |
| quantity_parse_checked | scalar | Checked quantity parsing: returns STRUCT(quantity, status, message). Invalid input has NULL quantity; NULL text has status missing_input. A space or tab must separate number and unit. | NULL | [SELECT quantity_parse_checked('12.5 kg/m3')] |
| unit_compatible | scalar | Check dimensional compatibility of supported UCUM units. Unknown/unsupported units raise errors; this is not quantity-kind validation. | NULL | [SELECT unit_compatible('Pa', 'kg/(m.s2)')] |
| unit_convert | scalar | Convert between compatible UCUM units. Invalid units and incompatible dimensions raise errors. | NULL | [SELECT unit_convert(1, 'kW.h', 'J')] |
| unit_convert_checked | scalar | Convert without aborting on data errors: returns STRUCT(value, status, message). NULL inputs have status missing_input. | NULL | [SELECT unit_convert_checked(1, 'kg', 'm')] |
| unit_convert_delta | scalar | Convert temperature differences without affine offsets. Only temperature dimensions are accepted. | NULL | [SELECT unit_convert_delta(10, 'Cel', '[degF]')] |
| unit_convert_delta_checked | scalar | Checked temperature-difference conversion, returning STRUCT(value, status, message). | NULL | [SELECT unit_convert_delta_checked(10, 'Cel', 'K')] |
| unit_dimension | scalar | Return the UCUM dimension vector as text; does not infer semantic quantity kinds. | NULL | [SELECT unit_dimension('Pa')] |
| unit_parse | scalar | Parse a supported UCUM unit: dimension, base_unit, factor, offset, is_affine. Base units follow UCUM, including grams for mass. | NULL | [SELECT unit_parse('kg/m3')] |
| unit_parse_checked | scalar | Parse without aborting on data errors: returns STRUCT(definition, status, message), with the same definition as unit_parse. NULL input has status missing_input. | NULL | [SELECT unit_parse_checked('Cel/s')] |
| unit_search | table | Case-insensitive substring search of registered unit codes, names and properties. Discovery only, not alias resolution. Empty query lists all atoms; NULL returns no rows. Use ORDER BY for ordering. | NULL | [SELECT unit, name, supported FROM unit_search('pressure') ORDER BY unit] |
| unit_valid | scalar | Whether an expression is supported by this extension. Case-sensitive UCUM; unsupported special units return false. NULL stays NULL. | NULL | [SELECT unit_valid('kg/m3')] |
| units_backend | scalar | Return the pinned engine, standard, and policy versions. | NULL | [SELECT units_backend()] |
| units_catalog | table | List the pinned UCUM atom registry, including unsupported units with diagnostics. Prefixes and compound expressions are not enumerated. Property labels are descriptive, not quantity-kind enforcement. | NULL | [SELECT unit, name, property, supported FROM units_catalog() ORDER BY unit] |
Overloaded Functions
This extension does not add any function overloads.
Added Types
| type_name | type_size | logical_type | type_category | internal |
|---|---|---|---|---|
| STRUCT | 0 | STRUCT | COMPOSITE | true |
Added Settings
| name | description | input_type | scope | aliases | typed_value |
|---|---|---|---|---|---|
| temp_directory | Set the directory to which temporary files are written. | VARCHAR | GLOBAL | [] | post.db.tmp |