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