1use std::fmt;
2
3use arrow::array::Array as _;
4use arrow::datatypes::{DataType, Field, TimeUnit};
5use datafusion::common::ScalarValue;
6
7use crate::SqlError;
8
9#[derive(Clone, Debug, Eq, PartialEq)]
11pub enum SqlType {
12 Null,
14 Boolean,
16 SignedInteger(u8),
18 UnsignedInteger(u8),
20 Float(u8),
22 TimestampMillis(Option<String>),
24 Text,
26 Bytes,
28 List(Box<Self>),
30 Other(String),
32}
33
34impl SqlType {
35 pub(crate) fn from_arrow(data_type: &DataType) -> Self {
36 match data_type {
37 DataType::Null => Self::Null,
38 DataType::Boolean => Self::Boolean,
39 DataType::Int8 => Self::SignedInteger(8),
40 DataType::Int16 => Self::SignedInteger(16),
41 DataType::Int32 => Self::SignedInteger(32),
42 DataType::Int64 => Self::SignedInteger(64),
43 DataType::UInt8 => Self::UnsignedInteger(8),
44 DataType::UInt16 => Self::UnsignedInteger(16),
45 DataType::UInt32 => Self::UnsignedInteger(32),
46 DataType::UInt64 => Self::UnsignedInteger(64),
47 DataType::Float16 => Self::Float(16),
48 DataType::Float32 => Self::Float(32),
49 DataType::Float64 => Self::Float(64),
50 DataType::Timestamp(TimeUnit::Millisecond, timezone) => {
51 Self::TimestampMillis(timezone.as_ref().map(ToString::to_string))
52 }
53 DataType::Utf8 | DataType::LargeUtf8 | DataType::Utf8View => Self::Text,
54 DataType::Binary
55 | DataType::LargeBinary
56 | DataType::BinaryView
57 | DataType::FixedSizeBinary(_) => Self::Bytes,
58 DataType::List(field) | DataType::LargeList(field) => {
59 Self::List(Box::new(Self::from_arrow(field.data_type())))
60 }
61 other => Self::Other(other.to_string()),
62 }
63 }
64}
65
66#[derive(Clone, Debug, Eq, PartialEq)]
68pub struct SqlColumn {
69 pub name: String,
71 pub data_type: SqlType,
73 pub nullable: bool,
75}
76
77impl SqlColumn {
78 pub(crate) fn from_arrow(field: &Field) -> Self {
79 Self {
80 name: field.name().clone(),
81 data_type: SqlType::from_arrow(field.data_type()),
82 nullable: field.is_nullable(),
83 }
84 }
85}
86
87#[derive(Clone, Debug, PartialEq)]
89pub enum SqlValue {
90 Null,
92 Boolean(bool),
94 Integer(i64),
96 Unsigned(u64),
98 Float(f64),
100 TimestampMillis(i64),
102 Text(String),
104 Bytes(Vec<u8>),
106 List(Vec<Self>),
109 Other(String),
111}
112
113pub type SqlRow = Vec<SqlValue>;
115
116impl SqlValue {
117 pub(crate) fn from_scalar(value: ScalarValue) -> Result<Self, SqlError> {
118 Ok(match value {
119 ScalarValue::Null
120 | ScalarValue::Boolean(None)
121 | ScalarValue::Int8(None)
122 | ScalarValue::Int16(None)
123 | ScalarValue::Int32(None)
124 | ScalarValue::Int64(None)
125 | ScalarValue::UInt8(None)
126 | ScalarValue::UInt16(None)
127 | ScalarValue::UInt32(None)
128 | ScalarValue::UInt64(None)
129 | ScalarValue::Float16(None)
130 | ScalarValue::Float32(None)
131 | ScalarValue::Float64(None)
132 | ScalarValue::Utf8(None)
133 | ScalarValue::Utf8View(None)
134 | ScalarValue::LargeUtf8(None)
135 | ScalarValue::Binary(None)
136 | ScalarValue::BinaryView(None)
137 | ScalarValue::LargeBinary(None)
138 | ScalarValue::TimestampMillisecond(None, _)
139 | ScalarValue::FixedSizeBinary(_, None) => Self::Null,
140 ScalarValue::Boolean(Some(value)) => Self::Boolean(value),
141 ScalarValue::Int8(Some(value)) => Self::Integer(i64::from(value)),
142 ScalarValue::Int16(Some(value)) => Self::Integer(i64::from(value)),
143 ScalarValue::Int32(Some(value)) => Self::Integer(i64::from(value)),
144 ScalarValue::Int64(Some(value)) => Self::Integer(value),
145 ScalarValue::UInt8(Some(value)) => Self::Unsigned(u64::from(value)),
146 ScalarValue::UInt16(Some(value)) => Self::Unsigned(u64::from(value)),
147 ScalarValue::UInt32(Some(value)) => Self::Unsigned(u64::from(value)),
148 ScalarValue::UInt64(Some(value)) => Self::Unsigned(value),
149 ScalarValue::Float16(Some(value)) => Self::Float(f64::from(value)),
150 ScalarValue::Float32(Some(value)) => Self::Float(f64::from(value)),
151 ScalarValue::Float64(Some(value)) => Self::Float(value),
152 ScalarValue::TimestampMillisecond(Some(value), _) => Self::TimestampMillis(value),
153 ScalarValue::Utf8(Some(value))
154 | ScalarValue::Utf8View(Some(value))
155 | ScalarValue::LargeUtf8(Some(value)) => Self::Text(value),
156 ScalarValue::Binary(Some(value))
157 | ScalarValue::BinaryView(Some(value))
158 | ScalarValue::LargeBinary(Some(value))
159 | ScalarValue::FixedSizeBinary(_, Some(value)) => Self::Bytes(value),
160 ScalarValue::List(array) => {
161 if array.is_null(0) {
162 Self::Null
163 } else {
164 let values = array.value(0);
165 let mut result = Vec::with_capacity(values.len());
166 for index in 0..values.len() {
167 result.push(Self::from_scalar(ScalarValue::try_from_array(
168 values.as_ref(),
169 index,
170 )?)?);
171 }
172 Self::List(result)
173 }
174 }
175 other => Self::Other(other.to_string()),
176 })
177 }
178}
179
180impl fmt::Display for SqlValue {
181 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
182 match self {
183 Self::Null => formatter.write_str("NULL"),
184 Self::Boolean(value) => write!(formatter, "{value}"),
185 Self::Integer(value) | Self::TimestampMillis(value) => write!(formatter, "{value}"),
186 Self::Unsigned(value) => write!(formatter, "{value}"),
187 Self::Float(value) => write!(formatter, "{value}"),
188 Self::Text(value) | Self::Other(value) => formatter.write_str(value),
189 Self::Bytes(value) => {
190 for byte in value {
191 write!(formatter, "{byte:02x}")?;
192 }
193 Ok(())
194 }
195 Self::List(values) => {
196 formatter.write_str("[")?;
197 for (index, value) in values.iter().enumerate() {
198 if index > 0 {
199 formatter.write_str(", ")?;
200 }
201 write!(formatter, "{value}")?;
202 }
203 formatter.write_str("]")
204 }
205 }
206 }
207}