fix: refuse a remote table as a materialized view before any request

The connection-level entry points hold a local-only boundary, but
from_table does not, and that is the entry both bindings use to refresh.
A remote table therefore reached a describe request and came back as a
plain table rather than as unsupported, so the caller paid a round trip
for a misleading error.

Check the boundary before the schema read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Wyatt Alt
2026-08-16 13:04:46 -07:00
co-authored by Claude Fable 5
parent 1d8c2a0a6f
commit dbe93edb12
2 changed files with 21 additions and 0 deletions
+7
View File
@@ -656,6 +656,13 @@ impl MaterializedView {
/// [`Error::NotSupported`] for a view whose kind this version cannot
/// refresh.
pub async fn from_table(table: Table) -> Result<Self> {
// Same local-only boundary the connection-level entry points hold,
// applied before the schema read so a remote table costs no request.
if table.as_native().is_none() {
return Err(Error::NotSupported {
message: "materialized views are supported only on local databases".into(),
});
}
let schema = table.schema().await?;
match materialized_view_kind(schema.metadata())? {
Some(MaterializedViewKind::Select(definition)) => Ok(Self { table, definition }),
+14
View File
@@ -10156,6 +10156,20 @@ mod tests {
);
}
#[tokio::test]
async fn test_materialized_view_refused_without_a_request() {
// Materialized views are local-only. The table-level entry the
// bindings use must refuse a remote table before reading its schema,
// so the panicking handler is the assertion.
let table = Table::new_with_handler("my_table", |request| -> http::Response<String> {
panic!("unexpected request: {}", request.url().path())
});
let err = crate::MaterializedView::from_table(table)
.await
.unwrap_err();
assert!(matches!(err, Error::NotSupported { .. }), "got {err:?}");
}
#[tokio::test]
async fn test_create_branch_empty_name_rejected_client_side() {
use lance::dataset::refs::Ref;