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