1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
use crate::protocol::parts::type_id::TypeId;
use std::sync::Arc;
use vec_map::VecMap;
// The structure is a bit weird; reason is that we want to retain the transfer format
// which seeks to avoid String duplication
/// Metadata of a field in a `ResultSet`.
#[derive(Clone, Debug)]
pub struct FieldMetadata {
inner: InnerFieldMetadata,
names: Arc<VecMap<String>>,
}
/// Describes a single field (column) in a result set.
#[derive(Clone, Copy, Debug)]
pub(crate) struct InnerFieldMetadata {
schemaname_idx: u32,
tablename_idx: u32,
columnname_idx: u32,
displayname_idx: u32,
// Column_options.
// Bit pattern:
// 0 = Mandatory
// 1 = Optional
// 2 = Default
// 3 = Escape_char
// 4 = Readonly
// 5 = Autoincrement
// 6 = ArrayType
column_options: u8,
type_id: TypeId,
// scale
scale: i16,
// Precision
precision: i16,
}
impl InnerFieldMetadata {
#[allow(clippy::too_many_arguments)]
pub fn new(
schemaname_idx: u32,
tablename_idx: u32,
columnname_idx: u32,
displayname_idx: u32,
column_options: u8,
type_id: TypeId,
scale: i16,
precision: i16,
) -> Self {
Self {
schemaname_idx,
tablename_idx,
columnname_idx,
displayname_idx,
column_options,
type_id,
scale,
precision,
}
}
}
impl FieldMetadata {
pub(crate) fn new(inner: InnerFieldMetadata, names: Arc<VecMap<String>>) -> Self {
Self { inner, names }
}
/// Database schema of the field.
pub fn schemaname(&self) -> &str {
self.names
.get(self.inner.schemaname_idx as usize)
.map_or("", String::as_str)
}
/// Database table.
pub fn tablename(&self) -> &str {
self.names
.get(self.inner.tablename_idx as usize)
.map_or("", String::as_str)
}
/// Column name.
pub fn columnname(&self) -> &str {
self.names
.get(self.inner.columnname_idx as usize)
.map_or("", String::as_str)
}
/// Display name of the column.
pub fn displayname(&self) -> &str {
self.names
.get(self.inner.displayname_idx as usize)
.map_or("", String::as_str)
}
/// Returns the id of the value type.
pub fn type_id(&self) -> TypeId {
self.inner.type_id
}
// Returns true for BLOB, CLOB, and NCLOB, and false otherwise.
pub(crate) fn is_lob(&self) -> bool {
matches!(
self.inner.type_id,
TypeId::BLOB | TypeId::CLOB | TypeId::NCLOB
)
}
/// True if column can contain NULL values.
pub fn is_nullable(&self) -> bool {
(self.inner.column_options & 0b_0000_0010_u8) != 0
}
/// The length or the precision of the value.
///
/// Is `-1` for LOB types.
pub fn precision(&self) -> i16 {
self.inner.precision
}
/// The scale of the value.
///
/// Is `0` for all types where a scale does not make sense.
pub fn scale(&self) -> i16 {
self.inner.scale
}
/// Returns true if the column has a default value.
pub fn has_default(&self) -> bool {
(self.inner.column_options & 0b_0000_0100_u8) != 0
}
/// Returns true if the column is read-only.
pub fn is_read_only(&self) -> bool {
(self.inner.column_options & 0b_0100_0000_u8) != 0
}
/// Returns true if the column is auto-incremented.
pub fn is_auto_incremented(&self) -> bool {
(self.inner.column_options & 0b_0010_0000_u8) != 0
}
/// Returns true if the column is of array type.
pub fn is_array_type(&self) -> bool {
(self.inner.column_options & 0b_0100_0000_u8) != 0
}
}