zero_mysql/protocol/command/
column_definition.rs1use crate::constant::{ColumnFlags, ColumnType};
2use crate::error::{Error, Result, eyre};
3use crate::protocol::primitive::*;
4use zerocopy::byteorder::little_endian::{U16 as U16LE, U32 as U32LE};
5use zerocopy::{FromBytes, Immutable, KnownLayout};
6
7#[derive(Debug, Clone, Copy)]
9pub struct ColumnDefinitionBytes<'a>(pub &'a [u8]);
10
11impl<'a> ColumnDefinitionBytes<'a> {
12 pub fn tail(&self) -> Result<&'a ColumnDefinitionTail> {
16 if self.0.len() < 12 {
17 return Err(Error::LibraryBug(eyre!(
18 "column definition too short: {} < 12",
19 self.0.len()
20 )));
21 }
22 let tail_bytes = &self.0[self.0.len() - 12..];
23 Ok(ColumnDefinitionTail::ref_from_bytes(tail_bytes)?)
24 }
25}
26
27#[derive(Debug, Clone)]
29pub struct ColumnDefinition<'a> {
30 pub schema: &'a [u8],
31 pub table_alias: &'a [u8],
32 pub table_original: &'a [u8],
33 pub name_alias: &'a [u8],
34 pub name_original: &'a [u8],
35 pub tail: &'a ColumnDefinitionTail,
36}
37
38impl<'a> TryFrom<ColumnDefinitionBytes<'a>> for ColumnDefinition<'a> {
39 type Error = Error;
40
41 fn try_from(bytes: ColumnDefinitionBytes<'a>) -> Result<Self> {
42 let data = bytes.0;
43
44 let (_catalog, data) = read_string_lenenc(data)?;
46 let (schema, data) = read_string_lenenc(data)?;
47 let (table_alias, data) = read_string_lenenc(data)?;
48 let (table_original, data) = read_string_lenenc(data)?;
49 let (name_alias, data) = read_string_lenenc(data)?;
50 let (name_original, data) = read_string_lenenc(data)?;
51
52 let (_length, data) = read_int_lenenc(data)?;
55 let tail = ColumnDefinitionTail::ref_from_bytes(data)?;
56 Ok(Self {
57 schema,
59 table_alias,
60 table_original,
61 name_alias,
62 name_original,
63 tail,
64 })
65 }
66}
67
68#[repr(C, packed)]
70#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)]
71pub struct ColumnDefinitionTail {
72 charset: U16LE,
73 column_length: U32LE,
74 column_type: u8,
75 flags: U16LE,
76 decimals: u8,
77 reserved: U16LE,
78}
79
80impl ColumnDefinitionTail {
81 pub fn charset(&self) -> u16 {
82 self.charset.get()
83 }
84
85 pub fn column_length(&self) -> u32 {
86 self.column_length.get()
87 }
88
89 pub fn column_type(&self) -> Result<ColumnType> {
90 ColumnType::from_u8(self.column_type).ok_or_else(|| {
91 Error::LibraryBug(eyre!("unknown column type: 0x{:02X}", self.column_type))
92 })
93 }
94
95 pub fn flags(&self) -> Result<ColumnFlags> {
96 ColumnFlags::from_bits(self.flags.get()).ok_or_else(|| {
97 Error::LibraryBug(eyre!("invalid column flags: 0x{:04X}", self.flags.get()))
98 })
99 }
100}
101
102pub struct ColumnDefinitions {
103 _packets: Vec<u8>, definitions: Vec<ColumnDefinition<'static>>,
105}
106
107impl ColumnDefinitions {
108 pub fn new(num_columns: usize, packets: Vec<u8>) -> Result<Self> {
109 let definitions = {
110 let mut buf = packets.as_slice();
111 let mut definitions = Vec::with_capacity(num_columns);
112 for _ in 0..num_columns {
113 let len = u32::from_ne_bytes(buf[..4].try_into().unwrap()) as usize;
114 definitions.push(ColumnDefinition::try_from(ColumnDefinitionBytes(
115 &buf[4..4 + len],
116 ))?);
117 buf = &buf[4 + len..]; }
119
120 unsafe {
122 std::mem::transmute::<Vec<ColumnDefinition<'_>>, Vec<ColumnDefinition<'static>>>(
123 definitions,
124 )
125 }
126 };
127
128 Ok(Self {
129 _packets: packets,
130 definitions,
131 })
132 }
133
134 pub fn definitions<'a>(&'a self) -> &'a [ColumnDefinition<'a>] {
135 self.definitions.as_slice()
136 }
137}