1pub mod admin;
16pub mod alter;
17pub mod comment;
18pub mod copy;
19pub mod create;
20pub mod cursor;
21pub mod delete;
22pub mod describe;
23pub mod drop;
24pub mod explain;
25pub mod insert;
26pub mod kill;
27mod option_map;
28pub mod query;
29pub mod set_variables;
30pub mod show;
31pub mod statement;
32pub mod tql;
33pub(crate) mod transform;
34pub mod truncate;
35
36use std::sync::Arc;
37
38use api::helper::ColumnDataTypeWrapper;
39use api::v1::{ColumnOptions, SemanticType};
40use arrow_schema::extension::{
41 EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY, ExtensionType,
42};
43use common_sql::default_constraint::parse_column_default_constraint;
44use common_time::timezone::Timezone;
45use datatypes::extension::json::{Json2ExtensionType, JsonMetadata};
46use datatypes::json::JsonSettings;
47use datatypes::prelude::ConcreteDataType;
48use datatypes::schema::{COMMENT_KEY, ColumnDefaultConstraint, ColumnSchema};
49use datatypes::types::json_type::JsonNativeType;
50use datatypes::types::{JsonFormat, JsonType, TimestampType};
51use datatypes::value::Value;
52use snafu::ResultExt;
53use sqlparser::ast::{ExactNumberInfo, Ident};
54
55use crate::ast::{
56 ColumnDef, ColumnOption, DataType as SqlDataType, ObjectNamePartExt, TimezoneInfo,
57 Value as SqlValue,
58};
59use crate::error::{
60 self, ConvertToGrpcDataTypeSnafu, ConvertValueSnafu, Result,
61 SerializeColumnDefaultConstraintSnafu, SetCompressionOptionSnafu, SetFulltextOptionSnafu,
62 SetSkippingIndexOptionSnafu, SqlCommonSnafu,
63};
64use crate::statements::create::Column;
65pub use crate::statements::option_map::OptionMap;
66pub(crate) use crate::statements::transform::transform_statements;
67
68const VECTOR_TYPE_NAME: &str = "VECTOR";
69const JSON2_TYPE_NAME: &str = "JSON2";
70
71pub fn value_to_sql_value(val: &Value) -> Result<SqlValue> {
72 Ok(match val {
73 Value::Int8(v) => SqlValue::Number(v.to_string(), false),
74 Value::UInt8(v) => SqlValue::Number(v.to_string(), false),
75 Value::Int16(v) => SqlValue::Number(v.to_string(), false),
76 Value::UInt16(v) => SqlValue::Number(v.to_string(), false),
77 Value::Int32(v) => SqlValue::Number(v.to_string(), false),
78 Value::UInt32(v) => SqlValue::Number(v.to_string(), false),
79 Value::Int64(v) => SqlValue::Number(v.to_string(), false),
80 Value::UInt64(v) => SqlValue::Number(v.to_string(), false),
81 Value::Float32(v) => SqlValue::Number(v.to_string(), false),
82 Value::Float64(v) => SqlValue::Number(v.to_string(), false),
83 Value::Boolean(b) => SqlValue::Boolean(*b),
84 Value::Date(d) => SqlValue::SingleQuotedString(d.to_string()),
85 Value::Timestamp(ts) => SqlValue::SingleQuotedString(ts.to_iso8601_string()),
86 Value::String(s) => SqlValue::SingleQuotedString(s.as_utf8().to_string()),
87 Value::Null => SqlValue::Null,
88 _ => return ConvertValueSnafu { value: val.clone() }.fail(),
90 })
91}
92
93pub fn has_primary_key_option(column_def: &ColumnDef) -> bool {
95 column_def
96 .options
97 .iter()
98 .any(|options| matches!(options.option, ColumnOption::PrimaryKey(..)))
99}
100
101pub fn column_to_schema(
103 column: &Column,
104 time_index: &str,
105 timezone: Option<&Timezone>,
106) -> Result<ColumnSchema> {
107 let is_time_index = column.name().value == time_index;
108
109 let is_nullable = column
110 .options()
111 .iter()
112 .all(|o| !matches!(o.option, ColumnOption::NotNull))
113 && !is_time_index;
114
115 let name = column.name().value.clone();
116 let data_type = sql_data_type_to_concrete_data_type(column.data_type())?;
117 let default_constraint =
118 parse_column_default_constraint(&name, &data_type, column.options(), timezone)
119 .context(SqlCommonSnafu)?;
120
121 let mut column_schema = ColumnSchema::new(name, data_type, is_nullable)
122 .with_time_index(is_time_index)
123 .with_default_constraint(default_constraint)
124 .context(error::InvalidDefaultSnafu {
125 column: &column.name().value,
126 })?;
127
128 if let Some(ColumnOption::Comment(c)) = column.options().iter().find_map(|o| {
129 if matches!(o.option, ColumnOption::Comment(_)) {
130 Some(&o.option)
131 } else {
132 None
133 }
134 }) {
135 let _ = column_schema
136 .mut_metadata()
137 .insert(COMMENT_KEY.to_string(), c.clone());
138 }
139
140 if let Some(options) = column.extensions.build_fulltext_options()? {
141 column_schema = column_schema
142 .with_fulltext_options(options)
143 .context(SetFulltextOptionSnafu)?;
144 }
145
146 if let Some(options) = column.extensions.build_skipping_index_options()? {
147 column_schema = column_schema
148 .with_skipping_options(options)
149 .context(SetSkippingIndexOptionSnafu)?;
150 }
151
152 if let Some(options) = column.extensions.build_compression_options()? {
153 column_schema = column_schema
154 .with_compression_options(options)
155 .context(SetCompressionOptionSnafu)?;
156 }
157
158 column_schema.set_inverted_index(column.extensions.inverted_index_options.is_some());
159
160 set_json2_extension(&mut column_schema, column)?;
161
162 Ok(column_schema)
163}
164
165fn set_json2_extension(column_schema: &mut ColumnSchema, column: &Column) -> Result<()> {
167 if !column_schema.data_type.is_json2() {
168 return Ok(());
169 }
170
171 let settings = column
172 .extensions
173 .build_json_settings()?
174 .unwrap_or_else(JsonSettings::new_v2);
175 if let Some(extension) = json2_extension(column.data_type(), settings) {
176 column_schema.with_extension_type(&extension);
177 }
178
179 Ok(())
180}
181
182pub fn sql_col_to_grpc_col_def(
184 column: &Column,
185 timezone: Option<&Timezone>,
186) -> Result<api::v1::ColumnDef> {
187 let col = &column.column_def;
188 let name = col.name.value.clone();
189 let data_type = sql_data_type_to_concrete_data_type(&col.data_type)?;
190
191 let is_nullable = col
192 .options
193 .iter()
194 .all(|o| !matches!(o.option, ColumnOption::NotNull));
195
196 let default_constraint =
197 parse_column_default_constraint(&name, &data_type, &col.options, timezone)
198 .context(SqlCommonSnafu)?
199 .map(ColumnDefaultConstraint::try_into) .transpose()
201 .context(SerializeColumnDefaultConstraintSnafu)?;
202 let (datatype, datatype_ext) = ColumnDataTypeWrapper::try_from(data_type.clone())
204 .context(ConvertToGrpcDataTypeSnafu)?
205 .to_parts();
206
207 let is_primary_key = col
208 .options
209 .iter()
210 .any(|o| matches!(o.option, ColumnOption::PrimaryKey(..)));
211
212 let semantic_type = if is_primary_key {
213 SemanticType::Tag
214 } else {
215 SemanticType::Field
216 };
217
218 let settings = column
219 .extensions
220 .build_json_settings()?
221 .unwrap_or_else(JsonSettings::new_v2);
222 let options = json2_extension(&col.data_type, settings).map(|extension| {
223 let mut options = ColumnOptions::default();
224 options.options.insert(
225 EXTENSION_TYPE_NAME_KEY.to_string(),
226 Json2ExtensionType::NAME.to_string(),
227 );
228 if let Some(metadata) = extension.serialize_metadata() {
229 options
230 .options
231 .insert(EXTENSION_TYPE_METADATA_KEY.to_string(), metadata);
232 }
233 options
234 });
235
236 Ok(api::v1::ColumnDef {
237 name,
238 data_type: datatype as i32,
239 is_nullable,
240 default_constraint: default_constraint.unwrap_or_default(),
241 semantic_type: semantic_type as _,
242 comment: String::new(),
243 datatype_extension: datatype_ext,
244 options,
245 })
246}
247
248fn json2_extension(data_type: &SqlDataType, settings: JsonSettings) -> Option<Json2ExtensionType> {
249 let SqlDataType::Custom(name, _) = data_type else {
250 return None;
251 };
252 if !name.0.first().is_some_and(|name| {
253 name.to_string_unquoted()
254 .eq_ignore_ascii_case(JSON2_TYPE_NAME)
255 }) {
256 return None;
257 }
258
259 Some(Json2ExtensionType::new(Arc::new(JsonMetadata::new(
260 settings,
261 ))))
262}
263
264pub fn sql_data_type_to_concrete_data_type(data_type: &SqlDataType) -> Result<ConcreteDataType> {
265 match data_type {
266 SqlDataType::BigInt(_) | SqlDataType::Int64 => Ok(ConcreteDataType::int64_datatype()),
267 SqlDataType::BigIntUnsigned(_) | SqlDataType::UInt64 => {
268 Ok(ConcreteDataType::uint64_datatype())
269 }
270 SqlDataType::Int(_) | SqlDataType::Integer(_) => Ok(ConcreteDataType::int32_datatype()),
271 SqlDataType::IntUnsigned(_) | SqlDataType::UnsignedInteger => {
272 Ok(ConcreteDataType::uint32_datatype())
273 }
274 SqlDataType::SmallInt(_) => Ok(ConcreteDataType::int16_datatype()),
275 SqlDataType::SmallIntUnsigned(_) => Ok(ConcreteDataType::uint16_datatype()),
276 SqlDataType::TinyInt(_) | SqlDataType::Int8(_) => Ok(ConcreteDataType::int8_datatype()),
277 SqlDataType::TinyIntUnsigned(_) | SqlDataType::Int8Unsigned(_) => {
278 Ok(ConcreteDataType::uint8_datatype())
279 }
280 SqlDataType::Char(_)
281 | SqlDataType::Varchar(_)
282 | SqlDataType::Text
283 | SqlDataType::TinyText
284 | SqlDataType::MediumText
285 | SqlDataType::LongText
286 | SqlDataType::String(_) => Ok(ConcreteDataType::string_datatype()),
287 SqlDataType::Float(_) => Ok(ConcreteDataType::float32_datatype()),
288 SqlDataType::Double(_) | SqlDataType::Float64 => Ok(ConcreteDataType::float64_datatype()),
289 SqlDataType::Boolean => Ok(ConcreteDataType::boolean_datatype()),
290 SqlDataType::Date => Ok(ConcreteDataType::date_datatype()),
291 SqlDataType::Binary(_)
292 | SqlDataType::Blob(_)
293 | SqlDataType::Bytea
294 | SqlDataType::Varbinary(_) => Ok(ConcreteDataType::binary_datatype()),
295 SqlDataType::Datetime(_) => Ok(ConcreteDataType::timestamp_microsecond_datatype()),
296 SqlDataType::Timestamp(precision, _) => Ok(precision
297 .as_ref()
298 .map(|v| TimestampType::try_from(*v))
299 .transpose()
300 .map_err(|_| {
301 error::SqlTypeNotSupportedSnafu {
302 t: data_type.clone(),
303 }
304 .build()
305 })?
306 .map(|t| ConcreteDataType::timestamp_datatype(t.unit()))
307 .unwrap_or(ConcreteDataType::timestamp_millisecond_datatype())),
308 SqlDataType::Interval { .. } => Ok(ConcreteDataType::interval_month_day_nano_datatype()),
309 SqlDataType::Decimal(exact_info) => match exact_info {
310 ExactNumberInfo::None => Ok(ConcreteDataType::decimal128_default_datatype()),
311 ExactNumberInfo::Precision(p) => Ok(ConcreteDataType::decimal128_datatype(*p as u8, 0)),
314 ExactNumberInfo::PrecisionAndScale(p, s) => {
315 Ok(ConcreteDataType::decimal128_datatype(*p as u8, *s as i8))
316 }
317 },
318 SqlDataType::JSON => Ok(ConcreteDataType::Json(JsonType::new(JsonFormat::Jsonb))),
319 SqlDataType::Custom(name, args) if name.0.len() == 1 => {
321 let name = name.0[0].to_string_unquoted().to_ascii_uppercase();
322 match name.as_str() {
323 VECTOR_TYPE_NAME if args.len() == 1 => {
324 let dim = &args[0];
325 let dim = dim.parse().map_err(|e| {
326 error::ParseSqlValueSnafu {
327 msg: format!("Failed to parse vector dimension '{}': {}", dim, e),
328 }
329 .build()
330 })?;
331 Ok(ConcreteDataType::vector_datatype(dim))
332 }
333 JSON2_TYPE_NAME if args.is_empty() => {
334 let format = JsonFormat::Json2(Arc::new(JsonNativeType::Null));
337 Ok(ConcreteDataType::Json(JsonType::new(format)))
338 }
339 _ => error::SqlTypeNotSupportedSnafu {
340 t: data_type.clone(),
341 }
342 .fail(),
343 }
344 }
345 _ => error::SqlTypeNotSupportedSnafu {
346 t: data_type.clone(),
347 }
348 .fail(),
349 }
350}
351
352pub fn concrete_data_type_to_sql_data_type(data_type: &ConcreteDataType) -> Result<SqlDataType> {
353 match data_type {
354 ConcreteDataType::Int64(_) => Ok(SqlDataType::BigInt(None)),
355 ConcreteDataType::UInt64(_) => Ok(SqlDataType::BigIntUnsigned(None)),
356 ConcreteDataType::Int32(_) => Ok(SqlDataType::Int(None)),
357 ConcreteDataType::UInt32(_) => Ok(SqlDataType::IntUnsigned(None)),
358 ConcreteDataType::Int16(_) => Ok(SqlDataType::SmallInt(None)),
359 ConcreteDataType::UInt16(_) => Ok(SqlDataType::SmallIntUnsigned(None)),
360 ConcreteDataType::Int8(_) => Ok(SqlDataType::TinyInt(None)),
361 ConcreteDataType::UInt8(_) => Ok(SqlDataType::TinyIntUnsigned(None)),
362 ConcreteDataType::String(_) => Ok(SqlDataType::String(None)),
363 ConcreteDataType::Float32(_) => Ok(SqlDataType::Float(ExactNumberInfo::None)),
364 ConcreteDataType::Float64(_) => Ok(SqlDataType::Double(ExactNumberInfo::None)),
365 ConcreteDataType::Boolean(_) => Ok(SqlDataType::Boolean),
366 ConcreteDataType::Date(_) => Ok(SqlDataType::Date),
367 ConcreteDataType::Timestamp(ts_type) => Ok(SqlDataType::Timestamp(
368 Some(ts_type.precision()),
369 TimezoneInfo::None,
370 )),
371 ConcreteDataType::Time(time_type) => Ok(SqlDataType::Time(
372 Some(time_type.precision()),
373 TimezoneInfo::None,
374 )),
375 ConcreteDataType::Interval(_) => Ok(SqlDataType::Interval {
376 fields: None,
377 precision: None,
378 }),
379 ConcreteDataType::Binary(_) => Ok(SqlDataType::Varbinary(None)),
380 ConcreteDataType::Decimal128(d) => Ok(SqlDataType::Decimal(
381 ExactNumberInfo::PrecisionAndScale(d.precision() as u64, d.scale() as i64),
382 )),
383 ConcreteDataType::Json(_) => Ok(SqlDataType::JSON),
384 ConcreteDataType::Vector(v) => Ok(SqlDataType::Custom(
385 vec![Ident::new(VECTOR_TYPE_NAME)].into(),
386 vec![v.dim.to_string()],
387 )),
388 ConcreteDataType::Duration(_)
389 | ConcreteDataType::Null(_)
390 | ConcreteDataType::List(_)
391 | ConcreteDataType::Struct(_)
392 | ConcreteDataType::Dictionary(_) => error::ConcreteTypeNotSupportedSnafu {
393 t: data_type.clone(),
394 }
395 .fail(),
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use api::v1::ColumnDataType;
402 use datatypes::schema::{
403 COLUMN_FULLTEXT_OPT_KEY_ANALYZER, COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE, FulltextAnalyzer,
404 };
405 use sqlparser::ast::{ColumnOptionDef, Expr, PrimaryKeyConstraint};
406
407 use super::*;
408 use crate::ast::TimezoneInfo;
409 use crate::statements::ColumnOption;
410 use crate::statements::create::ColumnExtensions;
411
412 fn check_type(sql_type: SqlDataType, data_type: ConcreteDataType) {
413 assert_eq!(
414 data_type,
415 sql_data_type_to_concrete_data_type(&sql_type).unwrap()
416 );
417 }
418
419 #[test]
420 pub fn test_sql_data_type_to_concrete_data_type() {
421 check_type(
422 SqlDataType::BigInt(None),
423 ConcreteDataType::int64_datatype(),
424 );
425 check_type(SqlDataType::Int(None), ConcreteDataType::int32_datatype());
426 check_type(
427 SqlDataType::Integer(None),
428 ConcreteDataType::int32_datatype(),
429 );
430 check_type(
431 SqlDataType::SmallInt(None),
432 ConcreteDataType::int16_datatype(),
433 );
434 check_type(SqlDataType::Char(None), ConcreteDataType::string_datatype());
435 check_type(
436 SqlDataType::Varchar(None),
437 ConcreteDataType::string_datatype(),
438 );
439 check_type(SqlDataType::Text, ConcreteDataType::string_datatype());
440 check_type(
441 SqlDataType::String(None),
442 ConcreteDataType::string_datatype(),
443 );
444 check_type(
445 SqlDataType::Float(ExactNumberInfo::None),
446 ConcreteDataType::float32_datatype(),
447 );
448 check_type(
449 SqlDataType::Double(ExactNumberInfo::None),
450 ConcreteDataType::float64_datatype(),
451 );
452 check_type(SqlDataType::Boolean, ConcreteDataType::boolean_datatype());
453 check_type(SqlDataType::Date, ConcreteDataType::date_datatype());
454 check_type(
455 SqlDataType::Timestamp(None, TimezoneInfo::None),
456 ConcreteDataType::timestamp_millisecond_datatype(),
457 );
458 check_type(
459 SqlDataType::Varbinary(None),
460 ConcreteDataType::binary_datatype(),
461 );
462 check_type(
463 SqlDataType::BigIntUnsigned(None),
464 ConcreteDataType::uint64_datatype(),
465 );
466 check_type(SqlDataType::UInt64, ConcreteDataType::uint64_datatype());
467 check_type(
468 SqlDataType::IntUnsigned(None),
469 ConcreteDataType::uint32_datatype(),
470 );
471 check_type(
472 SqlDataType::SmallIntUnsigned(None),
473 ConcreteDataType::uint16_datatype(),
474 );
475 check_type(
476 SqlDataType::TinyIntUnsigned(None),
477 ConcreteDataType::uint8_datatype(),
478 );
479 check_type(
480 SqlDataType::Datetime(None),
481 ConcreteDataType::timestamp_microsecond_datatype(),
482 );
483 check_type(
484 SqlDataType::Interval {
485 fields: None,
486 precision: None,
487 },
488 ConcreteDataType::interval_month_day_nano_datatype(),
489 );
490 check_type(SqlDataType::JSON, ConcreteDataType::json_datatype());
491 check_type(
492 SqlDataType::Custom(
493 vec![Ident::new(VECTOR_TYPE_NAME)].into(),
494 vec!["3".to_string()],
495 ),
496 ConcreteDataType::vector_datatype(3),
497 );
498 }
499
500 #[test]
501 pub fn test_sql_col_to_grpc_col_def() {
502 let column = Column {
504 column_def: ColumnDef {
505 name: "col".into(),
506 data_type: SqlDataType::Double(ExactNumberInfo::None),
507 options: vec![],
508 },
509 extensions: ColumnExtensions::default(),
510 };
511
512 let grpc_column_def = sql_col_to_grpc_col_def(&column, None).unwrap();
513
514 assert_eq!("col", grpc_column_def.name);
515 assert!(grpc_column_def.is_nullable); assert_eq!(ColumnDataType::Float64 as i32, grpc_column_def.data_type);
517 assert!(grpc_column_def.default_constraint.is_empty());
518 assert_eq!(grpc_column_def.semantic_type, SemanticType::Field as i32);
519
520 let column = Column {
522 column_def: ColumnDef {
523 name: "col".into(),
524 data_type: SqlDataType::Double(ExactNumberInfo::None),
525 options: vec![ColumnOptionDef {
526 name: None,
527 option: ColumnOption::NotNull,
528 }],
529 },
530 extensions: ColumnExtensions::default(),
531 };
532
533 let grpc_column_def = sql_col_to_grpc_col_def(&column, None).unwrap();
534 assert!(!grpc_column_def.is_nullable);
535
536 let column = Column {
538 column_def: ColumnDef {
539 name: "col".into(),
540 data_type: SqlDataType::Double(ExactNumberInfo::None),
541 options: vec![ColumnOptionDef {
542 name: None,
543 option: ColumnOption::PrimaryKey(PrimaryKeyConstraint {
544 name: None,
545 index_name: None,
546 index_type: None,
547 columns: vec![],
548 index_options: vec![],
549 characteristics: None,
550 }),
551 }],
552 },
553 extensions: ColumnExtensions::default(),
554 };
555
556 let grpc_column_def = sql_col_to_grpc_col_def(&column, None).unwrap();
557 assert_eq!(grpc_column_def.semantic_type, SemanticType::Tag as i32);
558 }
559
560 #[test]
561 pub fn test_sql_col_to_grpc_col_def_with_timezone() {
562 let column = Column {
563 column_def: ColumnDef {
564 name: "col".into(),
565 data_type: SqlDataType::Timestamp(Some(3), TimezoneInfo::None),
567 options: vec![ColumnOptionDef {
568 name: None,
569 option: ColumnOption::Default(Expr::Value(
570 SqlValue::SingleQuotedString("2024-01-30T00:01:01".to_string()).into(),
571 )),
572 }],
573 },
574 extensions: ColumnExtensions::default(),
575 };
576
577 let grpc_column_def = sql_col_to_grpc_col_def(
579 &column,
580 Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap()),
581 )
582 .unwrap();
583 assert_eq!("col", grpc_column_def.name);
584 assert!(grpc_column_def.is_nullable); assert_eq!(
586 ColumnDataType::TimestampMillisecond as i32,
587 grpc_column_def.data_type
588 );
589 assert!(!grpc_column_def.default_constraint.is_empty());
590
591 let constraint =
592 ColumnDefaultConstraint::try_from(&grpc_column_def.default_constraint[..]).unwrap();
593 assert!(
594 matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
595 if ts.to_iso8601_string() == "2024-01-29 16:01:01+0000")
596 );
597
598 let grpc_column_def = sql_col_to_grpc_col_def(&column, None).unwrap();
600 assert_eq!("col", grpc_column_def.name);
601 assert!(grpc_column_def.is_nullable); assert_eq!(
603 ColumnDataType::TimestampMillisecond as i32,
604 grpc_column_def.data_type
605 );
606 assert!(!grpc_column_def.default_constraint.is_empty());
607
608 let constraint =
609 ColumnDefaultConstraint::try_from(&grpc_column_def.default_constraint[..]).unwrap();
610 assert!(
611 matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
612 if ts.to_iso8601_string() == "2024-01-30 00:01:01+0000")
613 );
614 }
615
616 #[test]
617 pub fn test_has_primary_key_option() {
618 let column_def = ColumnDef {
619 name: "col".into(),
620 data_type: SqlDataType::Double(ExactNumberInfo::None),
621 options: vec![],
622 };
623 assert!(!has_primary_key_option(&column_def));
624
625 let column_def = ColumnDef {
626 name: "col".into(),
627 data_type: SqlDataType::Double(ExactNumberInfo::None),
628 options: vec![ColumnOptionDef {
629 name: None,
630 option: ColumnOption::PrimaryKey(PrimaryKeyConstraint {
631 name: None,
632 index_name: None,
633 index_type: None,
634 columns: vec![],
635 index_options: vec![],
636 characteristics: None,
637 }),
638 }],
639 };
640 assert!(has_primary_key_option(&column_def));
641 }
642
643 #[test]
644 pub fn test_column_to_schema() {
645 let column_def = Column {
646 column_def: ColumnDef {
647 name: "col".into(),
648 data_type: SqlDataType::Double(ExactNumberInfo::None),
649 options: vec![],
650 },
651 extensions: ColumnExtensions::default(),
652 };
653
654 let column_schema = column_to_schema(&column_def, "ts", None).unwrap();
655
656 assert_eq!("col", column_schema.name);
657 assert_eq!(
658 ConcreteDataType::float64_datatype(),
659 column_schema.data_type
660 );
661 assert!(column_schema.is_nullable());
662 assert!(!column_schema.is_time_index());
663
664 let column_schema = column_to_schema(&column_def, "col", None).unwrap();
665
666 assert_eq!("col", column_schema.name);
667 assert_eq!(
668 ConcreteDataType::float64_datatype(),
669 column_schema.data_type
670 );
671 assert!(!column_schema.is_nullable());
672 assert!(column_schema.is_time_index());
673
674 let column_def = Column {
675 column_def: ColumnDef {
676 name: "col2".into(),
677 data_type: SqlDataType::String(None),
678 options: vec![
679 ColumnOptionDef {
680 name: None,
681 option: ColumnOption::NotNull,
682 },
683 ColumnOptionDef {
684 name: None,
685 option: ColumnOption::Comment("test comment".to_string()),
686 },
687 ],
688 },
689 extensions: ColumnExtensions::default(),
690 };
691
692 let column_schema = column_to_schema(&column_def, "ts", None).unwrap();
693
694 assert_eq!("col2", column_schema.name);
695 assert_eq!(ConcreteDataType::string_datatype(), column_schema.data_type);
696 assert!(!column_schema.is_nullable());
697 assert!(!column_schema.is_time_index());
698 assert_eq!(
699 column_schema.metadata().get(COMMENT_KEY),
700 Some(&"test comment".to_string())
701 );
702 }
703
704 #[test]
705 fn test_new_json2_column_uses_v2_layout() -> std::result::Result<(), Box<dyn std::error::Error>>
706 {
707 let column = Column {
708 column_def: ColumnDef {
709 name: "data".into(),
710 data_type: SqlDataType::Custom(
711 sqlparser::ast::ObjectName::from(vec!["JSON2".into()]),
712 vec![],
713 ),
714 options: vec![],
715 },
716 extensions: ColumnExtensions::default(),
717 };
718
719 let schema = column_to_schema(&column, "ts", None)?;
720 let metadata: serde_json::Value =
721 serde_json::from_str(schema.metadata().get("ARROW:extension:metadata").unwrap())?;
722 assert_eq!(Some(2), metadata["layout_version"].as_u64());
723 assert_eq!(
724 Some(100),
725 metadata["json_settings"]["max_auto_expanded_paths"].as_u64()
726 );
727
728 let mut hinted = column;
729 hinted
730 .extensions
731 .set_json_settings(datatypes::json::JsonSettings::try_new(
732 vec![datatypes::json::JsonTypeHint {
733 path: vec!["kind".to_string()],
734 data_type: ConcreteDataType::string_datatype(),
735 inverted_index: false,
736 }],
737 None,
738 )?)?;
739 let schema = column_to_schema(&hinted, "ts", None)?;
740 let metadata: serde_json::Value =
741 serde_json::from_str(schema.metadata().get("ARROW:extension:metadata").unwrap())?;
742 assert_eq!(
743 Some(100),
744 metadata["json_settings"]["max_auto_expanded_paths"].as_u64()
745 );
746 Ok(())
747 }
748
749 #[test]
750 pub fn test_column_to_schema_timestamp_with_timezone() {
751 let column = Column {
752 column_def: ColumnDef {
753 name: "col".into(),
754 data_type: SqlDataType::Timestamp(Some(3), TimezoneInfo::None),
756 options: vec![ColumnOptionDef {
757 name: None,
758 option: ColumnOption::Default(Expr::Value(
759 SqlValue::SingleQuotedString("2024-01-30T00:01:01".to_string()).into(),
760 )),
761 }],
762 },
763 extensions: ColumnExtensions::default(),
764 };
765
766 let column_schema = column_to_schema(
769 &column,
770 "ts",
771 Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap()),
772 )
773 .unwrap();
774
775 assert_eq!("col", column_schema.name);
776 assert_eq!(
777 ConcreteDataType::timestamp_millisecond_datatype(),
778 column_schema.data_type
779 );
780 assert!(column_schema.is_nullable());
781
782 let constraint = column_schema.default_constraint().unwrap();
783 assert!(
784 matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
785 if ts.to_iso8601_string() == "2024-01-29 16:01:01+0000")
786 );
787
788 let column_schema = column_to_schema(&column, "ts", None).unwrap();
790
791 assert_eq!("col", column_schema.name);
792 assert_eq!(
793 ConcreteDataType::timestamp_millisecond_datatype(),
794 column_schema.data_type
795 );
796 assert!(column_schema.is_nullable());
797
798 let constraint = column_schema.default_constraint().unwrap();
799 assert!(
800 matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
801 if ts.to_iso8601_string() == "2024-01-30 00:01:01+0000")
802 );
803 }
804
805 #[test]
806 fn test_column_to_schema_with_fulltext() {
807 let column = Column {
808 column_def: ColumnDef {
809 name: "col".into(),
810 data_type: SqlDataType::Text,
811 options: vec![],
812 },
813 extensions: ColumnExtensions {
814 fulltext_index_options: Some(OptionMap::from([
815 (
816 COLUMN_FULLTEXT_OPT_KEY_ANALYZER.to_string(),
817 "English".to_string(),
818 ),
819 (
820 COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE.to_string(),
821 "true".to_string(),
822 ),
823 ])),
824 ..Default::default()
825 },
826 };
827
828 let column_schema = column_to_schema(&column, "ts", None).unwrap();
829 assert_eq!("col", column_schema.name);
830 assert_eq!(ConcreteDataType::string_datatype(), column_schema.data_type);
831 let fulltext_options = column_schema.fulltext_options().unwrap().unwrap();
832 assert_eq!(fulltext_options.analyzer, FulltextAnalyzer::English);
833 assert!(fulltext_options.case_sensitive);
834 }
835}