Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions c/sedona-gdal/src/dyn_load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ fn load_all_symbols(lib: &Library, api: &mut SedonaGdalApi) -> Result<(), GdalIn
load_fn!(lib, api, VSIFileFromMemBuffer);
load_fn!(lib, api, VSIFCloseL);
load_fn!(lib, api, VSIUnlink);
load_fn!(lib, api, VSIOpenDir);
load_fn!(lib, api, VSIGetNextDirEntry);
load_fn!(lib, api, VSICloseDir);
load_fn!(lib, api, VSIGetMemFileBuffer);
load_fn!(lib, api, VSIFree);
load_fn!(lib, api, VSIMalloc);
Expand Down
11 changes: 11 additions & 0 deletions c/sedona-gdal/src/gdal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ impl Gdal {
vsi::get_vsi_mem_file_bytes_owned(self.api, file_name)
}

/// Open a VSI directory for iteration.
/// See also [`vsi::open_dir`].
pub fn open_vsi_dir(
&self,
path: &str,
recurse_depth: i32,
options: Option<&crate::cpl::CslStringList>,
) -> Result<crate::vsi::VsiDir> {
crate::vsi::open_dir(self.api, path, recurse_depth, options)
}

// -- Raster operations ---------------------------------------------------

/// Create a bare in-memory MEM dataset with GDAL-owned bands.
Expand Down
27 changes: 27 additions & 0 deletions c/sedona-gdal/src/gdal_dyn_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ pub type OGRLayerH = *mut c_void;
pub type OGRFeatureH = *mut c_void;
pub type OGRFieldDefnH = *mut c_void;
pub type VSILFILE = *mut c_void;
pub type VSIDIR = c_void;

#[repr(C)]
pub struct VSIDIREntry {
pub pszName: *const c_char,
pub nMode: c_int,
pub bModeKnown: c_int,
pub nSize: vsi_l_offset,
pub bSizeKnown: c_int,
pub nMTime: GIntBig,
pub bMTimeKnown: c_int,
}

pub type vsi_l_offset = u64;
pub type GIntBig = i64;

pub const VSI_S_IFMT: c_int = 0o170000;
pub const VSI_S_IFREG: c_int = 0o100000;

// --- Enum types ---

Expand Down Expand Up @@ -459,6 +477,15 @@ pub(crate) struct SedonaGdalApi {
>,
pub VSIFCloseL: Option<unsafe extern "C" fn(fp: VSILFILE) -> c_int>,
pub VSIUnlink: Option<unsafe extern "C" fn(pszFilename: *const c_char) -> c_int>,
pub VSIOpenDir: Option<
unsafe extern "C" fn(
pszPath: *const c_char,
nRecurseDepth: c_int,
papszOptions: *const *const c_char,
) -> *mut VSIDIR,
>,
pub VSIGetNextDirEntry: Option<unsafe extern "C" fn(dir: *mut VSIDIR) -> *const VSIDIREntry>,
pub VSICloseDir: Option<unsafe extern "C" fn(dir: *mut VSIDIR)>,
pub VSIGetMemFileBuffer: Option<
unsafe extern "C" fn(
pszFilename: *const c_char,
Expand Down
74 changes: 74 additions & 0 deletions c/sedona-gdal/src/vsi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,77 @@ mod tests {
.unwrap();
}
}

pub struct VsiDirEntry {
pub name: String,
pub mode: Option<i32>,
pub size: Option<crate::gdal_dyn_bindgen::vsi_l_offset>,
pub mtime: Option<crate::gdal_dyn_bindgen::GIntBig>,
}

pub struct VsiDir {
api: &'static crate::gdal_api::GdalApi,
handle: *mut crate::gdal_dyn_bindgen::VSIDIR,
}

impl VsiDir {
pub fn next_entry(&mut self) -> Option<VsiDirEntry> {
let entry = unsafe { (self.api.inner.VSIGetNextDirEntry?)(self.handle) };
if entry.is_null() {
return None;
}
let entry = unsafe { &*entry };

let name = if entry.pszName.is_null() {
String::new()
} else {
unsafe { std::ffi::CStr::from_ptr(entry.pszName) }
.to_string_lossy()
.into_owned()
};

Some(VsiDirEntry {
name,
mode: (entry.bModeKnown != 0).then_some(entry.nMode),
size: (entry.bSizeKnown != 0).then_some(entry.nSize),
mtime: (entry.bMTimeKnown != 0).then_some(entry.nMTime),
})
}
}

impl Iterator for VsiDir {
type Item = VsiDirEntry;

fn next(&mut self) -> Option<Self::Item> {
self.next_entry()
}
}

impl Drop for VsiDir {
fn drop(&mut self) {
if !self.handle.is_null() {
if let Some(close) = self.api.inner.VSICloseDir {
unsafe { close(self.handle) };
}
self.handle = std::ptr::null_mut();
}
}
}

pub fn open_dir(
api: &'static crate::gdal_api::GdalApi,
path: &str,
recurse_depth: i32,
options: Option<&crate::cpl::CslStringList>,
) -> crate::errors::Result<VsiDir> {
let c_path = std::ffi::CString::new(path)?;
let options_ptr: *const *const std::os::raw::c_char = options
.map(|opts| opts.as_ptr() as *const *const std::os::raw::c_char)
.unwrap_or(std::ptr::null());
let handle =
unsafe { (api.inner.VSIOpenDir.unwrap())(c_path.as_ptr(), recurse_depth, options_ptr) };
if handle.is_null() {
return Err(api.last_null_pointer_err("VSIOpenDir"));
}
Ok(VsiDir { api, handle })
}
51 changes: 51 additions & 0 deletions docs/reference/sql/rs_geotiff_tiles.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

title: rs_geotiff_tiles
description: Reads a GeoTIFF file or directory of GeoTIFF files as tile rows.
kernels:
- returns: table
args:
- name: path
type: string
- returns: table
args:
- name: path
type: string
- name: recursive
type: bool
---

## Description

`rs_geotiff_tiles()` reads a GeoTIFF file, or a directory of GeoTIFF files, and
returns one row per internal GDAL block. Each row contains the source `path`,
the zero-based tile indices `x` and `y`, and an out-db `rast` value pointing
back to the source file.

## Examples

```sql
SELECT path, x, y
FROM rs_geotiff_tiles('../../../submodules/sedona-testing/data/raster/test4.tiff');
```

```sql
SELECT RS_MetaData(rast)
FROM rs_geotiff_tiles('../../../submodules/sedona-testing/data/raster/test4.tiff');
```
8 changes: 8 additions & 0 deletions rust/sedona-raster-gdal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ arrow-array = { workspace = true }
arrow-buffer = { workspace = true }
arrow-schema = { workspace = true }
async-trait = { workspace = true }
datafusion = { workspace = true, default_features = false }
datafusion-common = { workspace = true }
datafusion-common-runtime = { workspace = true }
datafusion-expr = { workspace = true }
futures = { workspace = true }
lru = { workspace = true }
sedona-common = { workspace = true }
sedona-expr = { workspace = true }
Expand All @@ -63,3 +66,8 @@ path = "benches/rs_frompath.rs"
harness = false
name = "rs_metadata"
path = "benches/rs_metadata.rs"

[[bench]]
harness = false
name = "rs_geotiff_tiles"
path = "benches/rs_geotiff_tiles.rs"
81 changes: 81 additions & 0 deletions rust/sedona-raster-gdal/benches/rs_geotiff_tiles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

//! Benchmarks for rs_geotiff_tiles.

use std::hint::black_box;
use std::sync::Arc;

use arrow_schema::SchemaRef;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use datafusion::catalog::TableProvider;
use sedona_gdal::driver::DriverManager;
use sedona_gdal::global::with_global_gdal_api;
use sedona_gdal::raster::types::Buffer;
use tempfile::TempDir;

fn write_test_geotiff(dir: &TempDir, name: &str) -> String {
let path = dir.path().join(name);
let path_str = path.to_string_lossy().to_string();
with_global_gdal_api(|api| {
let driver = DriverManager::get_driver_by_name(api, "GTiff").unwrap();
let dataset = driver
.create_with_band_type::<u8>(&path_str, 10, 10, 1)
.unwrap();
dataset
.set_geo_transform(&[0.0, 1.0, 0.0, 10.0, 0.0, -1.0])
.unwrap();
let band = dataset.rasterband(1).unwrap();
let mut buffer = Buffer::new((10, 10), (0..100u8).collect::<Vec<_>>());
band.write((0, 0), (10, 10), &mut buffer).unwrap();
})
.unwrap();
path_str
}

fn provider_schema() -> SchemaRef {
sedona_raster_gdal::rs_geotiff_tiles::GeoTiffTilesProvider::try_new("/tmp".to_string(), false)
.unwrap()
.schema()
}

fn bench_rs_geotiff_tiles(c: &mut Criterion) {
let tmp = TempDir::new().unwrap();
let path = write_test_geotiff(&tmp, "bench.tiff");
let schema = Arc::new(provider_schema());
let mut group = c.benchmark_group("rs_geotiff_tiles");
group.throughput(Throughput::Elements(1));
group.bench_with_input(
BenchmarkId::new("fixture", "test4.tiff"),
&path,
|b, input| {
b.iter(|| {
black_box(
sedona_raster_gdal::rs_geotiff_tiles::build_batch_for_file(
input,
(*schema).clone(),
)
.unwrap(),
)
})
},
);
group.finish();
}

criterion_group!(benches, bench_rs_geotiff_tiles);
criterion_main!(benches);
2 changes: 2 additions & 0 deletions rust/sedona-raster-gdal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod gdal_dataset_provider;

mod raster_loader;
mod rs_frompath;
pub mod rs_geotiff_tiles;
mod rs_metadata;
mod source_uri;
mod utils;
Expand All @@ -45,6 +46,7 @@ pub use gdal_common::{
};
pub use raster_loader::{GdalLoader, GDAL_FORMAT};
pub use rs_frompath::rs_frompath_udf;
pub use rs_geotiff_tiles::rs_geotiff_tiles_udtf;
pub use rs_metadata::rs_metadata_udf;
pub use utils::{
append_as_indb_raster, append_as_outdb_raster, append_nd_from_dataset, dataset_to_indb_raster,
Expand Down
Loading
Loading