sqlx_core/column.rs
1use crate::database::Database;
2use crate::error::Error;
3
4use std::fmt::Debug;
5use std::sync::Arc;
6
7pub trait Column: 'static + Send + Sync + Debug {
8 type Database: Database<Column = Self>;
9
10 /// Gets the column ordinal.
11 ///
12 /// This can be used to unambiguously refer to this column within a row in case more than
13 /// one column have the same name
14 fn ordinal(&self) -> usize;
15
16 /// Gets the column name or alias.
17 ///
18 /// The column name is unreliable (and can change between database minor versions) if this
19 /// column is an expression that has not been aliased.
20 fn name(&self) -> &str;
21
22 /// Gets the type information for the column.
23 fn type_info(&self) -> &<Self::Database as Database>::TypeInfo;
24
25 /// If this column comes from a table, return the table and original column name.
26 ///
27 /// Returns [`ColumnOrigin::Expression`] if the column is the result of an expression
28 /// or else the source table could not be determined.
29 ///
30 /// Returns [`ColumnOrigin::Unknown`] if the database driver does not have that information,
31 /// or has not overridden this method.
32 // This method returns an owned value instead of a reference,
33 // to give the implementor more flexibility.
34 fn origin(&self) -> ColumnOrigin {
35 ColumnOrigin::Unknown
36 }
37}
38
39/// A [`Column`] that originates from a table.
40#[derive(Debug, Clone)]
41#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
42pub struct TableColumn {
43 /// The name of the table (optionally schema-qualified) that the column comes from.
44 pub table: Arc<str>,
45 /// The original name of the column.
46 pub name: Arc<str>,
47}
48
49/// The possible statuses for our knowledge of the origin of a [`Column`].
50#[derive(Debug, Clone, Default)]
51#[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))]
52pub enum ColumnOrigin {
53 /// The column is known to originate from a table.
54 ///
55 /// Included is the table name and original column name.
56 Table(TableColumn),
57 /// The column originates from an expression, or else its origin could not be determined.
58 Expression,
59 /// The database driver does not know the column origin at this time.
60 ///
61 /// This may happen if:
62 /// * The connection is in the middle of executing a query,
63 /// and cannot query the catalog to fetch this information.
64 /// * The connection does not have access to the database catalog.
65 /// * The implementation of [`Column`] did not override [`Column::origin()`].
66 #[default]
67 Unknown,
68}
69
70impl ColumnOrigin {
71 /// Returns the true column origin, if known.
72 pub fn table_column(&self) -> Option<&TableColumn> {
73 if let Self::Table(table_column) = self {
74 Some(table_column)
75 } else {
76 None
77 }
78 }
79}
80
81/// A type that can be used to index into a [`Row`] or [`Statement`].
82///
83/// The [`get`] and [`try_get`] methods of [`Row`] accept any type that implements `ColumnIndex`.
84/// This trait is implemented for strings which are used to look up a column by name, and for
85/// `usize` which is used as a positional index into the row.
86///
87/// *Caution*: The column index may differ between a [`Statement`] and a [`Row`] returned by the
88/// statement. This can happen with some databases if, for example, the schema changes between
89/// prepare and execute or if the database does not provide column information when the statement
90/// is prepared.
91///
92/// [`Row`]: crate::row::Row
93/// [`Statement`]: crate::statement::Statement
94/// [`get`]: crate::row::Row::get
95/// [`try_get`]: crate::row::Row::try_get
96///
97pub trait ColumnIndex<T: ?Sized>: Debug {
98 /// Returns a valid positional index into the row or statement, [`ColumnIndexOutOfBounds`], or,
99 /// [`ColumnNotFound`].
100 ///
101 /// [`ColumnNotFound`]: Error::ColumnNotFound
102 /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds
103 fn index(&self, container: &T) -> Result<usize, Error>;
104}
105
106impl<T: ?Sized, I: ColumnIndex<T> + ?Sized> ColumnIndex<T> for &'_ I {
107 #[inline]
108 fn index(&self, row: &T) -> Result<usize, Error> {
109 (**self).index(row)
110 }
111}
112
113#[macro_export]
114macro_rules! impl_column_index_for_row {
115 ($R:ident) => {
116 impl $crate::column::ColumnIndex<$R> for usize {
117 fn index(&self, row: &$R) -> Result<usize, $crate::error::Error> {
118 let len = $crate::row::Row::len(row);
119
120 if *self >= len {
121 return Err($crate::error::Error::ColumnIndexOutOfBounds { len, index: *self });
122 }
123
124 Ok(*self)
125 }
126 }
127 };
128}
129
130#[macro_export]
131macro_rules! impl_column_index_for_statement {
132 ($S:ident) => {
133 impl $crate::column::ColumnIndex<$S> for usize {
134 fn index(&self, statement: &$S) -> Result<usize, $crate::error::Error> {
135 let len = $crate::statement::Statement::columns(statement).len();
136
137 if *self >= len {
138 return Err($crate::error::Error::ColumnIndexOutOfBounds { len, index: *self });
139 }
140
141 Ok(*self)
142 }
143 }
144 };
145}