Skip to content

Commit df6074a

Browse files
authored
feat(datafusion): auto-register built-in table functions on catalog registration (#324)
1 parent 9619f79 commit df6074a

4 files changed

Lines changed: 41 additions & 2 deletions

File tree

bindings/python/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ arrow = { workspace = true, features = ["pyarrow"] }
3131
datafusion = { workspace = true }
3232
datafusion-ffi = { workspace = true }
3333
paimon = { path = "../../crates/paimon", features = ["storage-all"] }
34-
paimon-datafusion = { path = "../../crates/integrations/datafusion" }
34+
paimon-datafusion = { path = "../../crates/integrations/datafusion", features = ["fulltext"] }
3535
pyo3 = { version = "0.28", features = ["abi3-py310"] }
3636
tokio = { workspace = true }

bindings/python/tests/test_datafusion.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,20 @@ def test_register_batch_invalid_catalog():
177177
assert False, "Expected an error for unknown catalog"
178178
except Exception as e:
179179
assert "unknown_catalog" in str(e).lower() or "not a paimon" in str(e).lower() or "unknown" in str(e).lower()
180+
181+
182+
def test_table_functions_registered_with_catalog():
183+
"""register_catalog auto-registers vector_search / full_text_search as
184+
UDTFs. Calling one with the wrong argument count surfaces the function's
185+
own validation error, which proves it is registered — an unregistered
186+
name would instead fail with 'table function not found'."""
187+
with tempfile.TemporaryDirectory() as warehouse:
188+
ctx = SQLContext()
189+
ctx.register_catalog("paimon", {"warehouse": warehouse})
190+
191+
for fn in ("vector_search", "full_text_search"):
192+
try:
193+
ctx.sql(f"SELECT * FROM {fn}('only_one_arg')")
194+
assert False, f"expected {fn} to reject a single argument"
195+
except Exception as e:
196+
assert "requires 4 arguments" in str(e), str(e)

crates/integrations/datafusion/src/sql_context.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ impl SQLContext {
136136
self.dynamic_options.clone(),
137137
)),
138138
);
139+
register_table_functions(&self.ctx, &catalog, default_db);
139140
self.catalogs.insert(catalog_name.clone(), catalog);
140141
if is_first {
141142
self.set_current_catalog(catalog_name).await?;
@@ -2302,6 +2303,19 @@ fn ok_result(ctx: &SessionContext) -> DFResult<DataFrame> {
23022303
Ok(df)
23032304
}
23042305

2306+
/// Registers the built-in table-valued functions against `catalog` so they can
2307+
/// be used in SQL without any extra setup call. Called for every catalog
2308+
/// registered on the context; add new built-in table functions here.
2309+
fn register_table_functions(
2310+
ctx: &SessionContext,
2311+
catalog: &Arc<dyn Catalog>,
2312+
default_database: &str,
2313+
) {
2314+
crate::vector_search::register_vector_search(ctx, Arc::clone(catalog), default_database);
2315+
#[cfg(feature = "fulltext")]
2316+
crate::full_text_search::register_full_text_search(ctx, Arc::clone(catalog), default_database);
2317+
}
2318+
23052319
#[cfg(test)]
23062320
mod tests {
23072321
use super::*;

docs/src/sql.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ async fn example() -> Result<(), Box<dyn std::error::Error>> {
5353
}
5454
```
5555

56-
`SQLContext::new` creates a session context with the Paimon relation planner pre-registered. Use `register_catalog` to add one or more Paimon catalogs. It also manages session-scoped dynamic options internally for `SET`/`RESET` support.
56+
`SQLContext::new` creates a session context with the Paimon relation planner pre-registered. Use `register_catalog` to add one or more Paimon catalogs; registering a catalog also registers the built-in table-valued functions (`vector_search`, `full_text_search`) against it. It also manages session-scoped dynamic options internally for `SET`/`RESET` support.
5757

5858
## Data Types
5959

@@ -445,6 +445,10 @@ Paimon supports approximate nearest neighbor (ANN) vector search via the Lumina
445445

446446
### Registration
447447

448+
When you use a `SQLContext`, `vector_search` is registered automatically for every catalog you register — no extra setup is needed.
449+
450+
With a raw DataFusion `SessionContext`, register it explicitly:
451+
448452
```rust
449453
use paimon_datafusion::register_vector_search;
450454

@@ -510,6 +514,10 @@ paimon-datafusion = { version = "0.1.0", features = ["fulltext"] }
510514

511515
### Registration
512516

517+
When you use a `SQLContext`, `full_text_search` is registered automatically for every catalog you register (when the `fulltext` feature is enabled) — no extra setup is needed.
518+
519+
With a raw DataFusion `SessionContext`, register it explicitly:
520+
513521
```rust
514522
use paimon_datafusion::register_full_text_search;
515523

0 commit comments

Comments
 (0)