There are two issues I'd like to discuss related to constructing range
types from other values.
1.
The obvious constructor would be: range(1, 10)
But is that [1, 10), (1, 10], (1, 10), or [1, 10]? We need to support
all 4, and it's not obvious how to do that easily. The solution that I
came up with is not particularly clean, but is quite practical:
range(1, 10) -> [1, 10) range__(1, 10) -> (1, 10) range_i(1, 10) -> (1, 10] rangei_(1, 10) -> [1, 10) rangeii(1, 10)
->[1, 10]
The last two letters refer to the lower and upper bounds, respectively.
A "i" means "inclusive" and an "_" means "exclusive". range() is an
alias for rangei_(), because that's the most common representation to
use.
I realize this isn't a clean solution, and better ideas are welcome.
This one actually is quite natural to use I think: short to type and
easy to remember (for me at least ;).
It gets a little stranger for trying to construct unbounded ranges from
other values. Again, there are four possibilities: range_uinfi(5) -> [5, INF) range_uinf_(5) -> (5, INF)
range_linfi(5)-> (-INF, 5] range_linf_(5) -> (-INF, 5)
And again, not exactly clean, but they work.
Constructing a singleton range is easy, fortunately, because only
something like "[5,5]" makes sense, "[5,5)" doesn't. So there's just a
single-argument version of range: range(5) -> [5,5]
2.
The second issue is with the type system. In order for the polymorphic
constructors to work, they need to be able to determine the data types
of their inputs to construct the range. I am using get_fn_expr_argtype()
to accomplish that, but it's not always guaranteed to work.
That was the problem Erik ran into: the "range @> elem" operator was
implicitly constructing a range on the right side based on the type of
the right operand; but was being called in contexts where the types
aren't known (like the selectivity estimator). The fix was easy: get the
type from the range operand (which is actually stored with the range).
But that fix won't work for the constructors above, because there is no
range argument to start from.
So: in what contexts are functions called that get_fn_expr_argtype()
might fail; and are the above constructors at risk for that? Is there a
better way?
Regards,Jeff Davis