Carry, per function, the guard under which its answer is absent - #131
Merged
estebanzimanyi merged 1 commit intoSep 3, 2026
Merged
Conversation
A C return type says what a value LOOKS like and never whether there is one. `bool tbool_value_at_timestamptz(..., bool *value)` answers a value and a flag; `Temporal *temporal_at_timestamptz(...)` answers a pointer that may be NULL; and neither signature separates "no answer here" from "the answer is false". The catalog states nullability for PARAMETERS -- `shape.nullable`, from the Doxygen `@param ... may be NULL` -- and states nothing about the RESULT, so each binding invents a convention for absence: a nullable in MEOS.NET, a `None` in PyMEOS-CFFI, a zero value and a dereference in the two that carry neither. The PostgreSQL wrapper already states it. Each wrapper guards `PG_RETURN_NULL()` with the condition under which the answer is absent, and that guard is a token: `if (! result)` for a null pointer, `if (! found)` for an out-parameter that reports absence itself, `if (result == DBL_MAX)` for the distance sentinel, `if (result < 0)` for a three-valued predicate. This reads that guard and attaches it as `shape.nullableResult`, over the `@csqlfn` chain `parser.sqlfn` already builds, so no new join and no new tag. MEASURED against MobilityDB 4d3de5fc0e: 1038 wrappers carry an absence guard, in the proportions the wrappers themselves state -- 275 `if (! result)`, 67 the distance sentinel, 61 the three-valued form, 11 `if (! found)`. A THIRD OF THE TREE DELEGATES, AND READING ONLY THE WRAPPER INVERTS THOSE. `Temporal_at_timestamptz` is one line, `return Temporal_restrict_timestamptz(fcinfo, REST_AT);`, and the PG_RETURN_NULL sits in that shared helper: 961 of 2894 wrapper bodies take that shape. Following the helper the body names takes the count from 529 to 1038 and, more to the point, turns the whole restriction family from "always answers" into what it is. The walk is bounded and cycle-safe. `PG_ARGISNULL` guards are excluded: those propagate a null ARGUMENT, which `shape.nullable` already carries, and counting them would mark a function absence-capable because its caller may pass nothing. tests/test_nullresult.py covers the guard forms, the delegation hop, a delegation cycle, the argument-null exclusion, and that a wrapper without a guard and a function without a wrapper are left without the field rather than given a false one. The suite goes 307 to 314 and the floor with it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A C return type says what a value LOOKS like and never whether there is one.
bool tbool_value_at_timestamptz(..., bool *value)answers a value and a flag;Temporal *temporal_at_timestamptz(...)answers a pointer that may be NULL; andneither signature separates "no answer here" from "the answer is false". The
catalog states nullability for PARAMETERS --
shape.nullable, from the Doxygen@param ... may be NULL-- and states nothing about the RESULT, so each bindinginvents a convention for absence: a nullable in MEOS.NET, a
NoneinPyMEOS-CFFI, a zero value and a dereference in the two that carry neither.
The PostgreSQL wrapper already states it. Each wrapper guards
PG_RETURN_NULL()with the condition under which the answer is absent, and that guard is a token:
if (! result)for a null pointer,if (! found)for an out-parameter thatreports absence itself,
if (result == DBL_MAX)for the distance sentinel,if (result < 0)for a three-valued predicate. This reads that guard andattaches it as
shape.nullableResult, over the@csqlfnchainparser.sqlfnalready builds, so no new join and no new tag.
MEASURED against MobilityDB 4d3de5fc0e: 1038 wrappers carry an absence guard, in
the proportions the wrappers themselves state -- 275
if (! result), 67 thedistance sentinel, 61 the three-valued form, 11
if (! found).A THIRD OF THE TREE DELEGATES, AND READING ONLY THE WRAPPER INVERTS THOSE.
Temporal_at_timestamptzis one line,return Temporal_restrict_timestamptz(fcinfo, REST_AT);, and the PG_RETURN_NULL sits inthat shared helper: 961 of 2894 wrapper bodies take that shape. Following the
helper the body names takes the count from 529 to 1038 and, more to the point,
turns the whole restriction family from "always answers" into what it is. The
walk is bounded and cycle-safe.
PG_ARGISNULLguards are excluded: those propagate a null ARGUMENT, whichshape.nullablealready carries, and counting them would mark a functionabsence-capable because its caller may pass nothing.
tests/test_nullresult.py covers the guard forms, the delegation hop, a
delegation cycle, the argument-null exclusion, and that a wrapper without a
guard and a function without a wrapper are left without the field rather than
given a false one. The suite goes 307 to 314 and the floor with it.