adbc_core/
options.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Various option and configuration types.
19use std::{os::raw::c_int, str::FromStr};
20
21use crate::{
22    constants,
23    error::{Error, Status},
24};
25
26/// Option value.
27///
28/// Can be created with various implementations of [From].
29#[derive(Debug, Clone)]
30#[non_exhaustive]
31pub enum OptionValue {
32    String(String),
33    Bytes(Vec<u8>),
34    Int(i64),
35    Double(f64),
36}
37
38impl From<String> for OptionValue {
39    fn from(value: String) -> Self {
40        Self::String(value)
41    }
42}
43
44impl From<&str> for OptionValue {
45    fn from(value: &str) -> Self {
46        Self::String(value.into())
47    }
48}
49
50impl From<i64> for OptionValue {
51    fn from(value: i64) -> Self {
52        Self::Int(value)
53    }
54}
55
56impl From<f64> for OptionValue {
57    fn from(value: f64) -> Self {
58        Self::Double(value)
59    }
60}
61
62impl From<Vec<u8>> for OptionValue {
63    fn from(value: Vec<u8>) -> Self {
64        Self::Bytes(value)
65    }
66}
67
68impl From<&[u8]> for OptionValue {
69    fn from(value: &[u8]) -> Self {
70        Self::Bytes(value.into())
71    }
72}
73
74impl<const N: usize> From<[u8; N]> for OptionValue {
75    fn from(value: [u8; N]) -> Self {
76        Self::Bytes(value.into())
77    }
78}
79
80impl<const N: usize> From<&[u8; N]> for OptionValue {
81    fn from(value: &[u8; N]) -> Self {
82        Self::Bytes(value.into())
83    }
84}
85
86/// ADBC revision versions.
87///
88/// The [`Default`] implementation returns the latest version.
89#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
90#[non_exhaustive]
91pub enum AdbcVersion {
92    /// Version 1.0.0.
93    V100,
94    /// Version 1.1.0.
95    ///
96    /// <https://arrow.apache.org/adbc/current/format/specification.html#version-1-1-0>
97    #[default]
98    V110,
99}
100
101impl From<AdbcVersion> for c_int {
102    fn from(value: AdbcVersion) -> Self {
103        match value {
104            AdbcVersion::V100 => constants::ADBC_VERSION_1_0_0,
105            AdbcVersion::V110 => constants::ADBC_VERSION_1_1_0,
106        }
107    }
108}
109
110impl TryFrom<c_int> for AdbcVersion {
111    type Error = Error;
112    fn try_from(value: c_int) -> Result<Self, Self::Error> {
113        match value {
114            constants::ADBC_VERSION_1_0_0 => Ok(AdbcVersion::V100),
115            constants::ADBC_VERSION_1_1_0 => Ok(AdbcVersion::V110),
116            value => Err(Error::with_message_and_status(
117                format!("Unknown ADBC version: {value}"),
118                Status::InvalidArguments,
119            )),
120        }
121    }
122}
123
124impl FromStr for AdbcVersion {
125    type Err = Error;
126
127    fn from_str(s: &str) -> Result<Self, Self::Err> {
128        match s {
129            "1.0.0" | "1_0_0" | "100" => Ok(AdbcVersion::V100),
130            "1.1.0" | "1_1_0" | "110" => Ok(AdbcVersion::V110),
131            value => Err(Error::with_message_and_status(
132                format!("Unknown ADBC version: {value}"),
133                Status::InvalidArguments,
134            )),
135        }
136    }
137}
138
139/// Info codes for database/driver metadata.
140#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
141#[non_exhaustive]
142pub enum InfoCode {
143    /// The database vendor/product name (type: utf8).
144    VendorName,
145    /// The database vendor/product version (type: utf8).
146    VendorVersion,
147    /// The database vendor/product Arrow library version (type: utf8).
148    VendorArrowVersion,
149    /// Indicates whether SQL queries are supported (type: bool).
150    VendorSql,
151    /// Indicates whether Substrait queries are supported (type: bool).
152    VendorSubstrait,
153    /// The minimum supported Substrait version, or null if Substrait is not supported (type: utf8).
154    VendorSubstraitMinVersion,
155    /// The maximum supported Substrait version, or null if Substrait is not supported (type: utf8).
156    VendorSubstraitMaxVersion,
157    /// The driver name (type: utf8).
158    DriverName,
159    /// The driver version (type: utf8).
160    DriverVersion,
161    /// The driver Arrow library version (type: utf8).
162    DriverArrowVersion,
163    /// The driver ADBC API version (type: int64).
164    ///
165    /// # Since
166    ///
167    /// ADBC API revision 1.1.0
168    DriverAdbcVersion,
169}
170
171impl From<&InfoCode> for u32 {
172    fn from(value: &InfoCode) -> Self {
173        match value {
174            InfoCode::VendorName => constants::ADBC_INFO_VENDOR_NAME,
175            InfoCode::VendorVersion => constants::ADBC_INFO_VENDOR_VERSION,
176            InfoCode::VendorArrowVersion => constants::ADBC_INFO_VENDOR_ARROW_VERSION,
177            InfoCode::VendorSql => constants::ADBC_INFO_VENDOR_SQL,
178            InfoCode::VendorSubstrait => constants::ADBC_INFO_VENDOR_SUBSTRAIT,
179            InfoCode::VendorSubstraitMinVersion => {
180                constants::ADBC_INFO_VENDOR_SUBSTRAIT_MIN_VERSION
181            }
182            InfoCode::VendorSubstraitMaxVersion => {
183                constants::ADBC_INFO_VENDOR_SUBSTRAIT_MAX_VERSION
184            }
185            InfoCode::DriverName => constants::ADBC_INFO_DRIVER_NAME,
186            InfoCode::DriverVersion => constants::ADBC_INFO_DRIVER_VERSION,
187            InfoCode::DriverArrowVersion => constants::ADBC_INFO_DRIVER_ARROW_VERSION,
188            InfoCode::DriverAdbcVersion => constants::ADBC_INFO_DRIVER_ADBC_VERSION,
189        }
190    }
191}
192
193impl TryFrom<u32> for InfoCode {
194    type Error = Error;
195
196    fn try_from(value: u32) -> Result<Self, Self::Error> {
197        match value {
198            constants::ADBC_INFO_VENDOR_NAME => Ok(InfoCode::VendorName),
199            constants::ADBC_INFO_VENDOR_VERSION => Ok(InfoCode::VendorVersion),
200            constants::ADBC_INFO_VENDOR_ARROW_VERSION => Ok(InfoCode::VendorArrowVersion),
201            constants::ADBC_INFO_VENDOR_SQL => Ok(InfoCode::VendorSql),
202            constants::ADBC_INFO_VENDOR_SUBSTRAIT => Ok(InfoCode::VendorSubstrait),
203            constants::ADBC_INFO_VENDOR_SUBSTRAIT_MIN_VERSION => {
204                Ok(InfoCode::VendorSubstraitMinVersion)
205            }
206            constants::ADBC_INFO_VENDOR_SUBSTRAIT_MAX_VERSION => {
207                Ok(InfoCode::VendorSubstraitMaxVersion)
208            }
209            constants::ADBC_INFO_DRIVER_NAME => Ok(InfoCode::DriverName),
210            constants::ADBC_INFO_DRIVER_VERSION => Ok(InfoCode::DriverVersion),
211            constants::ADBC_INFO_DRIVER_ARROW_VERSION => Ok(InfoCode::DriverArrowVersion),
212            constants::ADBC_INFO_DRIVER_ADBC_VERSION => Ok(InfoCode::DriverAdbcVersion),
213            v => Err(Error::with_message_and_status(
214                format!("Unknown info code: {v}"),
215                Status::InvalidData,
216            )),
217        }
218    }
219}
220
221/// Depth parameter for [get_objects][crate::Connection::get_objects] method.
222#[derive(Debug)]
223pub enum ObjectDepth {
224    /// Catalogs, schemas, tables, and columns.
225    All,
226    /// Catalogs only.
227    Catalogs,
228    /// Catalogs and schemas.
229    Schemas,
230    /// Catalogs, schemas, and tables.
231    Tables,
232    /// Catalogs, schemas, tables, and columns. Identical to [ObjectDepth::All].
233    Columns,
234}
235
236impl From<ObjectDepth> for c_int {
237    fn from(value: ObjectDepth) -> Self {
238        match value {
239            ObjectDepth::All => constants::ADBC_OBJECT_DEPTH_ALL,
240            ObjectDepth::Catalogs => constants::ADBC_OBJECT_DEPTH_CATALOGS,
241            ObjectDepth::Schemas => constants::ADBC_OBJECT_DEPTH_DB_SCHEMAS,
242            ObjectDepth::Tables => constants::ADBC_OBJECT_DEPTH_TABLES,
243            ObjectDepth::Columns => constants::ADBC_OBJECT_DEPTH_COLUMNS,
244        }
245    }
246}
247
248impl TryFrom<c_int> for ObjectDepth {
249    type Error = Error;
250
251    fn try_from(value: c_int) -> Result<Self, Error> {
252        match value {
253            constants::ADBC_OBJECT_DEPTH_ALL => Ok(ObjectDepth::All),
254            constants::ADBC_OBJECT_DEPTH_CATALOGS => Ok(ObjectDepth::Catalogs),
255            constants::ADBC_OBJECT_DEPTH_DB_SCHEMAS => Ok(ObjectDepth::Schemas),
256            constants::ADBC_OBJECT_DEPTH_TABLES => Ok(ObjectDepth::Tables),
257            v => Err(Error::with_message_and_status(
258                format!("Unknown object depth: {v}"),
259                Status::InvalidData,
260            )),
261        }
262    }
263}
264
265/// Database option key.
266#[derive(PartialEq, Eq, Hash, Debug, Clone)]
267#[non_exhaustive]
268pub enum OptionDatabase {
269    /// Canonical option key for URIs.
270    ///
271    /// # Since
272    ///
273    /// ADBC API revision 1.1.0
274    Uri,
275    /// Canonical option key for usernames.
276    ///
277    /// # Since
278    ///
279    /// ADBC API revision 1.1.0
280    Username,
281    /// Canonical option key for passwords.
282    ///
283    /// # Since
284    ///
285    /// ADBC API revision 1.1.0
286    Password,
287    /// Driver-specific key.
288    Other(String),
289}
290
291impl AsRef<str> for OptionDatabase {
292    fn as_ref(&self) -> &str {
293        match self {
294            Self::Uri => constants::ADBC_OPTION_URI,
295            Self::Username => constants::ADBC_OPTION_USERNAME,
296            Self::Password => constants::ADBC_OPTION_PASSWORD,
297            Self::Other(key) => key,
298        }
299    }
300}
301
302impl From<&str> for OptionDatabase {
303    fn from(value: &str) -> Self {
304        match value {
305            constants::ADBC_OPTION_URI => Self::Uri,
306            constants::ADBC_OPTION_USERNAME => Self::Username,
307            constants::ADBC_OPTION_PASSWORD => Self::Password,
308            key => Self::Other(key.into()),
309        }
310    }
311}
312
313/// Connection option key.
314#[derive(PartialEq, Eq, Hash, Debug, Clone)]
315#[non_exhaustive]
316pub enum OptionConnection {
317    /// Whether autocommit is enabled.
318    AutoCommit,
319    /// Whether the current connection should be restricted to being read-only.
320    ReadOnly,
321    /// The catalog used by the connection.
322    /// # Since
323    /// ADBC API revision 1.1.0
324    CurrentCatalog,
325    /// The database schema used by the connection.
326    /// # Since
327    /// ADBC API revision 1.1.0
328    CurrentSchema,
329    /// The isolation level of the connection. See [IsolationLevel].
330    IsolationLevel,
331    /// Driver-specific key.
332    Other(String),
333}
334
335impl AsRef<str> for OptionConnection {
336    fn as_ref(&self) -> &str {
337        match self {
338            Self::AutoCommit => constants::ADBC_CONNECTION_OPTION_AUTOCOMMIT,
339            Self::ReadOnly => constants::ADBC_CONNECTION_OPTION_READ_ONLY,
340            Self::CurrentCatalog => constants::ADBC_CONNECTION_OPTION_CURRENT_CATALOG,
341            Self::CurrentSchema => constants::ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA,
342            Self::IsolationLevel => constants::ADBC_CONNECTION_OPTION_ISOLATION_LEVEL,
343            Self::Other(key) => key,
344        }
345    }
346}
347
348impl From<&str> for OptionConnection {
349    fn from(value: &str) -> Self {
350        match value {
351            constants::ADBC_CONNECTION_OPTION_AUTOCOMMIT => Self::AutoCommit,
352            constants::ADBC_CONNECTION_OPTION_READ_ONLY => Self::ReadOnly,
353            constants::ADBC_CONNECTION_OPTION_CURRENT_CATALOG => Self::CurrentCatalog,
354            constants::ADBC_CONNECTION_OPTION_CURRENT_DB_SCHEMA => Self::CurrentSchema,
355            constants::ADBC_CONNECTION_OPTION_ISOLATION_LEVEL => Self::IsolationLevel,
356            key => Self::Other(key.into()),
357        }
358    }
359}
360
361/// Statement option key.
362#[derive(PartialEq, Eq, Hash, Debug, Clone)]
363#[non_exhaustive]
364pub enum OptionStatement {
365    /// The ingest mode for a bulk insert. See [IngestMode].
366    IngestMode,
367    /// The name of the target table for a bulk insert.
368    TargetTable,
369    /// The catalog of the table for bulk insert.
370    TargetCatalog,
371    /// The schema of the table for bulk insert.
372    TargetDbSchema,
373    /// Use a temporary table for ingestion.
374    Temporary,
375    /// Whether query execution is nonblocking. By default, execution is blocking.
376    ///
377    /// When enabled, [execute_partitions][crate::Statement::execute_partitions]
378    /// will return partitions as soon as they are available, instead of returning
379    /// them all at the end. When there are no more to return, it will return an
380    /// empty set of partitions. The methods [execute][crate::Statement::execute],
381    /// [execute_schema][crate::Statement::execute_schema] and
382    /// [execute_update][crate::Statement::execute_update] are not affected.
383    ///
384    /// # Since
385    ///
386    /// ADBC API revision 1.1.0
387    Incremental,
388    /// Get the progress of a query. It's a read-only option that should be
389    /// read with [get_option_double][crate::Optionable::get_option_double].
390    ///
391    /// The value is not necessarily in any particular range or have any
392    /// particular units. For example, it might be a percentage, bytes of data,
393    /// rows of data, number of workers, etc. The max value can be retrieved
394    /// via [OptionStatement::MaxProgress]. This represents the progress of
395    /// execution, not of consumption (i.e., it is independent of how much of the
396    /// result set has been read by the client).
397    ///
398    /// # Since
399    ///
400    /// ADBC API revision 1.1.0
401    Progress,
402    /// Get the maximum progress of a query. It's a read-only option that should be
403    /// read with [get_option_double][crate::Optionable::get_option_double].
404    ///
405    /// This is the value of [OptionStatement::Progress] for a completed query.
406    /// If not supported, or if the value is nonpositive, then the maximum is not
407    /// known. For instance, the query may be fully streaming and the driver
408    /// does not know when the result set will end.
409    ///
410    /// # Since
411    ///
412    /// ADBC API revision 1.1.0
413    MaxProgress,
414    /// Driver-specific key.
415    Other(String),
416}
417
418impl AsRef<str> for OptionStatement {
419    fn as_ref(&self) -> &str {
420        match self {
421            Self::IngestMode => constants::ADBC_INGEST_OPTION_MODE,
422            Self::TargetTable => constants::ADBC_INGEST_OPTION_TARGET_TABLE,
423            Self::TargetCatalog => constants::ADBC_INGEST_OPTION_TARGET_CATALOG,
424            Self::TargetDbSchema => constants::ADBC_INGEST_OPTION_TARGET_DB_SCHEMA,
425            Self::Temporary => constants::ADBC_INGEST_OPTION_TEMPORARY,
426            Self::Incremental => constants::ADBC_STATEMENT_OPTION_INCREMENTAL,
427            Self::Progress => constants::ADBC_STATEMENT_OPTION_PROGRESS,
428            Self::MaxProgress => constants::ADBC_STATEMENT_OPTION_MAX_PROGRESS,
429            Self::Other(key) => key,
430        }
431    }
432}
433
434impl From<&str> for OptionStatement {
435    fn from(value: &str) -> Self {
436        match value {
437            constants::ADBC_INGEST_OPTION_MODE => Self::IngestMode,
438            constants::ADBC_INGEST_OPTION_TARGET_TABLE => Self::TargetTable,
439            constants::ADBC_INGEST_OPTION_TARGET_CATALOG => Self::TargetCatalog,
440            constants::ADBC_INGEST_OPTION_TARGET_DB_SCHEMA => Self::TargetDbSchema,
441            constants::ADBC_INGEST_OPTION_TEMPORARY => Self::Temporary,
442            constants::ADBC_STATEMENT_OPTION_INCREMENTAL => Self::Incremental,
443            constants::ADBC_STATEMENT_OPTION_PROGRESS => Self::Progress,
444            constants::ADBC_STATEMENT_OPTION_MAX_PROGRESS => Self::MaxProgress,
445            key => Self::Other(key.into()),
446        }
447    }
448}
449
450/// Isolation level value for key [OptionConnection::IsolationLevel].
451#[derive(Debug)]
452pub enum IsolationLevel {
453    /// Use database or driver default isolation level.
454    Default,
455    /// The lowest isolation level. Dirty reads are allowed, so one transaction
456    /// may see not-yet-committed changes made by others.
457    ReadUncommitted,
458    /// Lock-based concurrency control keeps write locks until the end of the
459    /// transaction, but read locks are released as soon as a SELECT is
460    /// performed. Non-repeatable reads can occur in this isolation level.
461    ///
462    /// More simply put, `ReadCommitted` is an isolation level that guarantees
463    /// that any data read is committed at the moment it is read. It simply
464    /// restricts the reader from seeing any intermediate, uncommitted,
465    /// 'dirty' reads. It makes no promise whatsoever that if the transaction
466    /// re-issues the read, it will find the same data; data is free to change
467    /// after it is read.
468    ReadCommitted,
469    /// Lock-based concurrency control keeps read AND write locks (acquired on
470    /// selection data) until the end of the transaction.
471    ///
472    /// However, range-locks are not managed, so phantom reads can occur.
473    /// Write skew is possible at this isolation level in some systems.
474    RepeatableRead,
475    /// This isolation guarantees that all reads in the transaction will see a
476    /// consistent snapshot of the database and the transaction should only
477    /// successfully commit if no updates conflict with any concurrent updates
478    /// made since that snapshot.
479    Snapshot,
480    /// Serializability requires read and write locks to be released only at the
481    /// end of the transaction. This includes acquiring range-locks when a
482    /// select query uses a ranged WHERE clause to avoid phantom reads.
483    Serializable,
484    /// The central distinction between serializability and linearizability is
485    /// that serializability is a global property; a property of an entire
486    /// history of operations and transactions. Linearizability is a local
487    /// property; a property of a single operation/transaction.
488    ///
489    /// Linearizability can be viewed as a special case of strict serializability
490    /// where transactions are restricted to consist of a single operation applied
491    /// to a single object.
492    Linearizable,
493}
494
495impl From<IsolationLevel> for String {
496    fn from(value: IsolationLevel) -> Self {
497        match value {
498            IsolationLevel::Default => constants::ADBC_OPTION_ISOLATION_LEVEL_DEFAULT.into(),
499            IsolationLevel::ReadUncommitted => {
500                constants::ADBC_OPTION_ISOLATION_LEVEL_READ_UNCOMMITTED.into()
501            }
502            IsolationLevel::ReadCommitted => {
503                constants::ADBC_OPTION_ISOLATION_LEVEL_READ_COMMITTED.into()
504            }
505            IsolationLevel::RepeatableRead => {
506                constants::ADBC_OPTION_ISOLATION_LEVEL_REPEATABLE_READ.into()
507            }
508            IsolationLevel::Snapshot => constants::ADBC_OPTION_ISOLATION_LEVEL_SNAPSHOT.into(),
509            IsolationLevel::Serializable => {
510                constants::ADBC_OPTION_ISOLATION_LEVEL_SERIALIZABLE.into()
511            }
512            IsolationLevel::Linearizable => {
513                constants::ADBC_OPTION_ISOLATION_LEVEL_LINEARIZABLE.into()
514            }
515        }
516    }
517}
518
519impl From<IsolationLevel> for OptionValue {
520    fn from(value: IsolationLevel) -> Self {
521        Self::String(value.into())
522    }
523}
524
525/// Ingestion mode value for key [OptionStatement::IngestMode].
526#[derive(Debug)]
527pub enum IngestMode {
528    /// Create the table and insert data; error if the table exists.
529    Create,
530    /// Do not create the table, and insert data; error if the table does not
531    /// exist ([Status::NotFound]) or does not match the schema of the data to
532    /// append ([Status::AlreadyExists]).
533    Append,
534    /// Create the table and insert data; drop the original table if it already
535    /// exists.
536    ///
537    /// # Since
538    ///
539    /// ADBC API revision 1.1.0
540    Replace,
541    /// Insert data; create the table if it does not exist, or error if the
542    /// table exists, but the schema does not match the schema of the data to
543    /// append ([Status::AlreadyExists]).
544    ///
545    /// # Since
546    ///
547    /// ADBC API revision 1.1.0
548    CreateAppend,
549}
550
551impl From<IngestMode> for String {
552    fn from(value: IngestMode) -> Self {
553        match value {
554            IngestMode::Create => constants::ADBC_INGEST_OPTION_MODE_CREATE.into(),
555            IngestMode::Append => constants::ADBC_INGEST_OPTION_MODE_APPEND.into(),
556            IngestMode::Replace => constants::ADBC_INGEST_OPTION_MODE_REPLACE.into(),
557            IngestMode::CreateAppend => constants::ADBC_INGEST_OPTION_MODE_CREATE_APPEND.into(),
558        }
559    }
560}
561impl From<IngestMode> for OptionValue {
562    fn from(value: IngestMode) -> Self {
563        Self::String(value.into())
564    }
565}
566
567/// Statistics about the data distribution.
568#[derive(Debug, Clone)]
569pub enum Statistics {
570    /// The average byte width statistic. The average size in bytes of a row in
571    /// the column. Value type is `float64`. For example, this is roughly the
572    /// average length of a string for a string column.
573    AverageByteWidth,
574    /// The distinct value count (NDV) statistic. The number of distinct values
575    /// in the column. Value type is `int64` (when not approximate) or `float64`
576    /// (when approximate).
577    DistinctCount,
578    /// The max byte width statistic. The maximum size in bytes of a row in the
579    /// column. Value type is `int64` (when not approximate) or `float64` (when approximate).
580    /// For example, this is the maximum length of a string for a string column.
581    MaxByteWidth,
582    /// The max value statistic. Value type is column-dependent.
583    MaxValue,
584    /// The min value statistic. Value type is column-dependent.
585    MinValue,
586    /// The null count statistic. The number of values that are null in the
587    /// column. Value type is `int64` (when not approximate) or `float64` (when approximate).
588    NullCount,
589    /// The row count statistic. The number of rows in the column or table.
590    /// Value type is `int64` (when not approximate) or `float64` (when approximate).
591    RowCount,
592    /// Driver-specific statistics.
593    Other { key: i16, name: String },
594}
595
596impl TryFrom<i16> for Statistics {
597    type Error = Error;
598    fn try_from(value: i16) -> Result<Self, Self::Error> {
599        match value {
600            constants::ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_KEY => Ok(Self::AverageByteWidth),
601            constants::ADBC_STATISTIC_DISTINCT_COUNT_KEY => Ok(Self::DistinctCount),
602            constants::ADBC_STATISTIC_MAX_BYTE_WIDTH_KEY => Ok(Self::MaxByteWidth),
603            constants::ADBC_STATISTIC_MAX_VALUE_KEY => Ok(Self::MaxValue),
604            constants::ADBC_STATISTIC_MIN_VALUE_KEY => Ok(Self::MinValue),
605            constants::ADBC_STATISTIC_NULL_COUNT_KEY => Ok(Self::NullCount),
606            constants::ADBC_STATISTIC_ROW_COUNT_KEY => Ok(Self::RowCount),
607            _ => Err(Error::with_message_and_status(
608                format!("Unknown standard statistic key: {value}"),
609                Status::InvalidArguments,
610            )),
611        }
612    }
613}
614
615impl From<Statistics> for i16 {
616    fn from(value: Statistics) -> Self {
617        match value {
618            Statistics::AverageByteWidth => constants::ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_KEY,
619            Statistics::DistinctCount => constants::ADBC_STATISTIC_DISTINCT_COUNT_KEY,
620            Statistics::MaxByteWidth => constants::ADBC_STATISTIC_MAX_BYTE_WIDTH_KEY,
621            Statistics::MaxValue => constants::ADBC_STATISTIC_MAX_VALUE_KEY,
622            Statistics::MinValue => constants::ADBC_STATISTIC_MIN_VALUE_KEY,
623            Statistics::NullCount => constants::ADBC_STATISTIC_NULL_COUNT_KEY,
624            Statistics::RowCount => constants::ADBC_STATISTIC_ROW_COUNT_KEY,
625            Statistics::Other { key, name: _ } => key,
626        }
627    }
628}
629
630impl AsRef<str> for Statistics {
631    fn as_ref(&self) -> &str {
632        match self {
633            Statistics::AverageByteWidth => constants::ADBC_STATISTIC_AVERAGE_BYTE_WIDTH_NAME,
634            Statistics::DistinctCount => constants::ADBC_STATISTIC_DISTINCT_COUNT_NAME,
635            Statistics::MaxByteWidth => constants::ADBC_STATISTIC_MAX_BYTE_WIDTH_NAME,
636            Statistics::MaxValue => constants::ADBC_STATISTIC_MAX_VALUE_NAME,
637            Statistics::MinValue => constants::ADBC_STATISTIC_MIN_VALUE_NAME,
638            Statistics::NullCount => constants::ADBC_STATISTIC_NULL_COUNT_NAME,
639            Statistics::RowCount => constants::ADBC_STATISTIC_ROW_COUNT_NAME,
640            Statistics::Other { key: _, name } => name,
641        }
642    }
643}
644
645impl std::fmt::Display for Statistics {
646    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
647        write!(f, "{}", self.as_ref())
648    }
649}