use arrow_array::{
Array, BinaryArray, BooleanArray, Date32Array, Date64Array, Decimal32Array, Decimal64Array,
Decimal128Array, Decimal256Array, FixedSizeBinaryArray, Float16Array, Float32Array,
Float64Array, Int8Array, Int16Array, Int32Array, Int64Array, LargeBinaryArray,
LargeStringArray, StringArray, Time32MillisecondArray, Time32SecondArray,
Time64MicrosecondArray, Time64NanosecondArray, TimestampMicrosecondArray,
TimestampMillisecondArray, TimestampNanosecondArray, TimestampSecondArray, UInt8Array,
UInt16Array, UInt32Array, UInt64Array,
};
use arrow_buffer::i256;
use arrow_schema::{DataType, TimeUnit};
use crate::{Diagnostic, DiagnosticCode, DiagnosticSet, FieldRef, Result, SchemaMapping};
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum ArrowCell<'a> {
Null,
Boolean(bool),
Int8(i8),
Int16(i16),
Int32(i32),
Int64(i64),
UInt8(u8),
UInt16(u16),
UInt32(u32),
UInt64(u64),
Decimal32(i32),
Decimal64(i64),
Decimal128(i128),
Decimal256(i256),
Date32(i32),
Date64(i64),
Time32Second(i32),
Time32Millisecond(i32),
Time64Microsecond(i64),
Time64Nanosecond(i64),
TimestampSecond(i64),
TimestampMillisecond(i64),
TimestampMicrosecond(i64),
TimestampNanosecond(i64),
Float32(f32),
Float16(f32),
Float64(f64),
Utf8(&'a str),
Binary(&'a [u8]),
}
pub(crate) fn extract_arrow_cell<'a>(
array: &'a dyn Array,
mapping: &SchemaMapping,
row_index: usize,
) -> Result<ArrowCell<'a>> {
if array.is_null(row_index) {
return Ok(ArrowCell::Null);
}
match mapping.arrow().data_type() {
DataType::Boolean => {
let array = downcast_array::<BooleanArray>(array, mapping, row_index)?;
Ok(ArrowCell::Boolean(array.value(row_index)))
}
DataType::Int8 => {
let array = downcast_array::<Int8Array>(array, mapping, row_index)?;
Ok(ArrowCell::Int8(array.value(row_index)))
}
DataType::Int16 => {
let array = downcast_array::<Int16Array>(array, mapping, row_index)?;
Ok(ArrowCell::Int16(array.value(row_index)))
}
DataType::Int32 => {
let array = downcast_array::<Int32Array>(array, mapping, row_index)?;
Ok(ArrowCell::Int32(array.value(row_index)))
}
DataType::Int64 => {
let array = downcast_array::<Int64Array>(array, mapping, row_index)?;
Ok(ArrowCell::Int64(array.value(row_index)))
}
DataType::UInt8 => {
let array = downcast_array::<UInt8Array>(array, mapping, row_index)?;
Ok(ArrowCell::UInt8(array.value(row_index)))
}
DataType::UInt16 => {
let array = downcast_array::<UInt16Array>(array, mapping, row_index)?;
Ok(ArrowCell::UInt16(array.value(row_index)))
}
DataType::UInt32 => {
let array = downcast_array::<UInt32Array>(array, mapping, row_index)?;
Ok(ArrowCell::UInt32(array.value(row_index)))
}
DataType::UInt64 => {
let array = downcast_array::<UInt64Array>(array, mapping, row_index)?;
Ok(ArrowCell::UInt64(array.value(row_index)))
}
DataType::Decimal32(_, _) => {
let array = downcast_array::<Decimal32Array>(array, mapping, row_index)?;
Ok(ArrowCell::Decimal32(array.value(row_index)))
}
DataType::Decimal64(_, _) => {
let array = downcast_array::<Decimal64Array>(array, mapping, row_index)?;
Ok(ArrowCell::Decimal64(array.value(row_index)))
}
DataType::Decimal128(_, _) => {
let array = downcast_array::<Decimal128Array>(array, mapping, row_index)?;
Ok(ArrowCell::Decimal128(array.value(row_index)))
}
DataType::Decimal256(_, _) => {
let array = downcast_array::<Decimal256Array>(array, mapping, row_index)?;
Ok(ArrowCell::Decimal256(array.value(row_index)))
}
DataType::Date32 => {
let array = downcast_array::<Date32Array>(array, mapping, row_index)?;
Ok(ArrowCell::Date32(array.value(row_index)))
}
DataType::Date64 => {
let array = downcast_array::<Date64Array>(array, mapping, row_index)?;
Ok(ArrowCell::Date64(array.value(row_index)))
}
DataType::Time32(time_unit) => match time_unit {
TimeUnit::Second => {
let array = downcast_array::<Time32SecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::Time32Second(array.value(row_index)))
}
TimeUnit::Millisecond => {
let array = downcast_array::<Time32MillisecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::Time32Millisecond(array.value(row_index)))
}
other => Err(unsupported_value_conversion(
mapping,
row_index,
format!("Arrow Time32 unit {other:?} is not supported for value extraction"),
)),
},
DataType::Time64(time_unit) => match time_unit {
TimeUnit::Microsecond => {
let array = downcast_array::<Time64MicrosecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::Time64Microsecond(array.value(row_index)))
}
TimeUnit::Nanosecond => {
let array = downcast_array::<Time64NanosecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::Time64Nanosecond(array.value(row_index)))
}
other => Err(unsupported_value_conversion(
mapping,
row_index,
format!("Arrow Time64 unit {other:?} is not supported for value extraction"),
)),
},
DataType::Timestamp(time_unit, _) => match time_unit {
TimeUnit::Second => {
let array = downcast_array::<TimestampSecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::TimestampSecond(array.value(row_index)))
}
TimeUnit::Millisecond => {
let array = downcast_array::<TimestampMillisecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::TimestampMillisecond(array.value(row_index)))
}
TimeUnit::Microsecond => {
let array = downcast_array::<TimestampMicrosecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::TimestampMicrosecond(array.value(row_index)))
}
TimeUnit::Nanosecond => {
let array = downcast_array::<TimestampNanosecondArray>(array, mapping, row_index)?;
Ok(ArrowCell::TimestampNanosecond(array.value(row_index)))
}
},
DataType::Float16 => {
let array = downcast_array::<Float16Array>(array, mapping, row_index)?;
Ok(ArrowCell::Float16(array.value(row_index).to_f32()))
}
DataType::Float32 => {
let array = downcast_array::<Float32Array>(array, mapping, row_index)?;
Ok(ArrowCell::Float32(array.value(row_index)))
}
DataType::Float64 => {
let array = downcast_array::<Float64Array>(array, mapping, row_index)?;
Ok(ArrowCell::Float64(array.value(row_index)))
}
DataType::Utf8 => {
let array = downcast_array::<StringArray>(array, mapping, row_index)?;
Ok(ArrowCell::Utf8(array.value(row_index)))
}
DataType::LargeUtf8 => {
let array = downcast_array::<LargeStringArray>(array, mapping, row_index)?;
Ok(ArrowCell::Utf8(array.value(row_index)))
}
DataType::Binary => {
let array = downcast_array::<BinaryArray>(array, mapping, row_index)?;
Ok(ArrowCell::Binary(array.value(row_index)))
}
DataType::LargeBinary => {
let array = downcast_array::<LargeBinaryArray>(array, mapping, row_index)?;
Ok(ArrowCell::Binary(array.value(row_index)))
}
DataType::FixedSizeBinary(_) => {
let array = downcast_array::<FixedSizeBinaryArray>(array, mapping, row_index)?;
Ok(ArrowCell::Binary(array.value(row_index)))
}
other => Err(unsupported_value_conversion(
mapping,
row_index,
format!("Arrow value extraction for {other} is not supported yet"),
)),
}
}
fn downcast_array<'a, T: Array + 'static>(
array: &'a dyn Array,
mapping: &SchemaMapping,
row_index: usize,
) -> Result<&'a T> {
array.as_any().downcast_ref::<T>().ok_or_else(|| {
value_conversion_error(row_mapping_diagnostic(
mapping,
row_index,
DiagnosticCode::ValueTypeMismatch,
format!(
"runtime Arrow type {} does not match planned Arrow type {}",
array.data_type(),
mapping.arrow().data_type()
),
))
})
}
fn unsupported_value_conversion(
mapping: &SchemaMapping,
row_index: usize,
message: impl Into<String>,
) -> crate::Error {
value_conversion_error(row_mapping_diagnostic(
mapping,
row_index,
DiagnosticCode::ValueConversionUnsupported,
message,
))
}
fn row_mapping_diagnostic(
mapping: &SchemaMapping,
row_index: usize,
code: DiagnosticCode,
message: impl Into<String>,
) -> Diagnostic {
Diagnostic::error(code, message)
.with_field(FieldRef::new(
mapping.arrow().index(),
mapping.arrow().name(),
))
.with_row(row_index)
}
fn value_conversion_error(diagnostic: Diagnostic) -> crate::Error {
crate::Error::ValueConversion {
diagnostics: DiagnosticSet::from(vec![diagnostic]),
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use arrow_array::{
ArrayRef, BinaryArray, BooleanArray, Date32Array, Date64Array, Decimal32Array,
Decimal64Array, Decimal128Array, Decimal256Array, FixedSizeBinaryArray, Float16Array,
Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Int64Array,
LargeBinaryArray, LargeStringArray, StringArray, Time32MillisecondArray, Time32SecondArray,
Time64MicrosecondArray, Time64NanosecondArray, TimestampMicrosecondArray,
TimestampMillisecondArray, TimestampNanosecondArray, TimestampSecondArray, UInt8Array,
UInt16Array, UInt32Array, UInt64Array,
types::{ArrowPrimitiveType, Float16Type},
};
use arrow_buffer::i256;
use arrow_schema::{DataType, TimeUnit};
use super::{ArrowCell, extract_arrow_cell};
use crate::{ArrowFieldRef, Identifier, MssqlColumn, MssqlType, SchemaMapping};
type F16 = <Float16Type as ArrowPrimitiveType>::Native;
#[test]
fn extracts_arrow_cells_for_supported_initial_primitives() {
let cases: Vec<(SchemaMapping, ArrayRef, ArrowCell<'_>)> = vec![
(
mapping("active", DataType::Boolean),
Arc::new(BooleanArray::from(vec![Some(true), None])),
ArrowCell::Boolean(true),
),
(
mapping("tiny", DataType::Int8),
Arc::new(Int8Array::from(vec![Some(-8_i8), None])),
ArrowCell::Int8(-8),
),
(
mapping("small", DataType::Int16),
Arc::new(Int16Array::from(vec![Some(-16_i16), None])),
ArrowCell::Int16(-16),
),
(
mapping("quantity", DataType::Int32),
Arc::new(Int32Array::from(vec![Some(12_i32), None])),
ArrowCell::Int32(12),
),
(
mapping("total", DataType::Int64),
Arc::new(Int64Array::from(vec![Some(34_i64), None])),
ArrowCell::Int64(34),
),
(
mapping("unsigned_tiny", DataType::UInt8),
Arc::new(UInt8Array::from(vec![Some(8_u8), None])),
ArrowCell::UInt8(8),
),
(
mapping("unsigned_medium", DataType::UInt16),
Arc::new(UInt16Array::from(vec![Some(16_u16), None])),
ArrowCell::UInt16(16),
),
(
mapping("unsigned_large", DataType::UInt32),
Arc::new(UInt32Array::from(vec![Some(32_u32), None])),
ArrowCell::UInt32(32),
),
(
mapping("half_value", DataType::Float16),
Arc::new(Float16Array::from(vec![Some(F16::from_f32(1.5)), None])),
ArrowCell::Float16(1.5),
),
(
mapping("real_value", DataType::Float32),
Arc::new(Float32Array::from(vec![Some(1.25_f32), None])),
ArrowCell::Float32(1.25),
),
(
mapping("float_value", DataType::Float64),
Arc::new(Float64Array::from(vec![Some(2.5_f64), None])),
ArrowCell::Float64(2.5),
),
(
mapping("text", DataType::Utf8),
Arc::new(StringArray::from(vec![Some("hello"), None])),
ArrowCell::Utf8("hello"),
),
(
mapping("large_text", DataType::LargeUtf8),
Arc::new(LargeStringArray::from(vec![Some("Tokyo"), None])),
ArrowCell::Utf8("Tokyo"),
),
(
mapping("bytes", DataType::Binary),
Arc::new(BinaryArray::from(vec![Some(&b"abc"[..]), None])),
ArrowCell::Binary(b"abc"),
),
(
mapping("large_bytes", DataType::LargeBinary),
Arc::new(LargeBinaryArray::from(vec![Some(&b"large"[..]), None])),
ArrowCell::Binary(b"large"),
),
(
mapping("fixed_bytes", DataType::FixedSizeBinary(3)),
Arc::new(
FixedSizeBinaryArray::try_from_sparse_iter_with_size(
[Some(&b"abc"[..]), None].into_iter(),
3,
)
.unwrap(),
),
ArrowCell::Binary(b"abc"),
),
];
for (mapping, array, expected) in cases {
assert_eq!(
extract_arrow_cell(array.as_ref(), &mapping, 0).unwrap(),
expected
);
assert_eq!(
extract_arrow_cell(array.as_ref(), &mapping, 1).unwrap(),
ArrowCell::Null
);
}
}
#[test]
fn extracts_uint64_arrow_cells_at_policy_boundaries() {
let mapping = mapping("unsigned_huge", DataType::UInt64);
let array = UInt64Array::from(vec![
Some(0_u64),
Some(i64::MAX as u64),
Some((i64::MAX as u64) + 1),
Some(u64::MAX),
None,
]);
assert_eq!(
extract_arrow_cell(&array, &mapping, 0).unwrap(),
ArrowCell::UInt64(0)
);
assert_eq!(
extract_arrow_cell(&array, &mapping, 1).unwrap(),
ArrowCell::UInt64(i64::MAX as u64)
);
assert_eq!(
extract_arrow_cell(&array, &mapping, 2).unwrap(),
ArrowCell::UInt64((i64::MAX as u64) + 1)
);
assert_eq!(
extract_arrow_cell(&array, &mapping, 3).unwrap(),
ArrowCell::UInt64(u64::MAX)
);
assert_eq!(
extract_arrow_cell(&array, &mapping, 4).unwrap(),
ArrowCell::Null
);
}
#[test]
fn extracts_timestamp_arrow_cells_without_losing_epoch_values() {
let cases: Vec<(SchemaMapping, ArrayRef, ArrowCell<'_>, ArrowCell<'_>)> = vec![
(
mapping("ts_s", DataType::Timestamp(TimeUnit::Second, None)),
Arc::new(TimestampSecondArray::from(vec![
Some(i64::MIN),
Some(i64::MAX),
None,
])),
ArrowCell::TimestampSecond(i64::MIN),
ArrowCell::TimestampSecond(i64::MAX),
),
(
mapping("ts_ms", DataType::Timestamp(TimeUnit::Millisecond, None)),
Arc::new(TimestampMillisecondArray::from(vec![
Some(i64::MIN),
Some(i64::MAX),
None,
])),
ArrowCell::TimestampMillisecond(i64::MIN),
ArrowCell::TimestampMillisecond(i64::MAX),
),
(
mapping("ts_us", DataType::Timestamp(TimeUnit::Microsecond, None)),
Arc::new(TimestampMicrosecondArray::from(vec![
Some(i64::MIN),
Some(i64::MAX),
None,
])),
ArrowCell::TimestampMicrosecond(i64::MIN),
ArrowCell::TimestampMicrosecond(i64::MAX),
),
(
mapping("ts_ns", DataType::Timestamp(TimeUnit::Nanosecond, None)),
Arc::new(TimestampNanosecondArray::from(vec![
Some(i64::MIN),
Some(i64::MAX),
None,
])),
ArrowCell::TimestampNanosecond(i64::MIN),
ArrowCell::TimestampNanosecond(i64::MAX),
),
(
mapping(
"ts_tz",
DataType::Timestamp(TimeUnit::Second, Some("America/New_York".into())),
),
Arc::new(
TimestampSecondArray::from(vec![Some(1_i64), Some(2_i64), None])
.with_timezone("America/New_York"),
),
ArrowCell::TimestampSecond(1),
ArrowCell::TimestampSecond(2),
),
];
for (mapping, array, first, second) in cases {
assert_eq!(
extract_arrow_cell(array.as_ref(), &mapping, 0).unwrap(),
first
);
assert_eq!(
extract_arrow_cell(array.as_ref(), &mapping, 1).unwrap(),
second
);
assert_eq!(
extract_arrow_cell(array.as_ref(), &mapping, 2).unwrap(),
ArrowCell::Null
);
}
}
#[test]
fn extracts_decimal_arrow_cells_for_all_widths() {
let decimal32 =
Decimal32Array::from(vec![Some(12_345_i32), Some(-12_345_i32), Some(0_i32), None])
.with_precision_and_scale(9, 2)
.unwrap();
let decimal64 = Decimal64Array::from(vec![
Some(1_234_567_890_i64),
Some(-1_234_567_890_i64),
Some(0_i64),
None,
])
.with_precision_and_scale(18, 4)
.unwrap();
let decimal128 = Decimal128Array::from(vec![
Some(123_456_789_012_345_678_901_234_567_890_i128),
Some(-123_456_789_012_345_678_901_234_567_890_i128),
Some(0_i128),
None,
])
.with_precision_and_scale(38, 9)
.unwrap();
let decimal256 = Decimal256Array::from(vec![
Some(i256::from_i128(
123_456_789_012_345_678_901_234_567_890_i128,
)),
Some(i256::from_i128(
-123_456_789_012_345_678_901_234_567_890_i128,
)),
Some(i256::ZERO),
None,
])
.with_precision_and_scale(38, 0)
.unwrap();
let decimal32_mapping = mapping("decimal32", DataType::Decimal32(9, 2));
assert_eq!(
extract_arrow_cell(&decimal32, &decimal32_mapping, 0).unwrap(),
ArrowCell::Decimal32(12_345)
);
assert_eq!(
extract_arrow_cell(&decimal32, &decimal32_mapping, 1).unwrap(),
ArrowCell::Decimal32(-12_345)
);
assert_eq!(
extract_arrow_cell(&decimal32, &decimal32_mapping, 2).unwrap(),
ArrowCell::Decimal32(0)
);
assert_eq!(
extract_arrow_cell(&decimal32, &decimal32_mapping, 3).unwrap(),
ArrowCell::Null
);
let decimal64_mapping = mapping("decimal64", DataType::Decimal64(18, 4));
assert_eq!(
extract_arrow_cell(&decimal64, &decimal64_mapping, 0).unwrap(),
ArrowCell::Decimal64(1_234_567_890)
);
assert_eq!(
extract_arrow_cell(&decimal64, &decimal64_mapping, 1).unwrap(),
ArrowCell::Decimal64(-1_234_567_890)
);
assert_eq!(
extract_arrow_cell(&decimal64, &decimal64_mapping, 2).unwrap(),
ArrowCell::Decimal64(0)
);
assert_eq!(
extract_arrow_cell(&decimal64, &decimal64_mapping, 3).unwrap(),
ArrowCell::Null
);
let decimal128_mapping = mapping("decimal128", DataType::Decimal128(38, 9));
assert_eq!(
extract_arrow_cell(&decimal128, &decimal128_mapping, 0).unwrap(),
ArrowCell::Decimal128(123_456_789_012_345_678_901_234_567_890)
);
assert_eq!(
extract_arrow_cell(&decimal128, &decimal128_mapping, 1).unwrap(),
ArrowCell::Decimal128(-123_456_789_012_345_678_901_234_567_890)
);
assert_eq!(
extract_arrow_cell(&decimal128, &decimal128_mapping, 2).unwrap(),
ArrowCell::Decimal128(0)
);
assert_eq!(
extract_arrow_cell(&decimal128, &decimal128_mapping, 3).unwrap(),
ArrowCell::Null
);
let decimal256_mapping = mapping("decimal256", DataType::Decimal256(38, 0));
assert_eq!(
extract_arrow_cell(&decimal256, &decimal256_mapping, 0).unwrap(),
ArrowCell::Decimal256(i256::from_i128(123_456_789_012_345_678_901_234_567_890))
);
assert_eq!(
extract_arrow_cell(&decimal256, &decimal256_mapping, 1).unwrap(),
ArrowCell::Decimal256(i256::from_i128(-123_456_789_012_345_678_901_234_567_890))
);
assert_eq!(
extract_arrow_cell(&decimal256, &decimal256_mapping, 2).unwrap(),
ArrowCell::Decimal256(i256::ZERO)
);
assert_eq!(
extract_arrow_cell(&decimal256, &decimal256_mapping, 3).unwrap(),
ArrowCell::Null
);
}
#[test]
fn extracts_date_arrow_cells() {
let date32 = Date32Array::from(vec![Some(0_i32), Some(-1_i32), Some(1_i32), None]);
let date64 = Date64Array::from(vec![Some(0_i64), Some(-1_i64), Some(86_400_123_i64), None]);
let date32_mapping = mapping("date32", DataType::Date32);
let date64_mapping = mapping("date64", DataType::Date64);
assert_eq!(
extract_arrow_cell(&date32, &date32_mapping, 0).unwrap(),
ArrowCell::Date32(0)
);
assert_eq!(
extract_arrow_cell(&date32, &date32_mapping, 1).unwrap(),
ArrowCell::Date32(-1)
);
assert_eq!(
extract_arrow_cell(&date32, &date32_mapping, 2).unwrap(),
ArrowCell::Date32(1)
);
assert_eq!(
extract_arrow_cell(&date32, &date32_mapping, 3).unwrap(),
ArrowCell::Null
);
assert_eq!(
extract_arrow_cell(&date64, &date64_mapping, 0).unwrap(),
ArrowCell::Date64(0)
);
assert_eq!(
extract_arrow_cell(&date64, &date64_mapping, 1).unwrap(),
ArrowCell::Date64(-1)
);
assert_eq!(
extract_arrow_cell(&date64, &date64_mapping, 2).unwrap(),
ArrowCell::Date64(86_400_123)
);
assert_eq!(
extract_arrow_cell(&date64, &date64_mapping, 3).unwrap(),
ArrowCell::Null
);
}
#[test]
fn extracts_time_arrow_cells() {
let time32_s = Time32SecondArray::from(vec![Some(0_i32), Some(42_i32), None]);
let time32_ms = Time32MillisecondArray::from(vec![Some(0_i32), Some(42_123_i32), None]);
let time64_us = Time64MicrosecondArray::from(vec![Some(0_i64), Some(42_123_456_i64), None]);
let time64_ns =
Time64NanosecondArray::from(vec![Some(0_i64), Some(42_123_456_789_i64), None]);
let time32_s_mapping = mapping("time32_s", DataType::Time32(TimeUnit::Second));
let time32_ms_mapping = mapping("time32_ms", DataType::Time32(TimeUnit::Millisecond));
let time64_us_mapping = mapping("time64_us", DataType::Time64(TimeUnit::Microsecond));
let time64_ns_mapping = mapping("time64_ns", DataType::Time64(TimeUnit::Nanosecond));
assert_eq!(
extract_arrow_cell(&time32_s, &time32_s_mapping, 0).unwrap(),
ArrowCell::Time32Second(0)
);
assert_eq!(
extract_arrow_cell(&time32_s, &time32_s_mapping, 1).unwrap(),
ArrowCell::Time32Second(42)
);
assert_eq!(
extract_arrow_cell(&time32_s, &time32_s_mapping, 2).unwrap(),
ArrowCell::Null
);
assert_eq!(
extract_arrow_cell(&time32_ms, &time32_ms_mapping, 1).unwrap(),
ArrowCell::Time32Millisecond(42_123)
);
assert_eq!(
extract_arrow_cell(&time64_us, &time64_us_mapping, 1).unwrap(),
ArrowCell::Time64Microsecond(42_123_456)
);
assert_eq!(
extract_arrow_cell(&time64_ns, &time64_ns_mapping, 1).unwrap(),
ArrowCell::Time64Nanosecond(42_123_456_789)
);
}
fn mapping(name: &str, data_type: DataType) -> SchemaMapping {
SchemaMapping::new(
ArrowFieldRef::new(0, name.to_owned(), true, data_type),
MssqlColumn::new(Identifier::new(name).unwrap(), MssqlType::Int, true),
)
}
}