fix: preserve all function revisions through SQL history (#4786)

`list_functions()` promises every published immutable revision. Request
`SHOW FUNCTIONS HISTORY` so the SQL server's latest-only default does
not hide older revisions, and preserve the server's numeric revision
ordering when constructing page cursors (`1`, `2`, `10`).

```python
[(fn.name, fn.version) for fn in db.list_functions(page_limit=2)]
# [("embed", "1"), ("embed", "2"), ("embed", "10")]
```

```sql
SHOW FUNCTIONS; -- latest visible revision per name
SHOW FUNCTIONS HISTORY WITH (limit = 3, include_definition = true);
SHOW FUNCTIONS HISTORY WITH (after_name = 'embed', after_version = '2', limit = 3);
```

Each listing page uses the existing SQL query and polling transport; the
continuation token stores the last returned name/revision and remains
bound to its database and namespace. Function mutations keep their
query-backed job handles: `Job.id` is the query's ID and `job_type` is
`query`, so waiting observes that same SQL execution. No registry job or
second query ID is added.

Update the SQL and Python documentation for exact-revision drops:
sibling revisions and grants survive, and only the last visible
revision's removal releases the name and schedules object cleanup.
Extend the existing Flight SQL regression to paginate revisions `1`,
`2`, and `10` and verify the explicit history statement. Formatting and
static Python checks pass; local builds and tests were intentionally not
run.
This commit is contained in:
Jack Ye
2026-11-02 01:15:39 +08:00
committed by GitHub
parent cbc24fa84f
commit eeb244fa57
6 changed files with 92 additions and 52 deletions
+30 -16
View File
@@ -1018,7 +1018,9 @@ class DBConnection(EnforceOverrides):
"""List every published immutable Function version in a namespace.
Functions in child namespaces are not included. Results are ordered by
Function name then version. LanceDB Embedded connections raise
Function name then numeric version. Remote connections use
``SHOW FUNCTIONS HISTORY`` to include every revision.
LanceDB Embedded connections raise
``NotImplementedError``.
Examples
@@ -1044,13 +1046,15 @@ class DBConnection(EnforceOverrides):
version: str,
namespace_path: Optional[List[str]] = None,
) -> bool:
"""Drop a Function name and the object it was bound to.
"""Drop one published Function revision, preserving its siblings.
The requested version must exist in the currently named object. Returns
True when the catalog binding was removed and False when it was absent.
Physical cleanup continues in the background; use
:meth:`drop_function_async` to access the query job. Local connections
raise NotImplementedError.
Returns True when the revision was removed and False for a repeated drop
or a missing name. A revision never published under an existing name is
an error. Dropping the last visible revision releases the name and
schedules physical cleanup in the background. Use
:meth:`drop_function_async` to
access the query job, whose completion confirms catalog removal of the
revision. Local connections raise NotImplementedError.
"""
raise NotImplementedError(
"Function catalog operations are not supported for this connection type"
@@ -1063,11 +1067,13 @@ class DBConnection(EnforceOverrides):
version: str,
namespace_path: Optional[List[str]] = None,
) -> Tuple[bool, Job]:
"""Drop a Function binding and return its SQL query job.
"""Drop one Function revision and return its SQL query job.
The boolean reports catalog removal. The job has type ``query`` and its
ID is the SQL query UUID. Repeated waits confirm that completion;
physical cleanup continues in the background. LanceDB Embedded
The boolean reports removal of the requested revision from the catalog;
sibling revisions and their grants remain available. The job has type
``query`` and its ID is the SQL query UUID. Repeated waits confirm that
revision's removal. Only the last visible revision's drop releases the
name and schedules background object cleanup. LanceDB Embedded
connections raise NotImplementedError.
"""
raise NotImplementedError(
@@ -3515,7 +3521,13 @@ class AsyncConnection(object):
version: str,
namespace_path: Optional[List[str]] = None,
) -> bool:
"""Drop a Function name and the object it was bound to."""
"""Drop one published Function revision, preserving its siblings.
Returns True when the requested revision was removed and False for a
repeated drop or a missing name. A revision never published under an
existing name is an error. Only the last visible revision's removal
releases the name and schedules background object cleanup.
"""
return await self._inner.drop_function(name, version, namespace_path)
async def drop_function_async(
@@ -3525,11 +3537,13 @@ class AsyncConnection(object):
version: str,
namespace_path: Optional[List[str]] = None,
) -> Tuple[bool, AsyncJob]:
"""Drop a Function binding and return its SQL query job.
"""Drop one Function revision and return its SQL query job.
The boolean reports catalog removal. The job has type ``query`` and its
ID is the SQL query UUID. Repeated waits confirm that completion;
physical cleanup continues in the background.
The boolean reports removal of the requested revision from the catalog;
sibling revisions and their grants remain available. The job has type
``query`` and its ID is the SQL query UUID. Repeated waits confirm that
revision's removal. Only the last visible revision's drop releases the
name and schedules background object cleanup.
"""
dropped, job = await self._inner.drop_function_async(
name, version, namespace_path