FunctionConverter builds its signatures map exclusively from the FunctionMappings sig lists, keyed on SqlOperator identity, with no fall-back matching an operator to a same-named Substrait function. A Substrait scalar function with no entry therefore has no FunctionFinder, and every Calcite call to it fails with Unable to convert call X(...) at runtime. Nothing surfaces the gap earlier than that: FunctionConverter logs No binding for function: {} at DEBUG for the extension side, and a Sig whose name matches no loaded function is dropped from matcherMap with no log at all.
Roughly 38 of the 126 scalar function names currently have no finder. Most are harmless — Calcite has no operator for swapcase, title, capitalize, string_split, so there is nothing to map. The interesting subset is the names where a real Calcite operator does exist and already resolves in the validator, so a query parses and then dies at conversion: currently around nine, including REPEAT, OCTET_LENGTH, BIT_LENGTH, CARDINALITY, LOG1P, CONCAT_WS, REGEXP_REPLACE, IS_NAN and NULLIF.
That subset is mechanically detectable — enumerate getUnmappedFunctions(extensions.scalarFunctions(), SCALAR_SIGS), look each name up in the provider's operator table, and compare against a checked-in expected list. A test like that turns each new occurrence into a build failure instead of a bug report, and would have found #781, #1222 and the two entries added in #1251 in one pass.
Two things worth folding into the same test while it is being written:
- Nothing validates the other direction either — that a
Sig's Substrait name resolves to a loaded extension function. s(SqlStdOperatorTable.BETWEEN) derives the name "between asymmetric", which matches no function and is silently inert; it is the only dead entry across the three sig lists today. A typo such as "init_cap" would compile and pass spotless, PMD and javadoc, and surface only as a runtime conversion failure.
- Adding a bare
Sig is not automatically safe, so the detector should be an inventory rather than an auto-fix. Probing the nine names above with bare sigs, five convert correctly, four fail on operand shape — and regexp_replace silently bound a 3-operand Calcite call to regexp_replace:str_str_str_i64_i64, i.e. produced a wrong plan instead of an error. That is also the argument against a generic name-matching fall-back in FunctionConverter.
#1012 restructures this mapping wholesale, and its testing strategy lists reverse-N:1, registration-conflict and ArgAdapter invertibility checks but no unmapped-function inventory. Filing this separately so the baseline exists either way.
Found while reviewing #1251.
FunctionConverterbuilds itssignaturesmap exclusively from theFunctionMappingssig lists, keyed onSqlOperatoridentity, with no fall-back matching an operator to a same-named Substrait function. A Substrait scalar function with no entry therefore has noFunctionFinder, and every Calcite call to it fails withUnable to convert call X(...)at runtime. Nothing surfaces the gap earlier than that:FunctionConverterlogsNo binding for function: {}at DEBUG for the extension side, and aSigwhose name matches no loaded function is dropped frommatcherMapwith no log at all.Roughly 38 of the 126 scalar function names currently have no finder. Most are harmless — Calcite has no operator for
swapcase,title,capitalize,string_split, so there is nothing to map. The interesting subset is the names where a real Calcite operator does exist and already resolves in the validator, so a query parses and then dies at conversion: currently around nine, includingREPEAT,OCTET_LENGTH,BIT_LENGTH,CARDINALITY,LOG1P,CONCAT_WS,REGEXP_REPLACE,IS_NANandNULLIF.That subset is mechanically detectable — enumerate
getUnmappedFunctions(extensions.scalarFunctions(), SCALAR_SIGS), look each name up in the provider's operator table, and compare against a checked-in expected list. A test like that turns each new occurrence into a build failure instead of a bug report, and would have found #781, #1222 and the two entries added in #1251 in one pass.Two things worth folding into the same test while it is being written:
Sig's Substrait name resolves to a loaded extension function.s(SqlStdOperatorTable.BETWEEN)derives the name"between asymmetric", which matches no function and is silently inert; it is the only dead entry across the three sig lists today. A typo such as"init_cap"would compile and pass spotless, PMD and javadoc, and surface only as a runtime conversion failure.Sigis not automatically safe, so the detector should be an inventory rather than an auto-fix. Probing the nine names above with bare sigs, five convert correctly, four fail on operand shape — andregexp_replacesilently bound a 3-operand Calcite call toregexp_replace:str_str_str_i64_i64, i.e. produced a wrong plan instead of an error. That is also the argument against a generic name-matching fall-back inFunctionConverter.#1012 restructures this mapping wholesale, and its testing strategy lists reverse-N:1, registration-conflict and
ArgAdapterinvertibility checks but no unmapped-function inventory. Filing this separately so the baseline exists either way.Found while reviewing #1251.