Repository navigation
Closed
Labels
area/rangesRange unions, variants and the shape enginesRange unions, variants and the shape enginesenhancementNew feature or requestNew feature or requestpackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
Milestone
Description
Problem
Clamp(value) on a range runs in memory only (docs/efcore.md#what-runs-where). The obstacle the docs gave until #402 ("a CASE per shape") is overstated: GREATEST and LEAST skip NULL, so an unbounded side needs no branch.
Change
Translate Clamp on Int32Range, Int64Range and DecimalRange, matching RangeExtensions.Clamp:
- Memory's rule:
nullfor the empty range; the value itself inside; otherwise the finite bound it falls outside of, whatever that bound's inclusiveness (on a continuous type an exclusive bound is returned although the range doesn't contain it). An unbounded side never constrains. The value is first passed throughNormalizeElement. - SQL:
CASE WHEN isempty(x) THEN NULL ELSE LEAST(GREATEST(v, lower(x)), <upper>) END.<upper>isupper(x)fornumrange. Forint4range/int8rangeit isupper(x) - 1, because PostgreSQL canonicalizes to an exclusive upper bound where memory'sEndis inclusive.upper(x) - 1can't overflow, since the canonical exclusive bound is at least one above a real value. - Measured on PostgreSQL 16:
LEAST(GREATEST(15, lower('(,10]')), upper('(,10]') - 1)is10. - To check first:
DecimalRange'sNormalizeElement(scale) against whatnumericreturns, sinceSamecompares the loadeddecimal. - Declared nullability: NULL for a NULL range or a NULL value (rule (c)).
Done when
Every condition on the 10.3.0 epic's parity list holds for the three types, against memory over the loaded rows on a live server. translation-support.json classifies them server (the other range types stay client with their reason), and the docs list the three under "Runs as SQL". main first, then the cherry-pick.
Metadata
Metadata
Assignees
Labels
area/rangesRange unions, variants and the shape enginesRange unions, variants and the shape enginesenhancementNew feature or requestNew feature or requestpackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
Activity
CaffeinatedCoder commentedon Oct 25, 2026
PR #440 on
main. Measured on PostgreSQL 16 before writing it, and the issue's "to check first" item is resolved:DecimalRangekeeps the defaultNormalizeElement(the identity), so memory sees the value as given.numericreturns the stored scale (2.500), whichdecimalequality ignores.A NULL range or value needs its own test, because
GREATEST/LEASTskip NULL and would otherwise answer with the other operand.ClampParityTestscovers #408's parity list for these three types. The composition sweeps run overDateRange, whoseClampstays in memory. The 10.x cherry-pick follows the merge.Merge pull request #440 from CaffeinatedCoder/feat/406-translate-clamp
CaffeinatedCoder commentedon Oct 25, 2026
Runs as SQL on
mainsince PR #440 (84dc121). Therelease/10.xcherry-pick is tracked separately (port issue under #408).feat: translate Clamp on Int32Range, Int64Range and DecimalRange (#406)
Merge pull request #442 from CaffeinatedCoder/feat/441-translate-clam…