blob: dd0e01575709dc8d17bca352918eb5dabf862f58 [file]
// 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.
//! Various option and configuration types.
use std::{os::raw::c_int, str::FromStr};
use crate::constants::{ADBC_OPTION_VALUE_DISABLED, ADBC_OPTION_VALUE_ENABLED};
use crate::{
constants,
error::{Error, Status},
};
/// Option value.
///
/// Can be created with various implementations of [From].
///
/// # Note: Booleans
/// ADBC passes booleans as the strings `"true"` ([`ADBC_OPTION_VALUE_ENABLED`])
/// or `"false"` ([`ADBC_OPTION_VALUE_DISABLED`]).
///
/// To reflect this, instead of a special boolean variant, this type implements `From<bool>`
/// and provides `TryFrom<OptionValue> for bool` which expects [`Self::String`].
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum OptionValue {
String(String),
Bytes(Vec<u8>),
Int(i64),
Double(f64),
}
impl From<String> for OptionValue {
fn from(value: String) -> Self {
Self::String(value)
}
}
impl From<&str> for OptionValue {
fn from(value: &str) -> Self {
Self::String(value.into())
}
}
impl From<i64> for OptionValue {
fn from(value: i64) -> Self {
Self::Int(value)
}
}
impl From<f64> for OptionValue {
fn from(value: f64) -> Self {
Self::Double(value)
}
}
impl From<Vec<u8>> for OptionValue {
fn from(value: Vec<u8>) -> Self {
Self::Bytes(value)
}
}
impl From<&[u8]> for OptionValue {
fn from(value: &[u8]) -> Self {
Self::Bytes(value.into())
}
}
impl<const N: usize> From<[u8; N]> for OptionValue {
fn from(value: [u8; N]) -> Self {
Self::Bytes(value.into())
}
}
impl<const N: usize> From<&[u8; N]> for OptionValue {
fn from(value: &[u8; N]) -> Self {
Self::Bytes(value.into())
}
}
impl From<bool> for OptionValue {
/// Convert a boolean to the ADBC string equivalent.
///
/// Returns `"true"` ([`ADBC_OPTION_VALUE_ENABLED`]) for `true`
/// or `"false"` ([`ADBC_OPTION_VALUE_DISABLED`]) for `false`.
fn from(value: bool) -> Self {
if value {
ADBC_OPTION_VALUE_ENABLED.into()
} else {
ADBC_OPTION_VALUE_DISABLED.into()
}
}
}
impl TryFrom<OptionValue> for bool {
type Error = Error;
/// Expects either `"true"` ([`ADBC_OPTION_VALUE_ENABLED`]) for `true`
/// or `"false"` ([`ADBC_OPTION_VALUE_DISABLED`]) for `false`.
///
/// Returns an error with [`Status::InvalidArguments`] if any other string or value type.
fn try_from(value: OptionValue) -> Result<Self, Self::Error> {
// Forward to the borrowed implementation
<bool as TryFrom<&OptionValue>>::try_from(&value)
}
}
impl TryFrom<&OptionValue> for bool {
type Error = Error;
/// Expects either `"true"` ([`ADBC_OPTION_VALUE_ENABLED`]) for `true`
/// or `"false"` ([`ADBC_OPTION_VALUE_DISABLED`]) for `false`.
///
/// Returns an error with [`Status::InvalidArguments`] if any other string or value type.
fn try_from(value: &OptionValue) -> Result<Self, Self::Error> {
match value {
OptionValue::String(value) if value == ADBC_OPTION_VALUE_ENABLED => Ok(true),
OptionValue::String(value) if value == ADBC_OPTION_VALUE_DISABLED => Ok(false),
_ => Err(Error::with_message_and_status(
format!(
"expected {ADBC_OPTION_VALUE_ENABLED:?} or {ADBC_OPTION_VALUE_DISABLED:?}, \
got {value:?}"
),
Status::InvalidArguments,
)),
}
}
}
/// ADBC revision versions.
///
/// The [`Default`] implementation returns the latest version.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum AdbcVersion {
/// Version 1.0.0.
V100,
/// Version 1.1.0.
///
/// <https://arrow.apache.org/adbc/current/format/specification.html#version-1-1-0>
#[default]
V110,
}
impl From<AdbcVersion> for c_int {
fn from(value: AdbcVersion) -> Self {
match value {
AdbcVersion::V100 => constants::ADBC_VERSION_1_0_0,
AdbcVersion::V110 => constants::ADBC_VERSION_1_1_0,
}
}
}
impl TryFrom<c_int> for AdbcVersion {
type Error = Error;
fn try_from(value: c_int) -> Result<Self, Self::Error> {
match value {
constants::ADBC_VERSION_1_0_0 => Ok(AdbcVersion::V100),
constants::ADBC_VERSION_1_1_0 => Ok(AdbcVersion::V110),
value => Err(Error::with_message_and_status(
format!("Unknown ADBC version: {value}"),
Status::InvalidArguments,
)),
}
}
}
impl FromStr for AdbcVersion {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"1.0.0" | "1_0_0" | "100" => Ok(AdbcVersion::V100),
"1.1.0" | "1_1_0" | "110" => Ok(AdbcVersion::V110),
value => Err(Error::with_message_and_status(
format!("Unknown ADBC version: {value}"),
Status::InvalidArguments,
)),
}
}
}
/// Info codes for database/driver metadata.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum InfoCode {
/// The database vendor/product name (type: utf8).
VendorName,
/// The database vendor/product version (type: utf8).
VendorVersion,
/// The database vendor/product Arrow library version (type: utf8).
VendorArrowVersion,
/// Indicates whether SQL queries are supported (type: bool).
VendorSql,
/// Indicates whether Substrait queries are supported (type: bool).
VendorSubstrait,
/// The minimum supported Substrait version, or null if Substrait is not supported (type: utf8).
VendorSubstraitMinVersion,
/// The maximum supported Substrait version, or null if Substrait is not supported (type: utf8).
VendorSubstraitMaxVersion,
/// The driver name (type: utf8).
DriverName,
/// The driver version (type: utf8).
DriverVersion,
/// The driver Arrow library version (type: utf8).
DriverArrowVersion,
/// The driver ADBC API version (type: int64).
///
/// # Since
///
/// ADBC API revision 1.1.0
DriverAdbcVersion,
/// Any other info code than the ones listed above. The value is the raw code.
///
/// Codes `[0, 10_000)` are reserved for ADBC usage (of which `[500, 1_000)`
/// is reserved for "XDBC" information since ADBC API revision 1.1.0), while
/// codes `10_000` and higher are driver/vendor-specific. Drivers ignore
/// requests for codes they don't recognize (the row is omitted from the
/// result).
///
/// Note: to keep equality and hashing consistent, this variant should never
/// be constructed with the value of a code that has a dedicated variant;
/// use [InfoCode::from] to convert from a raw `u32`, which only produces
/// `Other` for values without one.
Other(u32),
}
impl From<&InfoCode> for u32 {
fn from(value: &InfoCode) -> Self {
match value {
InfoCode::VendorName => constants::ADBC_INFO_VENDOR_NAME,
InfoCode::VendorVersion => constants::ADBC_INFO_VENDOR_VERSION,
InfoCode::VendorArrowVersion => constants::ADBC_INFO_VENDOR_ARROW_VERSION,
InfoCode::VendorSql => constants::ADBC_INFO_VENDOR_SQL,
InfoCode::VendorSubstrait => constants::ADBC_INFO_VENDOR_SUBSTRAIT,
InfoCode::VendorSubstraitMinVersion => {
constants::ADBC_INFO_VENDOR_SUBSTRAIT_MIN_VERSION
}
InfoCode::VendorSubstraitMaxVersion => {
constants::ADBC_INFO_VENDOR_SUBSTRAIT_MAX_VERSION
}
InfoCode::DriverName => constants::ADBC_INFO_DRIVER_NAME,
InfoCode::DriverVersion => constants::ADBC_INFO_DRIVER_VERSION,
InfoCode::DriverArrowVersion => constants::ADBC_INFO_DRIVER_ARROW_VERSION,
InfoCode::DriverAdbcVersion => constants::ADBC_INFO_DRIVER_ADBC_VERSION,
InfoCode::Other(v) => *v,
}
}
}
impl From<u32> for InfoCode {
fn from(value: u32) -> Self {
match value {
constants::ADBC_INFO_VENDOR_NAME => InfoCode::VendorName,
constants::ADBC_INFO_VENDOR_VERSION => InfoCode::VendorVersion,
constants::ADBC_INFO_VENDOR_ARROW_VERSION => InfoCode::VendorArrowVersion,
constants::ADBC_INFO_VENDOR_SQL => InfoCode::VendorSql,
constants::ADBC_INFO_VENDOR_SUBSTRAIT => InfoCode::VendorSubstrait,
constants::ADBC_INFO_VENDOR_SUBSTRAIT_MIN_VERSION => {
InfoCode::VendorSubstraitMinVersion
}
constants::ADBC_INFO_VENDOR_SUBSTRAIT_MAX_VERSION => {
InfoCode::VendorSubstraitMaxVersion
}
constants::ADBC_INFO_DRIVER_NAME => InfoCode::DriverName,
constants::ADBC_INFO_DRIVER_VERSION => InfoCode::DriverVersion,
constants::ADBC_INFO_DRIVER_ARROW_VERSION => InfoCode::DriverArrowVersion,
constants::ADBC_INFO_DRIVER_ADBC_VERSION => InfoCode::DriverAdbcVersion,
v => InfoCode::Other(v),
}
}
}
/// Depth parameter for [get_objects][crate::Connection::get_objects] method.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ObjectDepth {
/// Catalogs, schemas, tables, and columns.
All,
/// Catalogs only.
Catalogs,
/// Catalogs and schemas.
Schemas,
/// Catalogs, schemas, and tables.
Tables,
/// Catalogs, schemas, tables, and columns. Identical to [ObjectDepth::All].
Columns,
}
impl From<ObjectDepth> for c_int {
fn from(value: ObjectDepth) -> Self {
match value {
ObjectDepth::All => constants::ADBC_OBJECT_DEPTH_ALL,
ObjectDepth::Catalogs => constants::ADBC_OBJECT_DEPTH_CATALOGS,
ObjectDepth::Schemas => constants::ADBC_OBJECT_DEPTH_DB_SCHEMAS,
ObjectDepth::Tables => constants::ADBC_OBJECT_DEPTH_TABLES,
ObjectDepth::Columns => constants::ADBC_OBJECT_DEPTH_COLUMNS,
}
}
}
impl TryFrom<c_int> for ObjectDepth {
type Error = Error;
fn try_from(value: c_int) -> Result<Self, Error> {
match value {
constants::ADBC_OBJECT_DEPTH_ALL => Ok(ObjectDepth::All),
constants::ADBC_OBJECT_DEPTH_CATALOGS => Ok(ObjectDepth::Catalogs),
constants::ADBC_OBJECT_DEPTH_DB_SCHEMAS => Ok(ObjectDepth::Schemas),
constants::ADBC_OBJECT_DEPTH_TABLES => Ok(ObjectDepth::Tables),
v => Err(Error::with_message_and_status(
format!("Unknown object depth: {v}"),
Status::InvalidData,
)),
}
}
}
/// Database option key.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[non_exhaustive]
pub enum OptionDatabase {
/// Canonical option key for URIs.
///
/// # Since
///
/// ADBC API revision 1.1.0
Uri,
/// Canonical option key for usernames.
///
/// # Since
///
/// ADBC API revision 1.1.0
Username,
/// Canonical option key for passwords.
///
/// # Since
///
/// ADBC API revision 1.1.0
Password,
/// Driver-specific key.
Other(String),
}
impl AsRef<str> for OptionDatabase {
fn as_ref(&self) -> &str {
match self {
Self::Uri => constants::ADBC_OPTION_URI,
Self::Username => constants::ADBC_OPTION_USERNAME,
Self::Password => constants::ADBC_OPTION_PASSWORD,
Self::Other(key) => key,
}
}
}
impl From<&str> for OptionDatabase {
fn from(value: &str) -> Self {
match value {
constants::ADBC_OPTION_URI => Self::Uri,
constants::ADBC_OPTION_USERNAME => Self::Username,
constants::ADBC_OPTION_PASSWORD => Self::Password,
key => Self::Other(key.into()),
}
}
}
/// Connection option key.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[non_exhaustive]
pub enum OptionConnection {
/// Whether autocommit is enabled.
AutoCommit,
/// Whether the current connection should be restricted to being read-only.
ReadOnly,
/// The catalog used by the connection.
/// # Since
/// ADBC API revision 1.1.0
CurrentCatalog,
/// The database schema used by the connection.
/// # Since
/// ADBC API revision 1.1.0
CurrentSchema,
/// The isolation level of the connection. See [IsolationLevel].
IsolationLevel,
/// Driver-specific key.
Other(String),
}
impl AsRef<str> for OptionConnection {
fn as_ref(&self) -> &str {
match self {
Self::AutoCommit => constants::ADBC_CONNECTION_OPTION_AUTOCOMMIT,
Self::ReadOnly => constants::ADBC_CONNECTION_OPTION_READ_ONLY,
Self::CurrentCatalog => constants::ADBC_CONNECTION_OPTION_CURRENT_CATALOG,
Self::CurrentSchema => constants::ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA,
Self::IsolationLevel => constants::ADBC_CONNECTION_OPTION_ISOLATION_LEVEL,
Self::Other(key) => key,
}
}
}
impl From<&str> for OptionConnection {
fn from(value: &str) -> Self {
match value {
constants::ADBC_CONNECTION_OPTION_AUTOCOMMIT => Self::AutoCommit,
constants::ADBC_CONNECTION_OPTION_READ_ONLY => Self::ReadOnly,
constants::ADBC_CONNECTION_OPTION_CURRENT_CATALOG => Self::CurrentCatalog,
constants::ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA => Self::CurrentSchema,
constants::ADBC_CONNECTION_OPTION_ISOLATION_LEVEL => Self::IsolationLevel,
key => Self::Other(key.into()),
}
}
}
/// Statement option key.
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
#[non_exhaustive]
pub enum OptionStatement {
/// The ingest mode for a bulk insert. See [IngestMode].
IngestMode,
/// The name of the target table for a bulk insert.
TargetTable,
/// The catalog of the table for bulk insert.
TargetCatalog,
/// The schema of the table for bulk insert.
TargetDbSchema,
/// Use a temporary table for ingestion.
Temporary,
/// Whether query execution is nonblocking. By default, execution is blocking.
///
/// When enabled, [execute_partitions][crate::Statement::execute_partitions]
/// will return partitions as soon as they are available, instead of returning
/// them all at the end. When there are no more to return, it will return an
/// empty set of partitions. The methods [execute][crate::Statement::execute],
/// [execute_schema][crate::Statement::execute_schema] and
/// [execute_update][crate::Statement::execute_update] are not affected.
///
/// # Since
///
/// ADBC API revision 1.1.0
Incremental,
/// Get the progress of a query. It's a read-only option that should be
/// read with [get_option_double][crate::Optionable::get_option_double].
///
/// The value is not necessarily in any particular range or have any
/// particular units. For example, it might be a percentage, bytes of data,
/// rows of data, number of workers, etc. The max value can be retrieved
/// via [OptionStatement::MaxProgress]. This represents the progress of
/// execution, not of consumption (i.e., it is independent of how much of the
/// result set has been read by the client).
///
/// # Since
///
/// ADBC API revision 1.1.0
Progress,
/// Get the maximum progress of a query. It's a read-only option that should be
/// read with [get_option_double][crate::Optionable::get_option_double].
///
/// This is the value of [OptionStatement::Progress] for a completed query.
/// If not supported, or if the value is nonpositive, then the maximum is not
/// known. For instance, the query may be fully streaming and the driver
/// does not know when the result set will end.
///
/// # Since
///
/// ADBC API revision 1.1.0
MaxProgress,
/// Driver-specific key.
Other(String),
}
impl AsRef<str> for OptionStatement {
fn as_ref(&self) -> &str {
match self {
Self::IngestMode => constants::ADBC_INGEST_OPTION_MODE,
Self::TargetTable => constants::ADBC_INGEST_OPTION_TARGET_TABLE,
Self::TargetCatalog => constants::ADBC_INGEST_OPTION_TARGET_CATALOG,
Self::TargetDbSchema => constants::ADBC_INGEST_OPTION_TARGET_DB_SCHEMA,
Self::Temporary => constants::ADBC_INGEST_OPTION_TEMPORARY,
Self::Incremental => constants::ADBC_STATEMENT_OPTION_INCREMENTAL,
Self::Progress => constants::ADBC_STATEMENT_OPTION_PROGRESS,
Self::MaxProgress => constants::ADBC_STATEMENT_OPTION_MAX_PROGRESS,
Self::Other(key) => key,
}
}
}
impl From<&str> for OptionStatement {
fn from(value: &str) -> Self {
match value {
constants::ADBC_INGEST_OPTION_MODE => Self::IngestMode,
constants::ADBC_INGEST_OPTION_TARGET_TABLE => Self::TargetTable,
constants::ADBC_INGEST_OPTION_TARGET_CATALOG => Self::TargetCatalog,
constants::ADBC_INGEST_OPTION_TARGET_DB_SCHEMA => Self::TargetDbSchema,
constants::ADBC_INGEST_OPTION_TEMPORARY => Self::Temporary,
constants::ADBC_STATEMENT_OPTION_INCREMENTAL => Self::Incremental,
constants::ADBC_STATEMENT_OPTION_PROGRESS => Self::Progress,
constants::ADBC_STATEMENT_OPTION_MAX_PROGRESS => Self::MaxProgress,
key => Self::Other(key.into()),
}
}
}
/// Isolation level value for key [OptionConnection::IsolationLevel].
#[derive(Debug)]
pub enum IsolationLevel {
/// Use database or driver default isolation level.
Default,
/// The lowest isolation level. Dirty reads are allowed, so one transaction
/// may see not-yet-committed changes made by others.
ReadUncommitted,
/// Lock-based concurrency control keeps write locks until the end of the
/// transaction, but read locks are released as soon as a SELECT is
/// performed. Non-repeatable reads can occur in this isolation level.
///
/// More simply put, `ReadCommitted` is an isolation level that guarantees
/// that any data read is committed at the moment it is read. It simply
/// restricts the reader from seeing any intermediate, uncommitted,
/// 'dirty' reads. It makes no promise whatsoever that if the transaction
/// re-issues the read, it will find the same data; data is free to change
/// after it is read.
ReadCommitted,
/// Lock-based concurrency control keeps read AND write locks (acquired on
/// selection data) until the end of the transaction.
///
/// However, range-locks are not managed, so phantom reads can occur.
/// Write skew is possible at this isolation level in some systems.
RepeatableRead,
/// This isolation guarantees that all reads in the transaction will see a
/// consistent snapshot of the database and the transaction should only
/// successfully commit if no updates conflict with any concurrent updates
/// made since that snapshot.
Snapshot,
/// Serializability requires read and write locks to be released only at the
/// end of the transaction. This includes acquiring range-locks when a
/// select query uses a ranged WHERE clause to avoid phantom reads.
Serializable,
/// The central distinction between serializability and linearizability is
/// that serializability is a global property; a property of an entire
/// history of operations and transactions. Linearizability is a local
/// property; a property of a single operation/transaction.
///
/// Linearizability can be viewed as a special case of strict serializability
/// where transactions are restricted to consist of a single operation applied
/// to a single object.
Linearizable,
}
impl From<IsolationLevel> for String {
fn from(value: IsolationLevel) -> Self {
match value {
IsolationLevel::Default => constants::ADBC_OPTION_ISOLATION_LEVEL_DEFAULT.into(),
IsolationLevel::ReadUncommitted => {
constants::ADBC_OPTION_ISOLATION_LEVEL_READ_UNCOMMITTED.into()
}
IsolationLevel::ReadCommitted => {
constants::ADBC_OPTION_ISOLATION_LEVEL_READ_COMMITTED.into()
}
IsolationLevel::RepeatableRead => {
constants::ADBC_OPTION_ISOLATION_LEVEL_REPEATABLE_READ.into()
}
IsolationLevel::Snapshot => constants::ADBC_OPTION_ISOLATION_LEVEL_SNAPSHOT.into(),
IsolationLevel::Serializable => {
constants::ADBC_OPTION_ISOLATION_LEVEL_SERIALIZABLE.into()
}
IsolationLevel::Linearizable => {
constants::ADBC_OPTION_ISOLATION_LEVEL_LINEARIZABLE.into()
}
}
}
}
impl From<IsolationLevel> for OptionValue {
fn from(value: IsolationLevel) -> Self {
Self::String(value.into())
}
}
/// Ingestion mode value for key [OptionStatement::IngestMode].
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum IngestMode {
/// Create the table and insert data; error if the table exists.
Create,
/// Do not create the table, and insert data; error if the table does not
/// exist ([Status::NotFound]) or does not match the schema of the data to
/// append ([Status::AlreadyExists]).
Append,
/// Create the table and insert data; drop the original table if it already
/// exists.
///
/// # Since
///
/// ADBC API revision 1.1.0
Replace,
/// Insert data; create the table if it does not exist, or error if the
/// table exists, but the schema does not match the schema of the data to
/// append ([Status::AlreadyExists]).
///
/// # Since
///
/// ADBC API revision 1.1.0
CreateAppend,
}
impl From<IngestMode> for String {
fn from(value: IngestMode) -> Self {
match value {
IngestMode::Create => constants::ADBC_INGEST_OPTION_MODE_CREATE.into(),
IngestMode::Append => constants::ADBC_INGEST_OPTION_MODE_APPEND.into(),
IngestMode::Replace => constants::ADBC_INGEST_OPTION_MODE_REPLACE.into(),
IngestMode::CreateAppend => constants::ADBC_INGEST_OPTION_MODE_CREATE_APPEND.into(),
}
}
}
impl From<IngestMode> for OptionValue {
fn from(value: IngestMode) -> Self {
Self::String(value.into())
}
}
impl FromStr for IngestMode {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
constants::ADBC_INGEST_OPTION_MODE_CREATE => Ok(Self::Create),
constants::ADBC_INGEST_OPTION_MODE_APPEND => Ok(Self::Append),
constants::ADBC_INGEST_OPTION_MODE_REPLACE => Ok(Self::Replace),
constants::ADBC_INGEST_OPTION_MODE_CREATE_APPEND => Ok(Self::CreateAppend),
other => Err(Error::with_message_and_status(
format!(
"invalid value for option {:?}: {other:?}",
constants::ADBC_INGEST_OPTION_MODE
),
Status::InvalidArguments,
)),
}
}
}
impl TryFrom<&OptionValue> for IngestMode {
type Error = Error;
fn try_from(value: &OptionValue) -> Result<Self, Self::Error> {
match value {
OptionValue::String(s) => s.parse(),
other => Err(Error::with_message_and_status(
format!(
"invalid value type for option {:?}: {other:?}",
constants::ADBC_INGEST_OPTION_MODE
),
Status::InvalidArguments,
)),
}
}
}
/// Statistics about the data distribution.
#[derive(Debug, Clone)]
pub enum Statistics {
/// The average byte width statistic. The average size in bytes of a row in
/// the column. Value type is `float64`. For example, this is roughly the
/// average length of a string for a string column.
AverageByteWidth,
/// The distinct value count (NDV) statistic. The number of distinct values
/// in the column. Value type is `int64` (when not approximate) or `float64`
/// (when approximate).
DistinctCount,
/// The max byte width statistic. The maximum size in bytes of a row in the
/// column. Value type is `int64` (when not approximate) or `float64` (when approximate).
/// For example, this is the maximum length of a string for a string column.
MaxByteWidth,
/// The max value statistic. Value type is column-dependent.
MaxValue,
/// The min value statistic. Value type is column-dependent.
MinValue,
/// The null count statistic. The number of values that are null in the
/// column. Value type is `int64` (when not approximate) or `float64` (when approximate).
NullCount,
/// The row count statistic. The number of rows in the column or table.
/// Value type is `int64` (when not approximate) or `float64` (when approximate).
RowCount,
/// Driver-specific statistics.
Other { key: i16, name: String },
}
impl TryFrom<i16> for Statistics {
type Error = Error;
fn try_from(value: i16) -> Result<Self, Self::Error> {
match value {
constants::ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_KEY => Ok(Self::AverageByteWidth),
constants::ADBC_STATISTIC_DISTINCT_COUNT_KEY => Ok(Self::DistinctCount),
constants::ADBC_STATISTIC_MAX_BYTE_WIDTH_KEY => Ok(Self::MaxByteWidth),
constants::ADBC_STATISTIC_MAX_VALUE_KEY => Ok(Self::MaxValue),
constants::ADBC_STATISTIC_MIN_VALUE_KEY => Ok(Self::MinValue),
constants::ADBC_STATISTIC_NULL_COUNT_KEY => Ok(Self::NullCount),
constants::ADBC_STATISTIC_ROW_COUNT_KEY => Ok(Self::RowCount),
_ => Err(Error::with_message_and_status(
format!("Unknown standard statistic key: {value}"),
Status::InvalidArguments,
)),
}
}
}
impl From<Statistics> for i16 {
fn from(value: Statistics) -> Self {
match value {
Statistics::AverageByteWidth => constants::ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_KEY,
Statistics::DistinctCount => constants::ADBC_STATISTIC_DISTINCT_COUNT_KEY,
Statistics::MaxByteWidth => constants::ADBC_STATISTIC_MAX_BYTE_WIDTH_KEY,
Statistics::MaxValue => constants::ADBC_STATISTIC_MAX_VALUE_KEY,
Statistics::MinValue => constants::ADBC_STATISTIC_MIN_VALUE_KEY,
Statistics::NullCount => constants::ADBC_STATISTIC_NULL_COUNT_KEY,
Statistics::RowCount => constants::ADBC_STATISTIC_ROW_COUNT_KEY,
Statistics::Other { key, name: _ } => key,
}
}
}
impl AsRef<str> for Statistics {
fn as_ref(&self) -> &str {
match self {
Statistics::AverageByteWidth => constants::ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_NAME,
Statistics::DistinctCount => constants::ADBC_STATISTIC_DISTINCT_COUNT_NAME,
Statistics::MaxByteWidth => constants::ADBC_STATISTIC_MAX_BYTE_WIDTH_NAME,
Statistics::MaxValue => constants::ADBC_STATISTIC_MAX_VALUE_NAME,
Statistics::MinValue => constants::ADBC_STATISTIC_MIN_VALUE_NAME,
Statistics::NullCount => constants::ADBC_STATISTIC_NULL_COUNT_NAME,
Statistics::RowCount => constants::ADBC_STATISTIC_ROW_COUNT_NAME,
Statistics::Other { key: _, name } => name,
}
}
}
impl std::fmt::Display for Statistics {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn info_code_u32_roundtrip() {
for code in (0..20_000_u32).chain([u32::MAX]) {
assert_eq!(u32::from(&InfoCode::from(code)), code);
}
assert_eq!(
InfoCode::from(constants::ADBC_INFO_VENDOR_NAME),
InfoCode::VendorName
);
assert_eq!(InfoCode::from(10_042), InfoCode::Other(10_042));
}
}