/
germanubis
/
sqlx
Обзор
Документация
Войти
/
germanubis
/
sqlx
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
sqlx-mysql/src/protocol/text/column.rs
266 строк
8 KB
Joey de Waal
fix spelling (#4069)
28 окт 2025, 15:18
Не верифицирован
28 окт 2025, 15:18
e8384f2
Код
Авторство
О чём код?
use std::str; use crate::collation::Collation; use crate::error::Error; use crate::io::MySqlBufExt; use crate::io::ProtocolDecode; use crate::protocol::Capabilities; use bitflags::bitflags; use bytes::{Buf, Bytes}; // https://dev.mysql.com/doc/dev/mysql-server/8.0.12/group__group__cs__column__definition__flags.html bitflags! { #[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub(crate) struct ColumnFlags: u16 { /// Field can't be `NULL`. const NOT_NULL = 1; /// Field is part of a primary key. const PRIMARY_KEY = 2; /// Field is part of a unique key. const UNIQUE_KEY = 4; /// Field is part of a multi-part unique or primary key. const MULTIPLE_KEY = 8; /// Field is a blob. const BLOB = 16; /// Field is unsigned. const UNSIGNED = 32; /// Field is zero filled. const ZEROFILL = 64; /// Field is binary. const BINARY = 128; /// Field is an enumeration. const ENUM = 256; /// Field is an auto-increment field. const AUTO_INCREMENT = 512; /// Field is a timestamp. const TIMESTAMP = 1024; /// Field is a set. const SET = 2048; /// Field does not have a default value. const NO_DEFAULT_VALUE = 4096; /// Field is set to NOW on UPDATE. const ON_UPDATE_NOW = 8192; /// Field is a number. const NUM = 32768; } } // https://dev.mysql.com/doc/internals/en/com-query-response.html#column-type #[derive(Debug, Copy, Clone, PartialEq)] #[cfg_attr(feature = "offline", derive(serde::Serialize, serde::Deserialize))] #[repr(u8)] pub enum ColumnType { Decimal = 0x00, Tiny = 0x01, Short = 0x02, Long = 0x03, Float = 0x04, Double = 0x05, Null = 0x06, Timestamp = 0x07, LongLong = 0x08, Int24 = 0x09, Date = 0x0a, Time = 0x0b, Datetime = 0x0c, Year = 0x0d, VarChar = 0x0f, Bit = 0x10, Json = 0xf5, NewDecimal = 0xf6, Enum = 0xf7, Set = 0xf8, TinyBlob = 0xf9, MediumBlob = 0xfa, LongBlob = 0xfb, Blob = 0xfc, VarString = 0xfd, String = 0xfe, Geometry = 0xff, } // https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_com_query_response_text_resultset_column_definition.html // https://mariadb.com/kb/en/resultset/#column-definition-packet // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41 #[derive(Debug)] pub(crate) struct ColumnDefinition { #[allow(unused)] catalog: Bytes, schema: Bytes, #[allow(unused)] table_alias: Bytes, table: Bytes, alias: Bytes, name: Bytes, pub(crate) collation: Collation, pub(crate) max_size: u32, pub(crate) r#type: ColumnType, pub(crate) flags: ColumnFlags, #[allow(unused)] decimals: u8, } impl ColumnDefinition { // NOTE: strings in-protocol are transmitted according to the client character set // as this is UTF-8, all these strings should be UTF-8 pub(crate) fn schema(&self) -> Result<&str, Error> { str::from_utf8(&self.schema).map_err(Error::protocol) } pub(crate) fn table(&self) -> Result<&str, Error> { str::from_utf8(&self.table).map_err(Error::protocol) } pub(crate) fn name(&self) -> Result<&str, Error> { str::from_utf8(&self.name).map_err(Error::protocol) } pub(crate) fn alias(&self) -> Result<&str, Error> { str::from_utf8(&self.alias).map_err(Error::protocol) } } impl ProtocolDecode<'_, Capabilities> for ColumnDefinition { fn decode_with(mut buf: Bytes, _: Capabilities) -> Result<Self, Error> { let catalog = buf.get_bytes_lenenc()?; let schema = buf.get_bytes_lenenc()?; let table_alias = buf.get_bytes_lenenc()?; let table = buf.get_bytes_lenenc()?; let alias = buf.get_bytes_lenenc()?; let name = buf.get_bytes_lenenc()?; let _next_len = buf.get_uint_lenenc(); // always 0x0c let collation = buf.get_u16_le(); let max_size = buf.get_u32_le(); let type_id = buf.get_u8(); let flags = buf.get_u16_le(); let decimals = buf.get_u8(); Ok(Self { catalog, schema, table_alias, table, alias, name, collation: Collation(collation), max_size, r#type: ColumnType::try_from_u16(type_id)?, flags: ColumnFlags::from_bits_truncate(flags), decimals, }) } } impl ColumnType { pub(crate) fn name(self, flags: ColumnFlags, max_size: Option<u32>) -> &'static str { let is_binary = flags.contains(ColumnFlags::BINARY); let is_unsigned = flags.contains(ColumnFlags::UNSIGNED); let is_enum = flags.contains(ColumnFlags::ENUM); match self { ColumnType::Tiny if max_size == Some(1) => "BOOLEAN", ColumnType::Tiny if is_unsigned => "TINYINT UNSIGNED", ColumnType::Short if is_unsigned => "SMALLINT UNSIGNED", ColumnType::Long if is_unsigned => "INT UNSIGNED", ColumnType::Int24 if is_unsigned => "MEDIUMINT UNSIGNED", ColumnType::LongLong if is_unsigned => "BIGINT UNSIGNED", ColumnType::Tiny => "TINYINT", ColumnType::Short => "SMALLINT", ColumnType::Long => "INT", ColumnType::Int24 => "MEDIUMINT", ColumnType::LongLong => "BIGINT", ColumnType::Float => "FLOAT", ColumnType::Double => "DOUBLE", ColumnType::Null => "NULL", ColumnType::Timestamp => "TIMESTAMP", ColumnType::Date => "DATE", ColumnType::Time => "TIME", ColumnType::Datetime => "DATETIME", ColumnType::Year => "YEAR", ColumnType::Bit => "BIT", ColumnType::Enum => "ENUM", ColumnType::Set => "SET", ColumnType::Decimal | ColumnType::NewDecimal => "DECIMAL", ColumnType::Geometry => "GEOMETRY", ColumnType::Json => "JSON", ColumnType::String if is_binary => "BINARY", ColumnType::String if is_enum => "ENUM", ColumnType::VarChar | ColumnType::VarString if is_binary => "VARBINARY", ColumnType::String => "CHAR", ColumnType::VarChar | ColumnType::VarString => "VARCHAR", ColumnType::TinyBlob if is_binary => "TINYBLOB", ColumnType::TinyBlob => "TINYTEXT", ColumnType::Blob if is_binary => "BLOB", ColumnType::Blob => "TEXT", ColumnType::MediumBlob if is_binary => "MEDIUMBLOB", ColumnType::MediumBlob => "MEDIUMTEXT", ColumnType::LongBlob if is_binary => "LONGBLOB", ColumnType::LongBlob => "LONGTEXT", } } pub(crate) fn try_from_u16(id: u8) -> Result<Self, Error> { Ok(match id { 0x00 => ColumnType::Decimal, 0x01 => ColumnType::Tiny, 0x02 => ColumnType::Short, 0x03 => ColumnType::Long, 0x04 => ColumnType::Float, 0x05 => ColumnType::Double, 0x06 => ColumnType::Null, 0x07 => ColumnType::Timestamp, 0x08 => ColumnType::LongLong, 0x09 => ColumnType::Int24, 0x0a => ColumnType::Date, 0x0b => ColumnType::Time, 0x0c => ColumnType::Datetime, 0x0d => ColumnType::Year, // [internal] 0x0e => ColumnType::NewDate, 0x0f => ColumnType::VarChar, 0x10 => ColumnType::Bit, // [internal] 0x11 => ColumnType::Timestamp2, // [internal] 0x12 => ColumnType::Datetime2, // [internal] 0x13 => ColumnType::Time2, 0xf5 => ColumnType::Json, 0xf6 => ColumnType::NewDecimal, 0xf7 => ColumnType::Enum, 0xf8 => ColumnType::Set, 0xf9 => ColumnType::TinyBlob, 0xfa => ColumnType::MediumBlob, 0xfb => ColumnType::LongBlob, 0xfc => ColumnType::Blob, 0xfd => ColumnType::VarString, 0xfe => ColumnType::String, 0xff => ColumnType::Geometry, _ => { return Err(err_protocol!("unknown column type 0x{:02x}", id)); } }) } }