stac-rs icon indicating copy to clipboard operation
stac-rs copied to clipboard

Use DuckDB for in-memory server backend

Open gadomski opened this issue 9 months ago • 2 comments

gadomski avatar Feb 21 '25 21:02 gadomski

Let's check out using arrow virtual tables: https://github.com/duckdb/duckdb-rs/issues/286,

gadomski avatar Jun 04 '25 21:06 gadomski

Whelp, I tried, but it looks like it chokes on the spatial column:

Big ol' diff
diff --git a/crates/duckdb/src/client.rs b/crates/duckdb/src/client.rs
index 9c8b383..9042d0e 100644
--- a/crates/duckdb/src/client.rs
+++ b/crates/duckdb/src/client.rs
@@ -2,10 +2,17 @@ use crate::{Error, Extension, Result};
 use arrow_array::{RecordBatch, RecordBatchIterator};
 use chrono::DateTime;
 use cql2::{Expr, ToDuckSQL};
-use duckdb::{Connection, types::Value};
+use duckdb::{
+    Connection,
+    types::Value,
+    vtab::{arrow::ArrowVTab, arrow_recordbatch_to_query_params},
+};
 use geo::BoundingRect;
 use geojson::Geometry;
-use stac::{Collection, SpatialExtent, TemporalExtent, geoarrow::DATETIME_COLUMNS};
+use stac::{
+    Collection, SpatialExtent, TemporalExtent,
+    geoarrow::{DATETIME_COLUMNS, Table},
+};
 use stac_api::{Direction, Search};
 use std::ops::{Deref, DerefMut};
 
@@ -18,6 +25,8 @@ pub const DEFAULT_CONVERT_WKB: bool = true;
 const DEFAULT_COLLECTION_DESCRIPTION: &str =
     "Auto-generated collection from stac-geoparquet extents";
 
+const ARROW_FROM: &str = "arrow(?, ?)";
+
 /// A client for making DuckDB requests for STAC objects.
 #[derive(Debug)]
 pub struct Client {
@@ -169,7 +178,17 @@ impl Client {
     /// let item_collection = client.search("data/100-sentinel-2-items.parquet", Default::default()).unwrap();
     /// ```
     pub fn search(&self, href: &str, search: Search) -> Result<stac_api::ItemCollection> {
-        let record_batches = self.search_to_arrow(href, search)?;
+        let from = self.format_parquet_href(href);
+        self.search_from(&from, &[], search)
+    }
+
+    fn search_from(
+        &self,
+        from: &str,
+        params: &[Value],
+        search: Search,
+    ) -> Result<stac_api::ItemCollection> {
+        let record_batches = self.search_to_arrow_from(from, params, search)?;
         if record_batches.is_empty() {
             Ok(Default::default())
         } else {
@@ -181,6 +200,32 @@ impl Client {
         }
     }
 
+    /// Searches an arrow table.
+    pub fn search_table(&self, table: Table, search: Search) -> Result<stac_api::ItemCollection> {
+        self.connection
+            .register_table_function::<ArrowVTab>("arrow")?;
+        let (record_batches, _) = table.into_inner();
+        if record_batches.len() > 1 {
+            unimplemented!("cannot limit/offset through multiple record batches (yet)")
+        }
+        let mut items = Vec::with_capacity(
+            record_batches
+                .iter()
+                .map(|record_batch| record_batch.num_rows())
+                .sum(),
+        );
+        for record_batch in record_batches {
+            let params = arrow_recordbatch_to_query_params(record_batch);
+            let item_collection = self.search_from(
+                ARROW_FROM,
+                &[params[0].into(), params[1].into()],
+                search.clone(),
+            )?;
+            items.extend(item_collection.items);
+        }
+        Ok(items.into())
+    }
+
     /// Searches to an iterator of record batches.
     ///
     /// # Examples
@@ -192,6 +237,16 @@ impl Client {
     /// let record_batches = client.search_to_arrow("data/100-sentinel-2-items.parquet", Default::default()).unwrap();
     /// ```
     pub fn search_to_arrow(&self, href: &str, search: Search) -> Result<Vec<RecordBatch>> {
+        let from = self.format_parquet_href(href);
+        self.search_to_arrow_from(&from, &[], search)
+    }
+
+    fn search_to_arrow_from(
+        &self,
+        from: &str,
+        params: &[Value],
+        search: Search,
+    ) -> Result<Vec<RecordBatch>> {
         // TODO can we return an iterator?
 
         // Note that we pull out some fields early so we can avoid closing some search strings below.
@@ -203,13 +258,15 @@ impl Client {
         // Check which columns we'll be selecting
         let mut statement = self.prepare(&format!(
             "SELECT column_name FROM (DESCRIBE SELECT * from {})",
-            self.format_parquet_href(href)
+            from
         ))?;
         let mut has_start_datetime = false;
         let mut has_end_datetime = false;
         let mut column_names = Vec::new();
         let mut columns = Vec::new();
-        for row in statement.query_map([], |row| row.get::<_, String>(0))? {
+        for row in statement.query_map(duckdb::params_from_iter(params), |row| {
+            row.get::<_, String>(0)
+        })? {
             let column = row?;
             if column == "start_datetime" {
                 has_start_datetime = true;
@@ -259,7 +316,7 @@ impl Client {
 
         // Build wheres and params
         let mut wheres = Vec::new();
-        let mut params = Vec::new();
+        let mut additional_params = Vec::new();
         if !search.ids.is_empty() {
             wheres.push(format!(
                 "id IN ({})",
@@ -268,11 +325,11 @@ impl Client {
                     .collect::<Vec<_>>()
                     .join(",")
             ));
-            params.extend(search.ids.into_iter().map(Value::Text));
+            additional_params.extend(search.ids.into_iter().map(Value::Text));
         }
         if let Some(intersects) = search.intersects {
             wheres.push("ST_Intersects(geometry, ST_GeomFromGeoJSON(?))".to_string());
-            params.push(Value::Text(intersects.to_string()));
+            additional_params.push(Value::Text(intersects.to_string()));
         }
         if !search.collections.is_empty() {
             wheres.push(format!(
@@ -282,11 +339,11 @@ impl Client {
                     .collect::<Vec<_>>()
                     .join(",")
             ));
-            params.extend(search.collections.into_iter().map(Value::Text));
+            additional_params.extend(search.collections.into_iter().map(Value::Text));
         }
         if let Some(bbox) = search.items.bbox {
             wheres.push("ST_Intersects(geometry, ST_GeomFromGeoJSON(?))".to_string());
-            params.push(Value::Text(bbox.to_geometry().to_string()));
+            additional_params.push(Value::Text(bbox.to_geometry().to_string()));
         }
         if let Some(datetime) = search.items.datetime {
             let interval = stac::datetime::parse(&datetime)?;
@@ -299,7 +356,7 @@ impl Client {
                         "datetime"
                     }
                 ));
-                params.push(Value::Text(start.to_rfc3339()));
+                additional_params.push(Value::Text(start.to_rfc3339()));
             }
             if let Some(end) = interval.1 {
                 wheres.push(format!(
@@ -310,7 +367,7 @@ impl Client {
                         "datetime"
                     }
                 ));
-                params.push(Value::Text(end.to_rfc3339()));
+                additional_params.push(Value::Text(end.to_rfc3339()));
             }
         }
         if let Some(filter) = search.items.filter {
@@ -337,16 +394,13 @@ impl Client {
             suffix.push_str(&format!(" OFFSET {}", offset));
         }
 
-        let sql = format!(
-            "SELECT {} FROM {}{}",
-            columns.join(","),
-            self.format_parquet_href(href),
-            suffix,
-        );
+        let sql = format!("SELECT {} FROM {}{}", columns.join(","), from, suffix,);
         log::debug!("duckdb sql: {}", sql);
         let mut statement = self.prepare(&sql)?;
         statement
-            .query_arrow(duckdb::params_from_iter(params))?
+            .query_arrow(duckdb::params_from_iter(
+                params.iter().chain(additional_params.iter()),
+            ))?
             .map(|record_batch| {
                 let record_batch = if self.convert_wkb {
                     stac::geoarrow::with_native_geometry(record_batch, "geometry")?
@@ -423,7 +477,7 @@ mod tests {
     use duckdb::Connection;
     use geo::Geometry;
     use rstest::{fixture, rstest};
-    use stac::Bbox;
+    use stac::{Bbox, ItemCollection, geoarrow::TableBuilder};
     use stac_api::{Search, Sortby};
     use stac_validate::Validate;
 
@@ -672,4 +726,18 @@ mod tests {
             .unwrap();
         assert_eq!(item_collection.items.len(), 100);
     }
+
+    #[rstest]
+    fn search_table(client: Client) {
+        let item_collection: ItemCollection =
+            stac_io::read("data/100-sentinel-2-items.parquet").unwrap();
+        let table = TableBuilder {
+            item_collection,
+            drop_invalid_attributes: false,
+        }
+        .build()
+        .unwrap();
+        let item_collection = client.search_table(table, Default::default()).unwrap();
+        assert_eq!(item_collection.items.len(), 100);
+    }
 }

gives

Big ol' error
---- client::tests::search_table stdout ----

thread 'client::tests::search_table' panicked at crates/duckdb/src/client.rs:740:78:
called `Result::unwrap()` on an `Err` value: DuckDB(DuckDBFailure(Error { code: Unknown, extended_code: 1 }, Some("Binder Error: Unsupported data type: Union([(1, Field { name: \"Point\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (2, Field { name: \"LineString\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (3, Field { name: \"Polygon\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (4, Field { name: \"MultiPoint\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (5, Field { name: \"MultiLineString\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (6, Field { name: \"MultiPolygon\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (7, Field { name: \"GeometryCollection\", data_type: List(Field { name: \"geometries\", data_type: Union([(1, Field { name: \"Point\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (2, Field { name: \"LineString\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (3, Field { name: \"Polygon\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (4, Field { name: \"MultiPoint\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (5, Field { name: \"MultiLineString\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (6, Field { name: \"MultiPolygon\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} })], Dense), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (11, Field { name: \"Point Z\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (12, Field { name: \"LineString Z\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (13, Field { name: \"Polygon Z\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (14, Field { name: \"MultiPoint Z\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (15, Field { name: \"MultiLineString Z\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (16, Field { name: \"MultiPolygon Z\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (17, Field { name: \"GeometryCollection Z\", data_type: List(Field { name: \"geometries\", data_type: Union([(11, Field { name: \"Point Z\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (12, Field { name: \"LineString Z\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (13, Field { name: \"Polygon Z\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (14, Field { name: \"MultiPoint Z\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (15, Field { name: \"MultiLineString Z\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (16, Field { name: \"MultiPolygon Z\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} })], Dense), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (21, Field { name: \"Point M\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (22, Field { name: \"LineString M\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (23, Field { name: \"Polygon M\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (24, Field { name: \"MultiPoint M\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (25, Field { name: \"MultiLineString M\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (26, Field { name: \"MultiPolygon M\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (27, Field { name: \"GeometryCollection M\", data_type: List(Field { name: \"geometries\", data_type: Union([(21, Field { name: \"Point M\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (22, Field { name: \"LineString M\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (23, Field { name: \"Polygon M\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (24, Field { name: \"MultiPoint M\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (25, Field { name: \"MultiLineString M\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (26, Field { name: \"MultiPolygon M\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} })], Dense), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (31, Field { name: \"Point ZM\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (32, Field { name: \"LineString ZM\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (33, Field { name: \"Polygon ZM\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (34, Field { name: \"MultiPoint ZM\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (35, Field { name: \"MultiLineString ZM\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (36, Field { name: \"MultiPolygon ZM\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (37, Field { name: \"GeometryCollection ZM\", data_type: List(Field { name: \"geometries\", data_type: Union([(31, Field { name: \"Point ZM\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (32, Field { name: \"LineString ZM\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (33, Field { name: \"Polygon ZM\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (34, Field { name: \"MultiPoint ZM\", data_type: List(Field { name: \"points\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (35, Field { name: \"MultiLineString ZM\", data_type: List(Field { name: \"linestrings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} }), (36, Field { name: \"MultiPolygon ZM\", data_type: List(Field { name: \"polygons\", data_type: List(Field { name: \"rings\", data_type: List(Field { name: \"vertices\", data_type: Struct([Field { name: \"x\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"y\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"z\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"m\", data_type: Float64, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }]), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} })], Dense), nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }), nullable: true, dict_id: 0, dict_is_ordered: false, metadata: {} })], Dense), please file an issue https://github.com/duckdb/duckdb-rs")))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    client::tests::search_table

test result: FAILED. 19 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.41s

gadomski avatar Jun 05 '25 18:06 gadomski