Skip to main content

sql/
statements.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub 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    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        // TODO(dennis): supports binary
86        _ => return ConvertValueSnafu { value: val.clone() }.fail(),
87    })
88}
89
90/// Return true when the `ColumnDef` options contain primary key
91pub 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
98/// Create a `ColumnSchema` from `Column`.
99pub 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    column_schema.set_inverted_index(column.extensions.inverted_index_options.is_some());
150
151    let is_json2_column = if let SqlDataType::Custom(object_name, _) = column.data_type() {
152        object_name
153            .0
154            .first()
155            .map(|x| x.to_string_unquoted().eq_ignore_ascii_case(JSON2_TYPE_NAME))
156            .unwrap_or_default()
157    } else {
158        false
159    };
160    if is_json2_column {
161        let settings = column
162            .extensions
163            .build_json_settings()?
164            .unwrap_or_else(JsonSettings::new_v2);
165        let extension = Json2ExtensionType::new(Arc::new(JsonMetadata::new(settings)));
166        column_schema.with_extension_type(&extension);
167    }
168
169    Ok(column_schema)
170}
171
172/// Convert `ColumnDef` in sqlparser to `ColumnDef` in gRPC proto.
173pub fn sql_column_def_to_grpc_column_def(
174    col: &ColumnDef,
175    timezone: Option<&Timezone>,
176) -> Result<api::v1::ColumnDef> {
177    let name = col.name.value.clone();
178    let data_type = sql_data_type_to_concrete_data_type(&col.data_type)?;
179
180    let is_nullable = col
181        .options
182        .iter()
183        .all(|o| !matches!(o.option, ColumnOption::NotNull));
184
185    let default_constraint =
186        parse_column_default_constraint(&name, &data_type, &col.options, timezone)
187            .context(SqlCommonSnafu)?
188            .map(ColumnDefaultConstraint::try_into) // serialize default constraint to bytes
189            .transpose()
190            .context(SerializeColumnDefaultConstraintSnafu)?;
191    // convert ConcreteDataType to grpc ColumnDataTypeWrapper
192    let (datatype, datatype_ext) = ColumnDataTypeWrapper::try_from(data_type.clone())
193        .context(ConvertToGrpcDataTypeSnafu)?
194        .to_parts();
195
196    let is_primary_key = col
197        .options
198        .iter()
199        .any(|o| matches!(o.option, ColumnOption::PrimaryKey(..)));
200
201    let semantic_type = if is_primary_key {
202        SemanticType::Tag
203    } else {
204        SemanticType::Field
205    };
206
207    Ok(api::v1::ColumnDef {
208        name,
209        data_type: datatype as i32,
210        is_nullable,
211        default_constraint: default_constraint.unwrap_or_default(),
212        semantic_type: semantic_type as _,
213        comment: String::new(),
214        datatype_extension: datatype_ext,
215        options: None,
216    })
217}
218
219pub fn sql_data_type_to_concrete_data_type(data_type: &SqlDataType) -> Result<ConcreteDataType> {
220    match data_type {
221        SqlDataType::BigInt(_) | SqlDataType::Int64 => Ok(ConcreteDataType::int64_datatype()),
222        SqlDataType::BigIntUnsigned(_) | SqlDataType::UInt64 => {
223            Ok(ConcreteDataType::uint64_datatype())
224        }
225        SqlDataType::Int(_) | SqlDataType::Integer(_) => Ok(ConcreteDataType::int32_datatype()),
226        SqlDataType::IntUnsigned(_) | SqlDataType::UnsignedInteger => {
227            Ok(ConcreteDataType::uint32_datatype())
228        }
229        SqlDataType::SmallInt(_) => Ok(ConcreteDataType::int16_datatype()),
230        SqlDataType::SmallIntUnsigned(_) => Ok(ConcreteDataType::uint16_datatype()),
231        SqlDataType::TinyInt(_) | SqlDataType::Int8(_) => Ok(ConcreteDataType::int8_datatype()),
232        SqlDataType::TinyIntUnsigned(_) | SqlDataType::Int8Unsigned(_) => {
233            Ok(ConcreteDataType::uint8_datatype())
234        }
235        SqlDataType::Char(_)
236        | SqlDataType::Varchar(_)
237        | SqlDataType::Text
238        | SqlDataType::TinyText
239        | SqlDataType::MediumText
240        | SqlDataType::LongText
241        | SqlDataType::String(_) => Ok(ConcreteDataType::string_datatype()),
242        SqlDataType::Float(_) => Ok(ConcreteDataType::float32_datatype()),
243        SqlDataType::Double(_) | SqlDataType::Float64 => Ok(ConcreteDataType::float64_datatype()),
244        SqlDataType::Boolean => Ok(ConcreteDataType::boolean_datatype()),
245        SqlDataType::Date => Ok(ConcreteDataType::date_datatype()),
246        SqlDataType::Binary(_)
247        | SqlDataType::Blob(_)
248        | SqlDataType::Bytea
249        | SqlDataType::Varbinary(_) => Ok(ConcreteDataType::binary_datatype()),
250        SqlDataType::Datetime(_) => Ok(ConcreteDataType::timestamp_microsecond_datatype()),
251        SqlDataType::Timestamp(precision, _) => Ok(precision
252            .as_ref()
253            .map(|v| TimestampType::try_from(*v))
254            .transpose()
255            .map_err(|_| {
256                error::SqlTypeNotSupportedSnafu {
257                    t: data_type.clone(),
258                }
259                .build()
260            })?
261            .map(|t| ConcreteDataType::timestamp_datatype(t.unit()))
262            .unwrap_or(ConcreteDataType::timestamp_millisecond_datatype())),
263        SqlDataType::Interval { .. } => Ok(ConcreteDataType::interval_month_day_nano_datatype()),
264        SqlDataType::Decimal(exact_info) => match exact_info {
265            ExactNumberInfo::None => Ok(ConcreteDataType::decimal128_default_datatype()),
266            // refer to https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html
267            // In standard SQL, the syntax DECIMAL(M) is equivalent to DECIMAL(M,0).
268            ExactNumberInfo::Precision(p) => Ok(ConcreteDataType::decimal128_datatype(*p as u8, 0)),
269            ExactNumberInfo::PrecisionAndScale(p, s) => {
270                Ok(ConcreteDataType::decimal128_datatype(*p as u8, *s as i8))
271            }
272        },
273        SqlDataType::JSON => Ok(ConcreteDataType::Json(JsonType::new(JsonFormat::Jsonb))),
274        // Vector type and JSON2 type
275        SqlDataType::Custom(name, args) if name.0.len() == 1 => {
276            let name = name.0[0].to_string_unquoted().to_ascii_uppercase();
277            match name.as_str() {
278                VECTOR_TYPE_NAME if args.len() == 1 => {
279                    let dim = &args[0];
280                    let dim = dim.parse().map_err(|e| {
281                        error::ParseSqlValueSnafu {
282                            msg: format!("Failed to parse vector dimension '{}': {}", dim, e),
283                        }
284                        .build()
285                    })?;
286                    Ok(ConcreteDataType::vector_datatype(dim))
287                }
288                JSON2_TYPE_NAME if args.is_empty() => {
289                    // Currently, JSON2 is not inferred as any native type initially.
290                    // TODO(fys): infer it later from type hints.
291                    let format = JsonFormat::Json2(Arc::new(JsonNativeType::Null));
292                    Ok(ConcreteDataType::Json(JsonType::new(format)))
293                }
294                _ => error::SqlTypeNotSupportedSnafu {
295                    t: data_type.clone(),
296                }
297                .fail(),
298            }
299        }
300        _ => error::SqlTypeNotSupportedSnafu {
301            t: data_type.clone(),
302        }
303        .fail(),
304    }
305}
306
307pub fn concrete_data_type_to_sql_data_type(data_type: &ConcreteDataType) -> Result<SqlDataType> {
308    match data_type {
309        ConcreteDataType::Int64(_) => Ok(SqlDataType::BigInt(None)),
310        ConcreteDataType::UInt64(_) => Ok(SqlDataType::BigIntUnsigned(None)),
311        ConcreteDataType::Int32(_) => Ok(SqlDataType::Int(None)),
312        ConcreteDataType::UInt32(_) => Ok(SqlDataType::IntUnsigned(None)),
313        ConcreteDataType::Int16(_) => Ok(SqlDataType::SmallInt(None)),
314        ConcreteDataType::UInt16(_) => Ok(SqlDataType::SmallIntUnsigned(None)),
315        ConcreteDataType::Int8(_) => Ok(SqlDataType::TinyInt(None)),
316        ConcreteDataType::UInt8(_) => Ok(SqlDataType::TinyIntUnsigned(None)),
317        ConcreteDataType::String(_) => Ok(SqlDataType::String(None)),
318        ConcreteDataType::Float32(_) => Ok(SqlDataType::Float(ExactNumberInfo::None)),
319        ConcreteDataType::Float64(_) => Ok(SqlDataType::Double(ExactNumberInfo::None)),
320        ConcreteDataType::Boolean(_) => Ok(SqlDataType::Boolean),
321        ConcreteDataType::Date(_) => Ok(SqlDataType::Date),
322        ConcreteDataType::Timestamp(ts_type) => Ok(SqlDataType::Timestamp(
323            Some(ts_type.precision()),
324            TimezoneInfo::None,
325        )),
326        ConcreteDataType::Time(time_type) => Ok(SqlDataType::Time(
327            Some(time_type.precision()),
328            TimezoneInfo::None,
329        )),
330        ConcreteDataType::Interval(_) => Ok(SqlDataType::Interval {
331            fields: None,
332            precision: None,
333        }),
334        ConcreteDataType::Binary(_) => Ok(SqlDataType::Varbinary(None)),
335        ConcreteDataType::Decimal128(d) => Ok(SqlDataType::Decimal(
336            ExactNumberInfo::PrecisionAndScale(d.precision() as u64, d.scale() as i64),
337        )),
338        ConcreteDataType::Json(_) => Ok(SqlDataType::JSON),
339        ConcreteDataType::Vector(v) => Ok(SqlDataType::Custom(
340            vec![Ident::new(VECTOR_TYPE_NAME)].into(),
341            vec![v.dim.to_string()],
342        )),
343        ConcreteDataType::Duration(_)
344        | ConcreteDataType::Null(_)
345        | ConcreteDataType::List(_)
346        | ConcreteDataType::Struct(_)
347        | ConcreteDataType::Dictionary(_) => error::ConcreteTypeNotSupportedSnafu {
348            t: data_type.clone(),
349        }
350        .fail(),
351    }
352}
353
354#[cfg(test)]
355mod tests {
356    use api::v1::ColumnDataType;
357    use datatypes::schema::{
358        COLUMN_FULLTEXT_OPT_KEY_ANALYZER, COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE, FulltextAnalyzer,
359    };
360    use sqlparser::ast::{ColumnOptionDef, Expr, PrimaryKeyConstraint};
361
362    use super::*;
363    use crate::ast::TimezoneInfo;
364    use crate::statements::ColumnOption;
365    use crate::statements::create::ColumnExtensions;
366
367    fn check_type(sql_type: SqlDataType, data_type: ConcreteDataType) {
368        assert_eq!(
369            data_type,
370            sql_data_type_to_concrete_data_type(&sql_type).unwrap()
371        );
372    }
373
374    #[test]
375    pub fn test_sql_data_type_to_concrete_data_type() {
376        check_type(
377            SqlDataType::BigInt(None),
378            ConcreteDataType::int64_datatype(),
379        );
380        check_type(SqlDataType::Int(None), ConcreteDataType::int32_datatype());
381        check_type(
382            SqlDataType::Integer(None),
383            ConcreteDataType::int32_datatype(),
384        );
385        check_type(
386            SqlDataType::SmallInt(None),
387            ConcreteDataType::int16_datatype(),
388        );
389        check_type(SqlDataType::Char(None), ConcreteDataType::string_datatype());
390        check_type(
391            SqlDataType::Varchar(None),
392            ConcreteDataType::string_datatype(),
393        );
394        check_type(SqlDataType::Text, ConcreteDataType::string_datatype());
395        check_type(
396            SqlDataType::String(None),
397            ConcreteDataType::string_datatype(),
398        );
399        check_type(
400            SqlDataType::Float(ExactNumberInfo::None),
401            ConcreteDataType::float32_datatype(),
402        );
403        check_type(
404            SqlDataType::Double(ExactNumberInfo::None),
405            ConcreteDataType::float64_datatype(),
406        );
407        check_type(SqlDataType::Boolean, ConcreteDataType::boolean_datatype());
408        check_type(SqlDataType::Date, ConcreteDataType::date_datatype());
409        check_type(
410            SqlDataType::Timestamp(None, TimezoneInfo::None),
411            ConcreteDataType::timestamp_millisecond_datatype(),
412        );
413        check_type(
414            SqlDataType::Varbinary(None),
415            ConcreteDataType::binary_datatype(),
416        );
417        check_type(
418            SqlDataType::BigIntUnsigned(None),
419            ConcreteDataType::uint64_datatype(),
420        );
421        check_type(SqlDataType::UInt64, ConcreteDataType::uint64_datatype());
422        check_type(
423            SqlDataType::IntUnsigned(None),
424            ConcreteDataType::uint32_datatype(),
425        );
426        check_type(
427            SqlDataType::SmallIntUnsigned(None),
428            ConcreteDataType::uint16_datatype(),
429        );
430        check_type(
431            SqlDataType::TinyIntUnsigned(None),
432            ConcreteDataType::uint8_datatype(),
433        );
434        check_type(
435            SqlDataType::Datetime(None),
436            ConcreteDataType::timestamp_microsecond_datatype(),
437        );
438        check_type(
439            SqlDataType::Interval {
440                fields: None,
441                precision: None,
442            },
443            ConcreteDataType::interval_month_day_nano_datatype(),
444        );
445        check_type(SqlDataType::JSON, ConcreteDataType::json_datatype());
446        check_type(
447            SqlDataType::Custom(
448                vec![Ident::new(VECTOR_TYPE_NAME)].into(),
449                vec!["3".to_string()],
450            ),
451            ConcreteDataType::vector_datatype(3),
452        );
453    }
454
455    #[test]
456    pub fn test_sql_column_def_to_grpc_column_def() {
457        // test basic
458        let column_def = ColumnDef {
459            name: "col".into(),
460            data_type: SqlDataType::Double(ExactNumberInfo::None),
461            options: vec![],
462        };
463
464        let grpc_column_def = sql_column_def_to_grpc_column_def(&column_def, None).unwrap();
465
466        assert_eq!("col", grpc_column_def.name);
467        assert!(grpc_column_def.is_nullable); // nullable when options are empty
468        assert_eq!(ColumnDataType::Float64 as i32, grpc_column_def.data_type);
469        assert!(grpc_column_def.default_constraint.is_empty());
470        assert_eq!(grpc_column_def.semantic_type, SemanticType::Field as i32);
471
472        // test not null
473        let column_def = ColumnDef {
474            name: "col".into(),
475            data_type: SqlDataType::Double(ExactNumberInfo::None),
476            options: vec![ColumnOptionDef {
477                name: None,
478                option: ColumnOption::NotNull,
479            }],
480        };
481
482        let grpc_column_def = sql_column_def_to_grpc_column_def(&column_def, None).unwrap();
483        assert!(!grpc_column_def.is_nullable);
484
485        // test primary key
486        let column_def = ColumnDef {
487            name: "col".into(),
488            data_type: SqlDataType::Double(ExactNumberInfo::None),
489            options: vec![ColumnOptionDef {
490                name: None,
491                option: ColumnOption::PrimaryKey(PrimaryKeyConstraint {
492                    name: None,
493                    index_name: None,
494                    index_type: None,
495                    columns: vec![],
496                    index_options: vec![],
497                    characteristics: None,
498                }),
499            }],
500        };
501
502        let grpc_column_def = sql_column_def_to_grpc_column_def(&column_def, None).unwrap();
503        assert_eq!(grpc_column_def.semantic_type, SemanticType::Tag as i32);
504    }
505
506    #[test]
507    pub fn test_sql_column_def_to_grpc_column_def_with_timezone() {
508        let column_def = ColumnDef {
509            name: "col".into(),
510            // MILLISECOND
511            data_type: SqlDataType::Timestamp(Some(3), TimezoneInfo::None),
512            options: vec![ColumnOptionDef {
513                name: None,
514                option: ColumnOption::Default(Expr::Value(
515                    SqlValue::SingleQuotedString("2024-01-30T00:01:01".to_string()).into(),
516                )),
517            }],
518        };
519
520        // with timezone "Asia/Shanghai"
521        let grpc_column_def = sql_column_def_to_grpc_column_def(
522            &column_def,
523            Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap()),
524        )
525        .unwrap();
526        assert_eq!("col", grpc_column_def.name);
527        assert!(grpc_column_def.is_nullable); // nullable when options are empty
528        assert_eq!(
529            ColumnDataType::TimestampMillisecond as i32,
530            grpc_column_def.data_type
531        );
532        assert!(!grpc_column_def.default_constraint.is_empty());
533
534        let constraint =
535            ColumnDefaultConstraint::try_from(&grpc_column_def.default_constraint[..]).unwrap();
536        assert!(
537            matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
538                         if ts.to_iso8601_string() == "2024-01-29 16:01:01+0000")
539        );
540
541        // without timezone
542        let grpc_column_def = sql_column_def_to_grpc_column_def(&column_def, None).unwrap();
543        assert_eq!("col", grpc_column_def.name);
544        assert!(grpc_column_def.is_nullable); // nullable when options are empty
545        assert_eq!(
546            ColumnDataType::TimestampMillisecond as i32,
547            grpc_column_def.data_type
548        );
549        assert!(!grpc_column_def.default_constraint.is_empty());
550
551        let constraint =
552            ColumnDefaultConstraint::try_from(&grpc_column_def.default_constraint[..]).unwrap();
553        assert!(
554            matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
555                         if ts.to_iso8601_string() == "2024-01-30 00:01:01+0000")
556        );
557    }
558
559    #[test]
560    pub fn test_has_primary_key_option() {
561        let column_def = ColumnDef {
562            name: "col".into(),
563            data_type: SqlDataType::Double(ExactNumberInfo::None),
564            options: vec![],
565        };
566        assert!(!has_primary_key_option(&column_def));
567
568        let column_def = ColumnDef {
569            name: "col".into(),
570            data_type: SqlDataType::Double(ExactNumberInfo::None),
571            options: vec![ColumnOptionDef {
572                name: None,
573                option: ColumnOption::PrimaryKey(PrimaryKeyConstraint {
574                    name: None,
575                    index_name: None,
576                    index_type: None,
577                    columns: vec![],
578                    index_options: vec![],
579                    characteristics: None,
580                }),
581            }],
582        };
583        assert!(has_primary_key_option(&column_def));
584    }
585
586    #[test]
587    pub fn test_column_to_schema() {
588        let column_def = Column {
589            column_def: ColumnDef {
590                name: "col".into(),
591                data_type: SqlDataType::Double(ExactNumberInfo::None),
592                options: vec![],
593            },
594            extensions: ColumnExtensions::default(),
595        };
596
597        let column_schema = column_to_schema(&column_def, "ts", None).unwrap();
598
599        assert_eq!("col", column_schema.name);
600        assert_eq!(
601            ConcreteDataType::float64_datatype(),
602            column_schema.data_type
603        );
604        assert!(column_schema.is_nullable());
605        assert!(!column_schema.is_time_index());
606
607        let column_schema = column_to_schema(&column_def, "col", None).unwrap();
608
609        assert_eq!("col", column_schema.name);
610        assert_eq!(
611            ConcreteDataType::float64_datatype(),
612            column_schema.data_type
613        );
614        assert!(!column_schema.is_nullable());
615        assert!(column_schema.is_time_index());
616
617        let column_def = Column {
618            column_def: ColumnDef {
619                name: "col2".into(),
620                data_type: SqlDataType::String(None),
621                options: vec![
622                    ColumnOptionDef {
623                        name: None,
624                        option: ColumnOption::NotNull,
625                    },
626                    ColumnOptionDef {
627                        name: None,
628                        option: ColumnOption::Comment("test comment".to_string()),
629                    },
630                ],
631            },
632            extensions: ColumnExtensions::default(),
633        };
634
635        let column_schema = column_to_schema(&column_def, "ts", None).unwrap();
636
637        assert_eq!("col2", column_schema.name);
638        assert_eq!(ConcreteDataType::string_datatype(), column_schema.data_type);
639        assert!(!column_schema.is_nullable());
640        assert!(!column_schema.is_time_index());
641        assert_eq!(
642            column_schema.metadata().get(COMMENT_KEY),
643            Some(&"test comment".to_string())
644        );
645    }
646
647    #[test]
648    fn test_new_json2_column_uses_v2_layout() -> std::result::Result<(), Box<dyn std::error::Error>>
649    {
650        let column = Column {
651            column_def: ColumnDef {
652                name: "data".into(),
653                data_type: SqlDataType::Custom(
654                    sqlparser::ast::ObjectName::from(vec!["JSON2".into()]),
655                    vec![],
656                ),
657                options: vec![],
658            },
659            extensions: ColumnExtensions::default(),
660        };
661
662        let schema = column_to_schema(&column, "ts", None)?;
663        let metadata: serde_json::Value =
664            serde_json::from_str(schema.metadata().get("ARROW:extension:metadata").unwrap())?;
665        assert_eq!(Some(2), metadata["layout_version"].as_u64());
666        assert_eq!(
667            Some(100),
668            metadata["json_settings"]["max_auto_expanded_paths"].as_u64()
669        );
670
671        let mut hinted = column;
672        hinted
673            .extensions
674            .set_json_settings(datatypes::json::JsonSettings::try_new(
675                vec![datatypes::json::JsonTypeHint {
676                    path: vec!["kind".to_string()],
677                    data_type: ConcreteDataType::string_datatype(),
678                    inverted_index: false,
679                }],
680                None,
681            )?)?;
682        let schema = column_to_schema(&hinted, "ts", None)?;
683        let metadata: serde_json::Value =
684            serde_json::from_str(schema.metadata().get("ARROW:extension:metadata").unwrap())?;
685        assert_eq!(
686            Some(100),
687            metadata["json_settings"]["max_auto_expanded_paths"].as_u64()
688        );
689        Ok(())
690    }
691
692    #[test]
693    pub fn test_column_to_schema_timestamp_with_timezone() {
694        let column = Column {
695            column_def: ColumnDef {
696                name: "col".into(),
697                // MILLISECOND
698                data_type: SqlDataType::Timestamp(Some(3), TimezoneInfo::None),
699                options: vec![ColumnOptionDef {
700                    name: None,
701                    option: ColumnOption::Default(Expr::Value(
702                        SqlValue::SingleQuotedString("2024-01-30T00:01:01".to_string()).into(),
703                    )),
704                }],
705            },
706            extensions: ColumnExtensions::default(),
707        };
708
709        // with timezone "Asia/Shanghai"
710
711        let column_schema = column_to_schema(
712            &column,
713            "ts",
714            Some(&Timezone::from_tz_string("Asia/Shanghai").unwrap()),
715        )
716        .unwrap();
717
718        assert_eq!("col", column_schema.name);
719        assert_eq!(
720            ConcreteDataType::timestamp_millisecond_datatype(),
721            column_schema.data_type
722        );
723        assert!(column_schema.is_nullable());
724
725        let constraint = column_schema.default_constraint().unwrap();
726        assert!(
727            matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
728                         if ts.to_iso8601_string() == "2024-01-29 16:01:01+0000")
729        );
730
731        // without timezone
732        let column_schema = column_to_schema(&column, "ts", None).unwrap();
733
734        assert_eq!("col", column_schema.name);
735        assert_eq!(
736            ConcreteDataType::timestamp_millisecond_datatype(),
737            column_schema.data_type
738        );
739        assert!(column_schema.is_nullable());
740
741        let constraint = column_schema.default_constraint().unwrap();
742        assert!(
743            matches!(constraint, ColumnDefaultConstraint::Value(Value::Timestamp(ts))
744                         if ts.to_iso8601_string() == "2024-01-30 00:01:01+0000")
745        );
746    }
747
748    #[test]
749    fn test_column_to_schema_with_fulltext() {
750        let column = Column {
751            column_def: ColumnDef {
752                name: "col".into(),
753                data_type: SqlDataType::Text,
754                options: vec![],
755            },
756            extensions: ColumnExtensions {
757                fulltext_index_options: Some(OptionMap::from([
758                    (
759                        COLUMN_FULLTEXT_OPT_KEY_ANALYZER.to_string(),
760                        "English".to_string(),
761                    ),
762                    (
763                        COLUMN_FULLTEXT_OPT_KEY_CASE_SENSITIVE.to_string(),
764                        "true".to_string(),
765                    ),
766                ])),
767                ..Default::default()
768            },
769        };
770
771        let column_schema = column_to_schema(&column, "ts", None).unwrap();
772        assert_eq!("col", column_schema.name);
773        assert_eq!(ConcreteDataType::string_datatype(), column_schema.data_type);
774        let fulltext_options = column_schema.fulltext_options().unwrap().unwrap();
775        assert_eq!(fulltext_options.analyzer, FulltextAnalyzer::English);
776        assert!(fulltext_options.case_sensitive);
777    }
778}