Skip to content

Support UDTFs in information_schema.routines / SHOW FUNCTIONS#23438

Merged
zhuqi-lucas merged 2 commits into
apache:mainfrom
zhuqi-lucas:qizhu/show-functions-udtf-upstream
Jul 17, 2026
Merged

Support UDTFs in information_schema.routines / SHOW FUNCTIONS#23438
zhuqi-lucas merged 2 commits into
apache:mainfrom
zhuqi-lucas:qizhu/show-functions-udtf-upstream

Conversation

@zhuqi-lucas

@zhuqi-lucas zhuqi-lucas commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

information_schema.routines and SHOW FUNCTIONS currently enumerate only scalar / aggregate / window UDFs. Table functions (UDTFs) registered via SessionContext::register_udtf are omitted, making them undiscoverable through SQL. Discovery matters because downstream tooling (DataFusion CLI, Massive's atlas SQL surface, dbt-datafusion, etc.) uses these SQL surfaces to list available functions.

What changes are included in this PR?

1. Snapshot table functions into the information_schema provider.

Session::table_functions() cannot exist on the Session trait today: TableFunction lives in datafusion-catalog, which already depends on datafusion-session (both TableProvider::scan and TableFunction take &dyn Session). Adding a trait method returning &HashMap<String, Arc<TableFunction>> would reverse that edge and create a crate-dependency cycle. ScalarUDF / AggregateUDF / WindowUDF don't hit this because they live in datafusion-expr, which sits below datafusion-session.

This is the same underlying constraint as #23348. A follow-up PR will move TableFunction (or hoist the relevant traits) so the builder can be deleted.

For this PR, SessionState.table_functions is snapshotted into InformationSchemaProvider via with_table_functions() at construction. The provider is built per-query, so the snapshot stays fresh.

2. Emit UDTF rows in information_schema.routines only.

make_routines: one row per UDTF with routine_type = "FUNCTION", function_type = "TABLE", data_type = "TABLE".

UDTFs deliberately do NOT appear in information_schema.parameters. A same-named scalar UDF (e.g. generate_series exists as both a scalar UDF in functions-nested and a UDTF in functions-table) would cross-join with a UDTF row keyed only by (name, rid) and produce spurious TABLE-typed variants of every scalar signature in SHOW FUNCTIONS.

3. Rewrite the SHOW FUNCTIONS SQL to UNION UDTFs directly from routines.

The old query joined parameters p (INNER) requiring both IN and OUT rows before joining routines. UDTFs have no IN parameters, so they fell out. The new plan sources scalar / aggregate / window signatures from parameters as before, and UDTFs from a separate UNION branch that reads routines directly (guarded by function_type = TABLE). This avoids the cross-join blowup mentioned above.

Are these changes tested?

Verified locally by registering a UDTF and running SHOW FUNCTIONS:

> SHOW FUNCTIONS LIKE 'stale%'
+---------------+-------------+---------------+
| function_name | return_type | function_type |
| stale_files   | TABLE       | TABLE         |
+---------------+-------------+---------------+

Happy to add sqllogictests in datafusion/sqllogictest/test_files/information_schema.slt if maintainers prefer.

Are there any user-facing changes?

Yes: SHOW FUNCTIONS output now includes table functions. information_schema.routines gains one row per registered UDTF. information_schema.parameters is intentionally unchanged (see rationale in point 2 above). Existing rows are unchanged.

Copilot AI review requested due to automatic review settings July 10, 2026 07:10
@github-actions github-actions Bot added sql SQL Planner core Core DataFusion crate catalog Related to the catalog crate labels Jul 10, 2026
@zhuqi-lucas
zhuqi-lucas force-pushed the qizhu/show-functions-udtf-upstream branch from f297568 to 55cb62d Compare July 10, 2026 07:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends DataFusion’s SQL discovery surfaces to include table functions (UDTFs) in information_schema.routines and SHOW FUNCTIONS, addressing the gap where only scalar/aggregate/window UDFs were listed.

Changes:

  • Snapshot SessionState.table_functions into InformationSchemaProvider so UDTFs can be exposed without introducing crate cycles.
  • Emit information_schema.routines and information_schema.parameters rows for UDTFs (synthetic OUT parameter row with data_type = 'TABLE').
  • Rewrite SHOW FUNCTIONS SQL to start from OUT parameter rows and LEFT JOIN IN parameter rows so functions with no inputs can appear.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
datafusion/sql/src/statement.rs Rewrites SHOW FUNCTIONS to be compatible with functions that lack IN parameters (e.g., UDTFs).
datafusion/core/src/execution/session_state.rs Passes the session’s registered table functions into the per-query InformationSchemaProvider.
datafusion/catalog/src/information_schema.rs Stores table functions in InformationSchemaConfig and emits corresponding routines / parameters rows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2646 to 2649
o.specific_name function_name,
o.data_type return_type,
array_agg(i.parameter_name ORDER BY i.ordinal_position ASC) parameters,
array_agg(i.data_type ORDER BY i.ordinal_position ASC) parameter_types
Comment on lines +320 to +322
// Table functions (UDTFs) don't have scalar signatures; their return
// type is always a table, so emit a single row per UDTF with
// routine_type = "TABLE" and data_type = "TABLE".
Comment thread datafusion/sql/src/statement.rs Outdated
Comment on lines 2634 to 2636
// Note: use LEFT JOIN from OUT rows to IN rows so functions without
// input parameters (notably UDTFs / table functions) still appear.
let query = format!(
@zhuqi-lucas
zhuqi-lucas force-pushed the qizhu/show-functions-udtf-upstream branch from 55cb62d to 3ede8a3 Compare July 10, 2026 07:35
@github-actions github-actions Bot added the sqllogictest SQL Logic Tests (.slt) label Jul 10, 2026
@zhuqi-lucas
zhuqi-lucas force-pushed the qizhu/show-functions-udtf-upstream branch from 3ede8a3 to 129e008 Compare July 10, 2026 07:58
- add table_functions field to InformationSchemaConfig + builder
- emit UDTFs from make_routines (function_type=TABLE, data_type=TABLE)
- emit synthetic OUT parameter for UDTFs so JOIN in SHOW FUNCTIONS resolves
- rewrite SHOW FUNCTIONS SQL as OUT LEFT JOIN IN so args-less UDTFs surface
- wire SessionState.table_functions snapshot into InformationSchemaProvider
@zhuqi-lucas
zhuqi-lucas force-pushed the qizhu/show-functions-udtf-upstream branch from 129e008 to 3fb1e9a Compare July 10, 2026 08:35
@xudong963
xudong963 self-requested a review July 10, 2026 10:30
zhuqi-lucas added a commit to massive-com/datafusion-materialized-views that referenced this pull request Jul 13, 2026
Bumps DataFusion to 6363fbe (Support UDTFs in information_schema.routines /
SHOW FUNCTIONS, apache/datafusion equivalent open as apache/datafusion#23438).
zhuqi-lucas added a commit to massive-com/datafusion-materialized-views that referenced this pull request Jul 13, 2026
Bumps DataFusion to 6363fbe (Support UDTFs in information_schema.routines /
SHOW FUNCTIONS, apache/datafusion equivalent open as apache/datafusion#23438).
zhuqi-lucas added a commit to massive-com/datafusion-materialized-views that referenced this pull request Jul 13, 2026
Bumps DataFusion to 6363fbe (Support UDTFs in information_schema.routines /
SHOW FUNCTIONS, apache/datafusion equivalent open as apache/datafusion#23438).
@zhuqi-lucas
zhuqi-lucas requested a review from alamb July 15, 2026 04:41

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me -- thank you @zhuqi-lucas

#[derive(Clone, Debug)]
struct InformationSchemaConfig {
catalog_list: Arc<dyn CatalogProviderList>,
table_functions: HashMap<String, Arc<TableFunction>>,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we have to treat TableFunctions specially -- the PR descriptio says it is to avoid a crate dependency cycle, but I don't understand why the same thing doesn't apply to Scalar and Aggregate functons

Mabe we just need to move a definition of TableFunction to datafusion-expr 🤔 But maybe that is not possible

@zhuqi-lucas zhuqi-lucas Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @alamb for good catch, refreshed the PR description with the concrete cycle explanation.

TableFunction lives in datafusion-catalog, which already depends on datafusion-session — putting table_functions() on the Session trait reverses that edge. Scalar/Agg live in datafusion-expr (below session), so no cycle there. Same root as #23348 — I'll open a follow-up PR that moves TableFunction down and deletes with_table_functions().

@zhuqi-lucas
zhuqi-lucas added this pull request to the merge queue Jul 17, 2026
@zhuqi-lucas

Copy link
Copy Markdown
Contributor Author

Thank you @alamb and @xudong963 for review, merged to main.

Merged via the queue into apache:main with commit 7ca6e54 Jul 17, 2026
40 checks passed
@zhuqi-lucas
zhuqi-lucas deleted the qizhu/show-functions-udtf-upstream branch July 17, 2026 04:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

catalog Related to the catalog crate core Core DataFusion crate sql SQL Planner sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SHOW FUNCTIONS / information_schema.routines omit table functions (UDTFs)

4 participants