How to repair a file’s spatial indexes
An index in a file you receive may be maintained by a pre-1.4 trigger set, or may have lost its triggers entirely. This library trusts neither for queries, so bounding-box reads fall back to a full scan until the index is repaired. This guide shows you how to repair it.
Repair is never automatic. The library rewrites an existing trigger set only when you ask it to.
From the shell
To repair every layer in a file that needs it:
$ gpkg repair places.gpkg
points: legacy trigger set index repaired to the 1.4 trigger set
To repair one named layer, add its name:
$ gpkg repair places.gpkg points
If nothing needs repairing, the command says so and exits zero:
$ gpkg repair places.gpkg
nothing to repair
gpkg repair leaves a layer with no index alone, because an unindexed layer
reads correctly. If you want an index built, see
How to add a spatial index to an existing layer.
From Rust
Open the file read-write, preferably with the lenient open. A file that needs
repair already has something wrong with it, and a strict open can fail on a
legacy application_id before you reach the index.
fn main() -> Result<(), Box<dyn std::error::Error>> {
use geopackage::{GeoPackage, SpatialIndexStatus};
let gpkg = GeoPackage::open_lenient("places.gpkg")?;
for layer in gpkg.layers()? {
if layer.geometry_column().is_none() {
continue;
}
match layer.spatial_index_status()? {
SpatialIndexStatus::Legacy | SpatialIndexStatus::Stale => {
layer.repair_spatial_index()?;
}
// Current needs nothing; Absent is a choice, not a defect.
_ => {}
}
}
Ok(()) }
repair_spatial_index drops every RTree trigger on the table, installs the
1.4 set, and rebuilds the index content, in one transaction. It returns
without doing anything when the index is already current, and fails with
Error::NoSpatialIndex when there is no index to repair.
If the structure is right but the contents are in doubt
spatial_index_status checks only the structure. It cannot tell whether the
entries agree with the geometries. An index can be Current and still be
wrong if rows were written while the triggers were absent, or if another tool
populated it incompletely. To check the contents, audit the index:
fn main() -> Result<(), Box<dyn std::error::Error>> {
use geopackage::GeoPackage;
let gpkg = GeoPackage::open_lenient("places.gpkg")?;
let layer = gpkg.layer("points")?;
let audit = layer.audit_spatial_index()?;
if !audit.is_consistent() {
eprintln!(
"{} missing, {} extra, {} not covering",
audit.missing, audit.extra, audit.not_covering
);
layer.rebuild_spatial_index()?;
}
Ok(()) }
The audit reads every geometry in the layer, so run it as a deliberate check,
not before each query. It writes nothing. To fix what it finds, call
rebuild_spatial_index. It does unconditionally what the repair does only when
the structure is wrong.
gpkg validate runs the same audit across the whole file. This is the cheaper
way to find out whether any layer needs rebuilding. See
How to validate a GeoPackage and act on the findings.
Then
- The spatial index: structure, contents, and the bulk build explains why repair is never automatic, and why a legacy trigger set is worth replacing.
- API reference:
Layer::spatial_index_status,Layer::repair_spatial_index,Layer::audit_spatial_index,Layer::rebuild_spatial_index,SpatialIndexAudit.