fix: return errors for unsupported remote alteration types (#4430)

RemoteTable::alter_columns currently unwraps the JsonDataType
conversion. A valid Arrow input that the remote wire format cannot
represent (for example Utf8View, BinaryView, or a struct containing
Utf8View) therefore panics instead of returning an error.

Propagate conversion/serialization failures as Error::InvalidInput,
including the column path. Unsupported inputs are rejected before any
HTTP request; supported alteration payloads are unchanged. This does not
add server support for view types or change server HTTP-error
classification.

Three new native Rust cases reproduce the panic on unchanged production
and return InvalidInput with the fix. The existing supported-type cases
remain passing.

Validation at head 88184ea, Linux/Rust 1.97.0, locked offline
dependencies:
- cargo test --offline --profile ci --locked -p lancedb
--no-default-features --features remote --lib remote::table::tests::
(269 passed)
- cargo clippy --offline --profile ci --locked -p lancedb
--no-default-features --features remote --lib --tests -- -D warnings
- cargo fmt --all -- --check

Current main merges cleanly; the intervening remote-table change is
unrelated nprobes validation. Live Cloud, rebuilt Python/Node bindings
and full-workspace integration were not tested.

AI-assisted; native regression and before/after results independently
checked.
This commit is contained in:
adenzhou1350
2026-10-23 02:43:07 +08:00
committed by GitHub
parent 4bdc8c3c00
commit e489d0cd7b
+32 -5
View File
@@ -3736,16 +3736,25 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
value["rename"] = serde_json::Value::String(rename.clone());
}
if let Some(data_type) = &alteration.data_type {
let json_data_type = JsonDataType::try_from(data_type).unwrap();
let json_data_type = serde_json::to_value(&json_data_type).unwrap();
value["data_type"] = json_data_type;
let json_data_type =
JsonDataType::try_from(data_type).map_err(|err| Error::InvalidInput {
message: format!(
"Cannot serialize data type for column '{}': {err}",
alteration.path
),
})?;
value["data_type"] = serde_json::to_value(&json_data_type).map_err(|err| {
Error::InvalidInput {
message: format!("Cannot serialize column alteration: {err}"),
}
})?;
}
if let Some(nullable) = &alteration.nullable {
value["nullable"] = serde_json::Value::Bool(*nullable);
}
value
Ok(value)
})
.collect::<Vec<_>>();
.collect::<Result<Vec<_>>>()?;
let mut body = serde_json::json!({ "alterations": body });
self.apply_branch_body(&mut body);
let request = self
@@ -5067,6 +5076,24 @@ mod tests {
}
}
#[rstest]
#[case::string_view(DataType::Utf8View)]
#[case::binary_view(DataType::BinaryView)]
#[case::nested_view(DataType::Struct(vec![Field::new("value", DataType::Utf8View, true)].into()))]
#[tokio::test]
async fn test_alter_columns_unsupported_type(#[case] data_type: DataType) {
let table = Table::new_with_handler("my_table", |_| -> http::Response<String> {
panic!("an unserializable alteration must not reach the server")
});
let err = table
.alter_columns(&[ColumnAlteration::new("value".into()).cast_to(data_type)])
.await
.unwrap_err();
assert!(matches!(err, Error::InvalidInput { .. }), "got {err:?}");
assert!(err.to_string().contains("value"));
assert!(err.to_string().contains("Unsupported type"));
}
#[rstest]
#[case(true)]
#[case(false)]