REVERSE and INITCAP exist on both sides of the Calcite ⇄ Substrait boundary, yet neither converts:
SELECT REVERSE(l_comment) FROM lineitem
-> IllegalArgumentException: Unable to convert call REVERSE(varchar<44>?).
SELECT INITCAP(l_comment) FROM lineitem
-> IllegalArgumentException: Unable to convert call INITCAP(varchar<44>?).
Both are declared in functions_string.yaml (spec v0.102.0) with character implementations, and both have a Calcite operator — SqlLibraryOperators.REVERSE and SqlStdOperatorTable.INITCAP. What is missing is the entry that joins them: FunctionConverter builds its signatures map exclusively from the FunctionMappings sig list, with no fall-back that matches an operator to a same-named Substrait function, so an operator absent from that table simply has no FunctionFinder and every call to it fails.
AutomaticDynamicFunctionMappingConverterProvider does not cover this. It synthesises Calcite operators for unmapped Substrait functions, which is the Substrait → Calcite direction; a real Calcite operator going the other way still needs a finder, and both queries above fail identically under it.
The fix is two entries:
s(SqlLibraryOperators.REVERSE, "reverse"),
s(SqlStdOperatorTable.INITCAP, "initcap"),
Passing exactly those to ScalarFunctionConverter as additionalSignatures makes both queries convert, so nothing beyond the mapping is missing — the yaml signatures already match a varchar argument.
Two notes for whoever picks this up. 42 of the 126 scalar function names have no FunctionFinder, so this is a sample of a wider gap rather than the whole of it; reverse and initcap are called out because both were confirmed to have a Calcite counterpart whose signature already lines up, which is not true of every name on that list. And if you take an inventory yourself, trim/ltrim/rtrim will look unbound when they are not: all three map onto the single Calcite TRIM operator and signatures is keyed by operator, so two of the three are overwritten — inert here, because TrimFunctionMapper handles TRIM ahead of the finder path.
#1012 would restructure this mapping wholesale; these two entries are worth adding independently of it. #781 is the earlier instance of the same shape, for ANY_VALUE.
Found while reviewing #1169. Checked on main @ 85c03c7.
REVERSEandINITCAPexist on both sides of the Calcite ⇄ Substrait boundary, yet neither converts:Both are declared in
functions_string.yaml(spec v0.102.0) with character implementations, and both have a Calcite operator —SqlLibraryOperators.REVERSEandSqlStdOperatorTable.INITCAP. What is missing is the entry that joins them:FunctionConverterbuilds itssignaturesmap exclusively from theFunctionMappingssig list, with no fall-back that matches an operator to a same-named Substrait function, so an operator absent from that table simply has noFunctionFinderand every call to it fails.AutomaticDynamicFunctionMappingConverterProviderdoes not cover this. It synthesises Calcite operators for unmapped Substrait functions, which is the Substrait → Calcite direction; a real Calcite operator going the other way still needs a finder, and both queries above fail identically under it.The fix is two entries:
Passing exactly those to
ScalarFunctionConverterasadditionalSignaturesmakes both queries convert, so nothing beyond the mapping is missing — the yaml signatures already match avarcharargument.Two notes for whoever picks this up. 42 of the 126 scalar function names have no
FunctionFinder, so this is a sample of a wider gap rather than the whole of it;reverseandinitcapare called out because both were confirmed to have a Calcite counterpart whose signature already lines up, which is not true of every name on that list. And if you take an inventory yourself,trim/ltrim/rtrimwill look unbound when they are not: all three map onto the single CalciteTRIMoperator andsignaturesis keyed by operator, so two of the three are overwritten — inert here, becauseTrimFunctionMapperhandlesTRIMahead of the finder path.#1012 would restructure this mapping wholesale; these two entries are worth adding independently of it. #781 is the earlier instance of the same shape, for
ANY_VALUE.Found while reviewing #1169. Checked on
main@ 85c03c7.