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