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