use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub enum GpkgError {
Sql(rusqlite::Error),
Wkb(wkb::error::WkbError),
#[cfg(feature = "arrow")]
Arrow(arrow_schema::ArrowError),
#[cfg(feature = "arrow")]
GeoArrow(String),
UnsupportedGeometryType(String),
UnsupportedColumnType {
column: String,
declared_type: String,
},
InvalidDimension {
z: i8,
m: i8,
},
InvalidPropertyCount {
expected: usize,
got: usize,
},
InvalidGpkgGeometryFlags(u8),
InvalidGpkgGeometryLength {
len: usize,
minimum: usize,
},
InvalidGpkgGeometryEnvelope {
len: usize,
required: usize,
},
ValueTypeMismatch {
expected: &'static str,
actual: &'static str,
},
ValueOutOfRange {
target: &'static str,
},
MissingProperty {
property: String,
},
LayerAlreadyExists {
layer_name: String,
},
GeometryColumnInAttributeTable {
column: String,
},
MissingSpatialRefSysId {
srs_id: u32,
},
CompositePrimaryKeyUnsupported {
layer_name: String,
},
MissingPrimaryKeyColumn {
layer_name: String,
},
MissingGeometryColumn {
layer_name: String,
},
NotAFeatureLayer {
layer_name: String,
},
NotAnAttributeTable {
layer_name: String,
},
UnsupportedDataType {
layer_name: String,
data_type: String,
},
NullGeometryValue,
Vfs(String),
#[cfg(feature = "arrow")]
InvalidArrowValue {
expected: &'static str,
actual: &'static str,
},
ReadOnly,
}
impl fmt::Display for GpkgError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Sql(err) => write!(f, "{err}"),
Self::Wkb(err) => write!(f, "{err}"),
#[cfg(feature = "arrow")]
Self::Arrow(err) => write!(f, "{err}"),
#[cfg(feature = "arrow")]
Self::GeoArrow(err) => write!(f, "{err}"),
Self::UnsupportedGeometryType(ty) => write!(f, "unsupported geometry type: {ty}"),
Self::UnsupportedColumnType {
column,
declared_type,
} => write!(
f,
"unsupported column type for column '{column}': {declared_type}"
),
Self::InvalidDimension { z, m } => {
write!(f, "invalid or mixed geometry dimension (z={z}, m={m})")
}
Self::InvalidPropertyCount { expected, got } => {
write!(f, "invalid property count: expected {expected}, got {got}")
}
Self::InvalidGpkgGeometryFlags(flags) => {
write!(f, "invalid gpkg geometry flags: {flags:#04x}")
}
Self::InvalidGpkgGeometryLength { len, minimum } => {
write!(
f,
"invalid gpkg geometry length: got {len} bytes, expected at least {minimum}"
)
}
Self::InvalidGpkgGeometryEnvelope { len, required } => {
write!(
f,
"invalid gpkg geometry envelope length: got {len} bytes, required {required}"
)
}
Self::ValueTypeMismatch { expected, actual } => {
write!(f, "expected {expected}, got {actual}")
}
Self::ValueOutOfRange { target } => {
write!(f, "value out of range for {target}")
}
Self::MissingProperty { property } => write!(f, "missing property: {property}"),
Self::LayerAlreadyExists { layer_name } => {
write!(f, "layer already exists: {layer_name}")
}
Self::GeometryColumnInAttributeTable { column } => {
write!(
f,
"attribute tables must not contain geometry columns, but found column '{column}'"
)
}
Self::MissingSpatialRefSysId { srs_id } => {
write!(f, "srs_id {srs_id} not found in gpkg_spatial_ref_sys")
}
Self::CompositePrimaryKeyUnsupported { layer_name } => write!(
f,
"composite primary keys are not supported yet for layer: {layer_name}"
),
Self::MissingPrimaryKeyColumn { layer_name } => {
write!(f, "no primary key column found for layer: {layer_name}")
}
Self::MissingGeometryColumn { layer_name } => {
write!(f, "no geometry column found for layer: {layer_name}")
}
Self::NotAFeatureLayer { layer_name } => {
write!(
f,
"'{layer_name}' is not a feature layer; use get_attribute_table() instead"
)
}
Self::NotAnAttributeTable { layer_name } => {
write!(
f,
"'{layer_name}' is not an attribute table; use get_layer() instead"
)
}
Self::UnsupportedDataType {
layer_name,
data_type,
} => {
write!(
f,
"data_type '{data_type}' is not supported yet (table '{layer_name}')"
)
}
Self::NullGeometryValue => write!(f, "feature has null geometry value"),
Self::Vfs(err) => write!(f, "vfs error: {err}"),
#[cfg(feature = "arrow")]
Self::InvalidArrowValue { expected, actual } => {
write!(
f,
"invalid value for Arrow conversion: expected {expected}, got {actual}"
)
}
Self::ReadOnly => write!(f, "operation not allowed on read-only connection"),
}
}
}
impl Error for GpkgError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Sql(err) => Some(err),
Self::Wkb(err) => Some(err),
#[cfg(feature = "arrow")]
Self::Arrow(err) => Some(err),
_ => None,
}
}
}
impl From<rusqlite::Error> for GpkgError {
fn from(err: rusqlite::Error) -> Self {
Self::Sql(err)
}
}
impl From<wkb::error::WkbError> for GpkgError {
fn from(err: wkb::error::WkbError) -> Self {
Self::Wkb(err)
}
}
pub type Result<T> = std::result::Result<T, GpkgError>;
#[cfg(feature = "arrow")]
impl From<GpkgError> for arrow_schema::ArrowError {
fn from(value: GpkgError) -> Self {
arrow_schema::ArrowError::ExternalError(value.into())
}
}
#[cfg(feature = "arrow")]
impl From<arrow_schema::ArrowError> for GpkgError {
fn from(value: arrow_schema::ArrowError) -> Self {
GpkgError::Arrow(value)
}
}