diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 64c4d114a..b732d098a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -45,16 +45,6 @@ jobs: - uses: actions/checkout@master - run: cargo doc --document-private-items --no-deps --workspace --all-features - compile-no-std: - runs-on: ubuntu-latest - steps: - - name: Set up Rust - uses: hecrj/setup-rust-action@v1 - with: - targets: 'thumbv6m-none-eabi' - - uses: actions/checkout@master - - run: cargo check --no-default-features --target thumbv6m-none-eabi - test: strategy: matrix: diff --git a/Cargo.toml b/Cargo.toml index ed3d88b9f..7610d5360 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,11 +8,7 @@ documentation = "https://docs.rs/sqlparser/" keywords = ["ansi", "sql", "lexer", "parser"] repository = "https://github.com/sqlparser-rs/sqlparser-rs" license = "Apache-2.0" -include = [ - "src/**/*.rs", - "Cargo.toml", - "LICENSE.TXT", -] +include = ["src/**/*.rs", "Cargo.toml", "LICENSE.TXT"] edition = "2021" [lib] @@ -24,17 +20,21 @@ default = ["std"] std = [] # Enable JSON output in the `cli` example: json_example = ["serde_json", "serde"] -visitor = ["sqlparser_derive"] +visitor = [] +bigdecimal-sql = ["bigdecimal", "df_sqlparser/bigdecimal"] [dependencies] bigdecimal = { version = "0.4.1", features = ["serde"], optional = true } +df_sqlparser = { package = "sqlparser", version = "0.44.0" } log = "0.4" serde = { version = "1.0", features = ["derive"], optional = true } # serde_json is only used in examples/cli, but we have to put it outside # of dev-dependencies because of # https://github.com/rust-lang/cargo/issues/1596 serde_json = { version = "1.0", optional = true } -sqlparser_derive = { version = "0.2.0", path = "derive", optional = true } +sqlparser_derive = { version = "0.2.0", path = "derive" } +regex = "1" +lazy_static = "1.4.0" [dev-dependencies] simple_logger = "4.0" diff --git a/derive/src/lib.rs b/derive/src/lib.rs index d19696aa4..b8ccd19a3 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,31 +1,40 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Literal, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::spanned::Spanned; use syn::{ parse::{Parse, ParseStream}, - parse_macro_input, parse_quote, Attribute, Data, DeriveInput, - Fields, GenericParam, Generics, Ident, Index, LitStr, Meta, Token + parse_macro_input, parse_quote, Attribute, Data, DeriveInput, Fields, GenericParam, Generics, + Ident, Index, LitStr, Meta, Token, +}; +use syn::{ + AngleBracketedGenericArguments, DataEnum, DataStruct, FieldsNamed, FieldsUnnamed, + GenericArgument, MetaList, Path, PathArguments, PathSegment, Type, TypePath, }; - /// Implementation of `[#derive(Visit)]` #[proc_macro_derive(VisitMut, attributes(visit))] pub fn derive_visit_mut(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - derive_visit(input, &VisitType { - visit_trait: quote!(VisitMut), - visitor_trait: quote!(VisitorMut), - modifier: Some(quote!(mut)), - }) + derive_visit( + input, + &VisitType { + visit_trait: quote!(VisitMut), + visitor_trait: quote!(VisitorMut), + modifier: Some(quote!(mut)), + }, + ) } /// Implementation of `[#derive(Visit)]` #[proc_macro_derive(Visit, attributes(visit))] pub fn derive_visit_immutable(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - derive_visit(input, &VisitType { - visit_trait: quote!(Visit), - visitor_trait: quote!(Visitor), - modifier: None, - }) + derive_visit( + input, + &VisitType { + visit_trait: quote!(Visit), + visitor_trait: quote!(Visitor), + modifier: None, + }, + ) } struct VisitType { @@ -34,15 +43,16 @@ struct VisitType { modifier: Option, } -fn derive_visit( - input: proc_macro::TokenStream, - visit_type: &VisitType, -) -> proc_macro::TokenStream { +fn derive_visit(input: proc_macro::TokenStream, visit_type: &VisitType) -> proc_macro::TokenStream { // Parse the input tokens into a syntax tree. let input = parse_macro_input!(input as DeriveInput); let name = input.ident; - let VisitType { visit_trait, visitor_trait, modifier } = visit_type; + let VisitType { + visit_trait, + visitor_trait, + modifier, + } = visit_type; let attributes = Attributes::parse(&input.attrs); // Add a bound `T: Visit` to every type parameter T. @@ -87,7 +97,10 @@ impl Parse for WithIdent { let mut result = WithIdent { with: None }; let ident = input.parse::()?; if ident != "with" { - return Err(syn::Error::new(ident.span(), "Expected identifier to be `with`")); + return Err(syn::Error::new( + ident.span(), + "Expected identifier to be `with`", + )); } input.parse::()?; let s = input.parse::()?; @@ -131,17 +144,26 @@ impl Attributes { } // Add a bound `T: Visit` to every type parameter T. -fn add_trait_bounds(mut generics: Generics, VisitType{visit_trait, ..}: &VisitType) -> Generics { +fn add_trait_bounds(mut generics: Generics, VisitType { visit_trait, .. }: &VisitType) -> Generics { for param in &mut generics.params { if let GenericParam::Type(ref mut type_param) = *param { - type_param.bounds.push(parse_quote!(sqlparser::ast::#visit_trait)); + type_param + .bounds + .push(parse_quote!(sqlparser::ast::#visit_trait)); } } generics } // Generate the body of the visit implementation for the given type -fn visit_children(data: &Data, VisitType{visit_trait, modifier, ..}: &VisitType) -> TokenStream { +fn visit_children( + data: &Data, + VisitType { + visit_trait, + modifier, + .. + }: &VisitType, +) -> TokenStream { match data { Data::Struct(data) => match &data.fields { Fields::Named(fields) => { @@ -221,3 +243,286 @@ fn visit_children(data: &Data, VisitType{visit_trait, modifier, ..}: &VisitType) Data::Union(_) => unimplemented!(), } } + +/// Determine the variable type to decide which method in the `Convert` trait to use +fn get_var_type(ty: &Type) -> proc_macro2::TokenStream { + let span = ty.span(); + if let Type::Path(TypePath { + path: Path { segments, .. }, + .. + }) = ty + { + if let Some(PathSegment { ident, arguments }) = segments.first() { + return match ident.to_string().as_str() { + "Option" => { + if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args, + .. + }) = arguments + { + if let Some(GenericArgument::Type(Type::Path(TypePath { + path: Path { segments, .. }, + .. + }))) = args.first() + { + if let Some(PathSegment { ident, .. }) = segments.first() { + return match ident.to_string().as_str() { + "Box" => quote_spanned!(span => Convert::convert_option_box), + "Vec" => quote_spanned!(span => Convert::convert_option_vec), + _ => quote_spanned!(span => Convert::convert_option), + }; + } + } + } + quote_spanned!(span => Convert::convert_option) + } + "Vec" => { + if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args, + .. + }) = arguments + { + if let Some(GenericArgument::Type(Type::Path(TypePath { + path: Path { segments, .. }, + .. + }))) = args.first() + { + if let Some(PathSegment { ident, .. }) = segments.first() { + return match ident.to_string().as_str() { + "Vec" => quote_spanned!(span => Convert::convert_matrix), + "Box" => quote_spanned!(span => Convert::convert_vec_box), + _ => quote_spanned!(span => Convert::convert_vec), + }; + } + } + } + quote_spanned!(span => Convert::convert_vec) + } + "Box" => quote_spanned!(span => Convert::convert_box), + _ => quote_spanned!(span => Convert::convert), + }; + } + } + quote_spanned!(span => Convert::convert) +} + +/// Obtain the struct path where `datafusion` `sqlparser` is located from derive macro helper attribute `df_path`, +/// if value not given, the default return is `df_sqlparser::ast` +fn get_crate_path(st: &syn::DeriveInput) -> proc_macro2::TokenStream { + let span = st.span(); + for attr in &st.attrs { + let Meta::List(MetaList { + path: Path { segments, .. }, + tokens, + .. + }) = &attr.meta + else { + continue; + }; + if let Some(PathSegment { ident, .. }) = segments.first() { + if ident.to_string().as_str() == "df_path" { + return tokens.clone(); + } + } + } + quote_spanned!(span => df_sqlparser::ast) +} + +/// Check whether the attribute `ignore_item` exists. If the attribute exists, +/// the corresponding convert method will not be generated. +/// If exist attribute `ignore_item` +/// 1. enum conversion returns panic +/// 2. struct conversion does not generate the corresponding field +fn ignore_convert(attrs: &Vec) -> bool { + for attr in attrs { + let Meta::Path(Path { segments, .. }) = &attr.meta else { + continue; + }; + if let Some(PathSegment { ident, .. }) = segments.first() { + if ident.to_string().as_str() == "ignore_item" { + return true; + } + } + } + false +} + +fn convert_struct(st: &syn::DeriveInput) -> proc_macro2::TokenStream { + let name = &st.ident; + let path = get_crate_path(st); + // for struct pattern like + // struct xxx { + // xxx: xxx + // } + if let Data::Struct(DataStruct { + fields: Fields::Named(FieldsNamed { named, .. }), + .. + }) = &st.data + { + let span = named.span(); + let mut fields: Vec = Vec::with_capacity(named.len()); + for field in named { + if ignore_convert(&field.attrs) { + continue; + } + let field_name = field.ident.clone().unwrap(); + let var_type = get_var_type(&field.ty); + let span = field_name.span(); + let code = quote_spanned! { span => + #field_name: #var_type(value.#field_name), + }; + fields.push(code); + } + return quote_spanned! { span => + impl From<#name> for #path::#name { + #[allow(unused_variables)] + fn from(value: #name) -> Self { + Self { + #(#fields)* + } + } + } + }; + } + // for struct pattern like + // struct xxx(xxxx); + if let Data::Struct(DataStruct { + fields: Fields::Unnamed(FieldsUnnamed { unnamed, .. }), + .. + }) = &st.data + { + let span = unnamed.span(); + let mut fields: Vec = Vec::with_capacity(unnamed.len()); + for i in 0..unnamed.len() { + if ignore_convert(&unnamed[i].attrs) { + continue; + } + let field_name = Literal::usize_unsuffixed(i); + let var_type = get_var_type(&unnamed[i].ty); + let span = unnamed[i].span(); + let code = quote_spanned! { span => + #var_type(value.#field_name), + }; + fields.push(code); + } + return quote_spanned! { span => + impl From<#name> for #path::#name { + #[allow(unused_variables)] + fn from(value: #name) -> Self { + Self(#(#fields)*) + } + } + }; + } + panic!("Unrecognised Struct Type{}", st.to_token_stream()) +} + +fn convert_enum(st: &DeriveInput) -> proc_macro2::TokenStream { + let name = &st.ident; + let path = get_crate_path(st); + if let Data::Enum(DataEnum { variants, .. }) = &st.data { + let span = variants.span(); + let mut fields: Vec = Vec::with_capacity(variants.len()); + for field in variants { + let enum_name = &field.ident; + let span = enum_name.span(); + let ignore_convert = ignore_convert(&field.attrs); + // for enum item like xxxxxx(xxx) + if let Fields::Unnamed(FieldsUnnamed { unnamed, .. }) = &field.fields { + let inner_names = ('a'..='z') + .map(|x| Ident::new(x.to_string().as_str(), unnamed.span())) + .collect::>()[..unnamed.len()] + .to_vec(); + let mut codes: Vec = Vec::with_capacity(unnamed.len()); + let inner_fields: Vec<_> = inner_names.iter().map(|x| quote!(#x,)).collect(); + for (inner_name, field) in inner_names.iter().zip(unnamed.iter()) { + let var_type = get_var_type(&field.ty); + let span = field.span(); + codes.push(quote_spanned! { span => + #var_type(#inner_name), + }); + } + fields.push(if ignore_convert { + quote_spanned! { span => + #name::#enum_name(#(#inner_fields)*) => panic!("Convert on this item is ignored"), + } + } else { + quote_spanned! { span => + #name::#enum_name(#(#inner_fields)*) => Self::#enum_name(#(#codes)*), + } + }); + } + // for enum item like + // xxxxxx { + // xxx: xxxx, + // }, + if let Fields::Named(FieldsNamed { named, .. }) = &field.fields { + let mut inner_fields: Vec = + Vec::with_capacity(named.len()); + let mut codes: Vec = Vec::with_capacity(named.len()); + let span = named.span(); + for field in named { + let field_name = field.ident.clone().unwrap(); + let span = field_name.span(); + let var_type = get_var_type(&field.ty); + inner_fields.push(quote_spanned!(span => #field_name,)); + codes.push(quote_spanned! { span => + #field_name: #var_type(#field_name), + }); + } + fields.push(if ignore_convert { + quote_spanned! { span => + #name::#enum_name{#(#inner_fields)*} => panic!("Convert on this item is ignored"), + } + } else { + quote_spanned! { span => + #name::#enum_name{#(#inner_fields)*} => Self::#enum_name{#(#codes)*}, + } + }); + } + // for enum item like + // xxxxxx + if let Fields::Unit = &field.fields { + let span = field.span(); + fields.push(if ignore_convert { + quote_spanned! { span => + #name::#enum_name => panic!("Convert on this item is ignored"), + } + } else { + quote_spanned! { span => + #name::#enum_name => Self::#enum_name, + } + }); + } + } + return quote_spanned! { span => + impl From<#name> for #path::#name { + #[allow(unused_variables)] + fn from(value: #name) -> Self { + match value{ + #(#fields)* + } + } + } + }; + } + panic!("Unrecognised Enum Type{}", st.to_token_stream()) +} + +fn expand_df_convert(st: &DeriveInput) -> proc_macro2::TokenStream { + match st.data { + syn::Data::Struct(_) => convert_struct(st), + syn::Data::Enum(_) => convert_enum(st), + syn::Data::Union(_) => panic!("Not support generate convert method for Union Type"), + } +} + +/// Derive macro to implement `From` Trait. Convert the current sqlparser struct to the struct used by datafusion sqlparser. +/// There are two helper attributes that can be marked on the derive struct/enum, affecting the generated Convert function +/// 1. `#[df_path(....)]`: Most structures are defined in `df_sqlparser::ast`, if the path of some structures is not in this path, +/// user need to specify `df_path` to tell the compiler the location of this struct/enum +/// 2. `#[ignore_item]`: Marked on the field of the struct/enum, indicating that the Convert method of the field of the struct/enum is not generated· +#[proc_macro_derive(DFConvert, attributes(df_path, ignore_item))] +pub fn derive_df_convert(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + expand_df_convert(&parse_macro_input!(input as DeriveInput)).into() +} diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 000000000..870bbe4e5 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +stable \ No newline at end of file diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs index 6b082a1fb..01b56e56c 100644 --- a/src/ast/data_type.rs +++ b/src/ast/data_type.rs @@ -24,8 +24,11 @@ use crate::ast::{display_comma_separated, ObjectName, StructField}; use super::value::escape_single_quote_string; +use crate::ast::Convert; +use crate::ast::DFConvert; + /// SQL data types -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DataType { @@ -444,7 +447,7 @@ fn format_datetime_precision_and_tz( /// /// This is more related to a display information than real differences between each variant. To /// guarantee compatibility with the input query we must maintain its exact information. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TimezoneInfo { @@ -492,7 +495,7 @@ impl fmt::Display for TimezoneInfo { /// following the 2016 [standard]. /// /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ExactNumberInfo { @@ -523,7 +526,7 @@ impl fmt::Display for ExactNumberInfo { /// Information about [character length][1], including length and possibly unit. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-length -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CharacterLength { @@ -557,7 +560,7 @@ impl fmt::Display for CharacterLength { /// Possible units for characters, initially based on 2016 ANSI [standard][1]. /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#char-length-units -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CharLengthUnits { @@ -584,7 +587,7 @@ impl fmt::Display for CharLengthUnits { /// the syntax used to declare the array. /// /// For example: Bigquery/Hive use `ARRAY` whereas snowflake uses ARRAY. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ArrayElemTypeDef { diff --git a/src/ast/dcl.rs b/src/ast/dcl.rs index f90de34d4..e52a1eb1f 100644 --- a/src/ast/dcl.rs +++ b/src/ast/dcl.rs @@ -13,9 +13,11 @@ //! AST types specific to GRANT/REVOKE/ROLE variants of [`Statement`](crate::ast::Statement) //! (commonly referred to as Data Control Language, or DCL) +use crate::ast::Convert; #[cfg(not(feature = "std"))] use alloc::vec::Vec; use core::fmt; +use sqlparser_derive::DFConvert; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -29,7 +31,7 @@ use crate::ast::{display_separated, ObjectName}; /// An option in `ROLE` statement. /// /// -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum RoleOption { @@ -94,7 +96,7 @@ impl fmt::Display for RoleOption { /// SET config value option: /// * SET `configuration_parameter` { TO | = } { `value` | DEFAULT } /// * SET `configuration_parameter` FROM CURRENT -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SetConfigValue { @@ -106,7 +108,7 @@ pub enum SetConfigValue { /// RESET config option: /// * RESET `configuration_parameter` /// * RESET ALL -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ResetConfig { @@ -115,7 +117,7 @@ pub enum ResetConfig { } /// An `ALTER ROLE` (`Statement::AlterRole`) operation -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum AlterRoleOperation { diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 9e3137d94..7995c60e2 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -24,6 +24,8 @@ use serde::{Deserialize, Serialize}; use sqlparser_derive::{Visit, VisitMut}; use crate::ast::value::escape_single_quote_string; +use crate::ast::Convert; +use crate::ast::DFConvert; use crate::ast::{ display_comma_separated, display_separated, DataType, Expr, Ident, ObjectName, SequenceOptions, SqlOption, @@ -31,7 +33,7 @@ use crate::ast::{ use crate::tokenizer::Token; /// An `ALTER TABLE` (`Statement::AlterTable`) operation -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum AlterTableOperation { @@ -147,7 +149,7 @@ pub enum AlterTableOperation { SetTblProperties { table_properties: Vec }, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum AlterIndexOperation { @@ -307,7 +309,7 @@ impl fmt::Display for AlterIndexOperation { } /// An `ALTER COLUMN` (`Statement::AlterTable`) operation -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum AlterColumnOperation { @@ -380,7 +382,7 @@ impl fmt::Display for AlterColumnOperation { /// A table-level constraint, specified in a `CREATE TABLE` or an /// `ALTER TABLE ADD ` statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TableConstraint { @@ -560,7 +562,7 @@ impl fmt::Display for TableConstraint { /// statements of `MySQL` [(1)]. /// /// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum KeyOrIndexDisplay { @@ -596,7 +598,7 @@ impl fmt::Display for KeyOrIndexDisplay { /// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html /// [2]: https://dev.mysql.com/doc/refman/8.0/en/create-index.html /// [3]: https://www.postgresql.org/docs/14/sql-createindex.html -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum IndexType { @@ -613,7 +615,7 @@ impl fmt::Display for IndexType { } } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ProcedureParam { @@ -628,7 +630,7 @@ impl fmt::Display for ProcedureParam { } /// SQL column definition -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ColumnDef { @@ -669,7 +671,7 @@ impl fmt::Display for ColumnDef { /// name /// age OPTIONS(description = "age column", tag = "prod") /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ViewColumnDef { @@ -707,7 +709,7 @@ impl fmt::Display for ViewColumnDef { /// For maximum flexibility, we don't distinguish between constraint and /// non-constraint options, lumping them all together under the umbrella of /// "column options," and we allow any column option to be named. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ColumnOptionDef { @@ -723,7 +725,7 @@ impl fmt::Display for ColumnOptionDef { /// `ColumnOption`s are modifiers that follow a column definition in a `CREATE /// TABLE` statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ColumnOption { @@ -877,7 +879,7 @@ impl fmt::Display for ColumnOption { /// `GeneratedAs`s are modifiers that follow a column option in a `generated`. /// 'ExpStored' is used for a column generated from an expression and stored. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum GeneratedAs { @@ -888,7 +890,7 @@ pub enum GeneratedAs { /// `GeneratedExpressionMode`s are modifiers that follow an expression in a `generated`. /// No modifier is typically the same as Virtual. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum GeneratedExpressionMode { @@ -912,7 +914,7 @@ fn display_constraint_name(name: &'_ Option) -> impl fmt::Display + '_ { /// ` = [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]` /// /// Used in UNIQUE and foreign key constraints. The individual settings may occur in any order. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ConstraintCharacteristics { @@ -924,7 +926,7 @@ pub struct ConstraintCharacteristics { pub enforced: Option, } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DeferrableInitial { @@ -991,7 +993,7 @@ impl fmt::Display for ConstraintCharacteristics { /// { RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT }` /// /// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ReferentialAction { @@ -1015,7 +1017,7 @@ impl fmt::Display for ReferentialAction { } /// SQL user defined type definition -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum UserDefinedTypeRepresentation { @@ -1035,7 +1037,7 @@ impl fmt::Display for UserDefinedTypeRepresentation { } /// SQL user defined type attribute definition -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct UserDefinedTypeCompositeAttributeDef { @@ -1055,7 +1057,7 @@ impl fmt::Display for UserDefinedTypeCompositeAttributeDef { } /// PARTITION statement used in ALTER TABLE et al. such as in Hive SQL -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Partition { diff --git a/src/ast/helpers/stmt_data_loading.rs b/src/ast/helpers/stmt_data_loading.rs index a259e664b..bb7010018 100644 --- a/src/ast/helpers/stmt_data_loading.rs +++ b/src/ast/helpers/stmt_data_loading.rs @@ -28,7 +28,11 @@ use crate::ast::Ident; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +use crate::ast::Convert; +use sqlparser_derive::DFConvert; + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::ast::helpers::stmt_data_loading)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct StageParamsObject { @@ -39,14 +43,16 @@ pub struct StageParamsObject { pub credentials: DataLoadingOptions, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::ast::helpers::stmt_data_loading)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct DataLoadingOptions { pub options: Vec, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::ast::helpers::stmt_data_loading)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DataLoadingOptionType { @@ -55,7 +61,8 @@ pub enum DataLoadingOptionType { ENUM, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::ast::helpers::stmt_data_loading)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct DataLoadingOption { @@ -64,7 +71,8 @@ pub struct DataLoadingOption { pub value: String, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::ast::helpers::stmt_data_loading)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct StageLoadSelectItem { diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d8688c1ab..cecc66d55 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -23,6 +23,8 @@ use core::fmt::{self, Display}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use sqlparser_derive::DFConvert; + #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; @@ -68,6 +70,46 @@ mod value; #[cfg(feature = "visitor")] mod visitor; +pub trait Convert +where + Self: Into, +{ + #[inline(always)] + fn convert(value: Self) -> T { + Self::into(value) + } + #[inline(always)] + #[allow(clippy::boxed_local)] + fn convert_box(value: Box) -> Box { + Box::new(Self::convert(*value)) + } + #[inline(always)] + fn convert_vec(value: Vec) -> Vec { + value.into_iter().map(Self::convert).collect() + } + #[inline(always)] + fn convert_vec_box(value: Vec>) -> Vec> { + value.into_iter().map(Self::convert_box).collect() + } + #[inline(always)] + fn convert_matrix(value: Vec>) -> Vec> { + value.into_iter().map(Self::convert_vec).collect() + } + #[inline(always)] + fn convert_option(value: Option) -> Option { + value.map(Self::convert) + } + #[inline(always)] + fn convert_option_box(value: Option>) -> Option> { + value.map(Self::convert_box) + } + #[inline(always)] + fn convert_option_vec(value: Option>) -> Option> { + value.map(Self::convert_vec) + } +} +impl Convert for V where V: Into {} + struct DisplaySeparated<'a, T> where T: fmt::Display, @@ -106,7 +148,7 @@ where } /// An identifier, decomposed into its value or character data and the quote style. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Ident { @@ -167,7 +209,7 @@ impl fmt::Display for Ident { } /// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ObjectName(pub Vec); @@ -180,7 +222,7 @@ impl fmt::Display for ObjectName { /// Represents an Array Expression, either /// `ARRAY[..]`, or `[..]` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Array { @@ -210,7 +252,7 @@ impl fmt::Display for Array { /// The parser does not validate the ``, nor does it ensure /// that the `` units >= the units in ``, /// so the user will have to reject intervals like `HOUR TO YEAR`. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Interval { @@ -267,7 +309,7 @@ impl fmt::Display for Interval { } /// JsonOperator -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum JsonOperator { @@ -329,7 +371,7 @@ impl fmt::Display for JsonOperator { /// A field definition within a struct. /// /// [bigquery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types#struct_type -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct StructField { @@ -349,7 +391,7 @@ impl fmt::Display for StructField { /// Options for `CAST` / `TRY_CAST` /// BigQuery: -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CastFormat { @@ -362,7 +404,7 @@ pub enum CastFormat { /// The parser does not distinguish between expressions of different types /// (e.g. boolean vs string), so the caller must handle expressions of /// inappropriate type, like `WHERE 1` or `SELECT 1=1`, as necessary. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( feature = "visitor", @@ -1196,7 +1238,7 @@ impl fmt::Display for Expr { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum WindowType { @@ -1214,7 +1256,7 @@ impl Display for WindowType { } /// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`) -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct WindowSpec { @@ -1263,7 +1305,7 @@ impl fmt::Display for WindowSpec { /// /// Note: The parser does not validate the specified bounds; the caller should /// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct WindowFrame { @@ -1289,7 +1331,7 @@ impl Default for WindowFrame { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum WindowFrameUnits { @@ -1311,7 +1353,7 @@ impl fmt::Display for WindowFrameUnits { /// Specifies Ignore / Respect NULL within window functions. /// For example /// `FIRST_VALUE(column2) IGNORE NULLS OVER (PARTITION BY column1)` -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum NullTreatment { @@ -1329,7 +1371,7 @@ impl fmt::Display for NullTreatment { } /// Specifies [WindowFrame]'s `start_bound` and `end_bound` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum WindowFrameBound { @@ -1353,7 +1395,7 @@ impl fmt::Display for WindowFrameBound { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum AddDropSync { @@ -1372,7 +1414,7 @@ impl fmt::Display for AddDropSync { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ShowCreateObject { @@ -1397,7 +1439,7 @@ impl fmt::Display for ShowCreateObject { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CommentObject { @@ -1414,7 +1456,7 @@ impl fmt::Display for CommentObject { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Password { @@ -1429,7 +1471,7 @@ pub enum Password { /// DECLARE variable_name := 42 /// DECLARE variable_name DEFAULT 42 /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DeclareAssignment { @@ -1476,7 +1518,7 @@ impl fmt::Display for DeclareAssignment { } /// Represents the type of a `DECLARE` statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DeclareType { @@ -1533,7 +1575,7 @@ impl fmt::Display for DeclareType { /// [Postgres]: https://www.postgresql.org/docs/current/sql-declare.html /// [Snowflake]: https://docs.snowflake.com/en/sql-reference/snowflake-scripting/declare /// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#declare -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Declare { @@ -1628,7 +1670,7 @@ impl fmt::Display for Declare { } /// Sql options of a `CREATE TABLE` statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CreateTableOptions { @@ -1665,7 +1707,7 @@ impl fmt::Display for CreateTableOptions { /// ```sql /// [FROM] table /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FromTable { @@ -1678,7 +1720,7 @@ pub enum FromTable { /// A top-level statement (SELECT, INSERT, CREATE, etc.) #[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr( feature = "visitor", @@ -4116,7 +4158,7 @@ impl fmt::Display for Statement { /// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] /// [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ] /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SequenceOptions { @@ -4171,7 +4213,7 @@ impl fmt::Display for SequenceOptions { /// Can use to describe options in create sequence or table column type identity /// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ] -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum MinMaxValue { @@ -4183,7 +4225,7 @@ pub enum MinMaxValue { Some(Expr), } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[non_exhaustive] @@ -4194,21 +4236,21 @@ pub enum OnInsert { OnConflict(OnConflict), } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct OnConflict { pub conflict_target: Option, pub action: OnConflictAction, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ConflictTarget { Columns(Vec), OnConstraint(ObjectName), } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum OnConflictAction { @@ -4216,7 +4258,7 @@ pub enum OnConflictAction { DoUpdate(DoUpdate), } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct DoUpdate { @@ -4278,7 +4320,7 @@ impl fmt::Display for OnConflictAction { } /// Privileges granted in a GRANT statement or revoked in a REVOKE statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Privileges { @@ -4315,7 +4357,7 @@ impl fmt::Display for Privileges { } /// Specific direction for FETCH statement -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FetchDirection { @@ -4379,7 +4421,7 @@ impl fmt::Display for FetchDirection { } /// A privilege on a database object (table, sequence, etc.). -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Action { @@ -4429,7 +4471,7 @@ impl fmt::Display for Action { } /// Objects on which privileges are granted in a GRANT statement. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum GrantObjects { @@ -4476,7 +4518,7 @@ impl fmt::Display for GrantObjects { } /// SQL assignment `foo = expr` as used in SQLUpdate -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Assignment { @@ -4490,7 +4532,7 @@ impl fmt::Display for Assignment { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FunctionArgExpr { @@ -4521,7 +4563,7 @@ impl fmt::Display for FunctionArgExpr { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] /// Operator used to separate function arguments @@ -4541,7 +4583,7 @@ impl fmt::Display for FunctionArgOperator { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FunctionArg { @@ -4566,7 +4608,7 @@ impl fmt::Display for FunctionArg { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CloseCursor { @@ -4584,7 +4626,7 @@ impl fmt::Display for CloseCursor { } /// A function call -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Function { @@ -4604,7 +4646,7 @@ pub struct Function { pub order_by: Vec, } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum AnalyzeFormat { @@ -4660,7 +4702,7 @@ impl fmt::Display for Function { } /// External table's available file format -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FileFormat { @@ -4690,7 +4732,7 @@ impl fmt::Display for FileFormat { /// A `LISTAGG` invocation `LISTAGG( [ DISTINCT ] [, ] [ON OVERFLOW ] ) ) /// [ WITHIN GROUP (ORDER BY [, ...] ) ]` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ListAgg { @@ -4728,7 +4770,7 @@ impl fmt::Display for ListAgg { } /// The `ON OVERFLOW` clause of a LISTAGG invocation -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ListAggOnOverflow { @@ -4766,7 +4808,7 @@ impl fmt::Display for ListAggOnOverflow { /// An `ARRAY_AGG` invocation `ARRAY_AGG( [ DISTINCT ] [ORDER BY ] [LIMIT ] )` /// Or `ARRAY_AGG( [ DISTINCT ] ) [ WITHIN GROUP ( ORDER BY ) ]` /// ORDER BY position is defined differently for BigQuery, Postgres and Snowflake. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ArrayAgg { @@ -4807,7 +4849,7 @@ impl fmt::Display for ArrayAgg { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ObjectType { @@ -4834,7 +4876,7 @@ impl fmt::Display for ObjectType { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum KillType { @@ -4855,7 +4897,7 @@ impl fmt::Display for KillType { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum HiveDistributionStyle { @@ -4875,7 +4917,7 @@ pub enum HiveDistributionStyle { NONE, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum HiveRowFormat { @@ -4883,7 +4925,7 @@ pub enum HiveRowFormat { DELIMITED { delimiters: Vec }, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct HiveRowDelimiter { @@ -4898,7 +4940,7 @@ impl fmt::Display for HiveRowDelimiter { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum HiveDelimiter { @@ -4924,7 +4966,7 @@ impl fmt::Display for HiveDelimiter { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum HiveDescribeFormat { @@ -4942,7 +4984,7 @@ impl fmt::Display for HiveDescribeFormat { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DescribeAlias { @@ -4962,7 +5004,7 @@ impl fmt::Display for DescribeAlias { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[allow(clippy::large_enum_variant)] @@ -4976,7 +5018,7 @@ pub enum HiveIOFormat { }, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct HiveFormat { @@ -4986,7 +5028,7 @@ pub struct HiveFormat { pub location: Option, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct SqlOption { @@ -5000,7 +5042,7 @@ impl fmt::Display for SqlOption { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TransactionMode { @@ -5018,7 +5060,7 @@ impl fmt::Display for TransactionMode { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TransactionAccessMode { @@ -5036,7 +5078,7 @@ impl fmt::Display for TransactionAccessMode { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TransactionIsolationLevel { @@ -5061,7 +5103,7 @@ impl fmt::Display for TransactionIsolationLevel { /// SQLite specific syntax /// /// -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TransactionModifier { @@ -5081,7 +5123,7 @@ impl fmt::Display for TransactionModifier { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ShowStatementFilter { @@ -5105,7 +5147,7 @@ impl fmt::Display for ShowStatementFilter { /// /// See [Sqlite documentation](https://sqlite.org/lang_conflict.html) /// for more details. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SqliteOnConflict { @@ -5134,7 +5176,7 @@ impl fmt::Display for SqliteOnConflict { /// See [Mysql documentation](https://dev.mysql.com/doc/refman/8.0/en/replace.html) /// See [Mysql documentation](https://dev.mysql.com/doc/refman/8.0/en/insert.html) /// for more details. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum MysqlInsertPriority { @@ -5154,7 +5196,7 @@ impl fmt::Display for crate::ast::MysqlInsertPriority { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CopySource { @@ -5168,7 +5210,7 @@ pub enum CopySource { Query(Box), } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CopyTarget { @@ -5200,7 +5242,7 @@ impl fmt::Display for CopyTarget { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum OnCommit { @@ -5212,7 +5254,7 @@ pub enum OnCommit { /// An option in `COPY` statement. /// /// -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CopyOption { @@ -5266,7 +5308,7 @@ impl fmt::Display for CopyOption { /// An option in `COPY` statement before PostgreSQL version 9.0. /// /// -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CopyLegacyOption { @@ -5295,7 +5337,7 @@ impl fmt::Display for CopyLegacyOption { /// A `CSV` option in `COPY` statement before PostgreSQL version 9.0. /// /// -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CopyLegacyCsvOption { @@ -5333,7 +5375,7 @@ impl fmt::Display for CopyLegacyCsvOption { /// ``` /// /// See [Snowflake documentation](https://docs.snowflake.com/en/sql-reference/sql/merge) -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum MergeClause { @@ -5395,7 +5437,7 @@ impl fmt::Display for MergeClause { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DiscardObject { @@ -5416,7 +5458,7 @@ impl fmt::Display for DiscardObject { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FlushType { @@ -5455,7 +5497,7 @@ impl fmt::Display for FlushType { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FlushLocation { @@ -5473,7 +5515,7 @@ impl fmt::Display for FlushLocation { } /// Optional context modifier for statements that can be or `LOCAL`, or `SESSION`. -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ContextModifier { @@ -5502,7 +5544,7 @@ impl fmt::Display for ContextModifier { } /// Function describe in DROP FUNCTION. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum DropFunctionOption { Restrict, @@ -5519,7 +5561,7 @@ impl fmt::Display for DropFunctionOption { } /// Function describe in DROP FUNCTION. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct DropFunctionDesc { @@ -5538,7 +5580,7 @@ impl fmt::Display for DropFunctionDesc { } /// Function argument in CREATE OR DROP FUNCTION. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct OperateFunctionArg { @@ -5587,7 +5629,7 @@ impl fmt::Display for OperateFunctionArg { } /// The mode of an argument in CREATE FUNCTION. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ArgMode { @@ -5607,7 +5649,7 @@ impl fmt::Display for ArgMode { } /// These attributes inform the query optimizer about the behavior of the function. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FunctionBehavior { @@ -5626,7 +5668,7 @@ impl fmt::Display for FunctionBehavior { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum FunctionDefinition { @@ -5648,7 +5690,7 @@ impl fmt::Display for FunctionDefinition { /// /// See [Postgresdocs](https://www.postgresql.org/docs/15/sql-createfunction.html) /// for more details -#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct CreateFunctionBody { @@ -5687,7 +5729,7 @@ impl fmt::Display for CreateFunctionBody { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CreateFunctionUsing { @@ -5711,7 +5753,7 @@ impl fmt::Display for CreateFunctionUsing { /// /// See [Create Macro - DuckDB](https://duckdb.org/docs/sql/statements/create_macro) /// for more details -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct MacroArg { @@ -5739,7 +5781,7 @@ impl fmt::Display for MacroArg { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum MacroDefinition { @@ -5760,7 +5802,7 @@ impl fmt::Display for MacroDefinition { /// Schema possible naming variants ([1]). /// /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#schema-definition -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SchemaName { @@ -5791,7 +5833,7 @@ impl fmt::Display for SchemaName { /// Fulltext search modifiers ([1]). /// /// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html#function_match -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SearchModifier { @@ -5826,7 +5868,7 @@ impl fmt::Display for SearchModifier { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct LockTable { @@ -5852,7 +5894,7 @@ impl fmt::Display for LockTable { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum LockTableType { @@ -5881,7 +5923,7 @@ impl fmt::Display for LockTableType { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct HiveSetLocation { diff --git a/src/ast/operator.rs b/src/ast/operator.rs index 8539c461b..579a7bfd0 100644 --- a/src/ast/operator.rs +++ b/src/ast/operator.rs @@ -23,8 +23,11 @@ use sqlparser_derive::{Visit, VisitMut}; use super::display_separated; +use crate::ast::Convert; +use crate::ast::DFConvert; + /// Unary operators -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum UnaryOperator { @@ -65,7 +68,7 @@ impl fmt::Display for UnaryOperator { } /// Binary operators -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum BinaryOperator { diff --git a/src/ast/query.rs b/src/ast/query.rs index bf33cdee6..66d8c459e 100644 --- a/src/ast/query.rs +++ b/src/ast/query.rs @@ -23,7 +23,7 @@ use crate::ast::*; /// The most complete variant of a `SELECT` query expression, optionally /// including `WITH`, `UNION` / other set operations, and `ORDER BY`. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "visitor", visit(with = "visit_query"))] @@ -86,7 +86,7 @@ impl fmt::Display for Query { /// A node in a tree, representing a "query body" expression, roughly: /// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]` #[allow(clippy::large_enum_variant)] -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SetExpr { @@ -139,7 +139,7 @@ impl fmt::Display for SetExpr { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SetOperator { @@ -161,7 +161,7 @@ impl fmt::Display for SetOperator { /// A quantifier for [SetOperator]. // TODO: Restrict parsing specific SetQuantifier in some specific dialects. // For example, BigQuery does not support `DISTINCT` for `EXCEPT` and `INTERSECT` -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SetQuantifier { @@ -186,7 +186,7 @@ impl fmt::Display for SetQuantifier { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// A [`TABLE` command]( https://www.postgresql.org/docs/current/sql-select.html#SQL-TABLE) #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] @@ -214,7 +214,7 @@ impl fmt::Display for Table { /// A restricted variant of `SELECT` (without CTEs/`ORDER BY`), which may /// appear either as the only body item of a `Query`, or as an operand /// to a set operation like `UNION`. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Select { @@ -319,7 +319,7 @@ impl fmt::Display for Select { } /// A hive LATERAL VIEW with potential column aliases -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct LateralView { @@ -353,7 +353,7 @@ impl fmt::Display for LateralView { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct NamedWindowDefinition(pub Ident, pub WindowSpec); @@ -364,7 +364,7 @@ impl fmt::Display for NamedWindowDefinition { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct With { @@ -383,7 +383,7 @@ impl fmt::Display for With { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum CteAsMaterialized { @@ -411,7 +411,7 @@ impl fmt::Display for CteAsMaterialized { /// The names in the column list before `AS`, when specified, replace the names /// of the columns returned by the query. The parser does not validate that the /// number of columns in the query matches the number of columns in the query. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Cte { @@ -435,7 +435,7 @@ impl fmt::Display for Cte { } /// One item of the comma-separated list following `SELECT` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum SelectItem { @@ -455,7 +455,7 @@ pub enum SelectItem { /// ```plaintext /// AS /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct IdentWithAlias { @@ -470,7 +470,7 @@ impl fmt::Display for IdentWithAlias { } /// Additional options for wildcards, e.g. Snowflake `EXCLUDE`/`RENAME` and Bigquery `EXCEPT`. -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct WildcardAdditionalOptions { @@ -512,7 +512,7 @@ impl fmt::Display for WildcardAdditionalOptions { /// /// | (, , ...) /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ExcludeSelectItem { @@ -553,7 +553,7 @@ impl fmt::Display for ExcludeSelectItem { /// AS /// | ( AS , AS , ...) /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum RenameSelectItem { @@ -593,7 +593,7 @@ impl fmt::Display for RenameSelectItem { /// ```plaintext /// EXCEPT ( [, ...]) /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ExceptSelectItem { @@ -627,7 +627,7 @@ impl fmt::Display for ExceptSelectItem { /// REPLACE ( [AS] ) /// REPLACE ( [AS] , [AS] , ...) /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ReplaceSelectItem { @@ -646,7 +646,7 @@ impl fmt::Display for ReplaceSelectItem { /// ```plaintext /// [AS] /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct ReplaceSelectElement { @@ -684,7 +684,7 @@ impl fmt::Display for SelectItem { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct TableWithJoins { @@ -703,7 +703,7 @@ impl fmt::Display for TableWithJoins { } /// A table name or a parenthesized subquery with an optional alias -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "visitor", visit(with = "visit_table_factor"))] @@ -980,7 +980,7 @@ impl fmt::Display for TableFactor { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct TableAlias { @@ -998,7 +998,7 @@ impl fmt::Display for TableAlias { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TableVersion { @@ -1014,7 +1014,7 @@ impl Display for TableVersion { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Join { @@ -1109,7 +1109,7 @@ impl fmt::Display for Join { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum JoinOperator { @@ -1132,7 +1132,7 @@ pub enum JoinOperator { OuterApply, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum JoinConstraint { @@ -1143,7 +1143,7 @@ pub enum JoinConstraint { } /// An `ORDER BY` expression -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct OrderByExpr { @@ -1171,7 +1171,7 @@ impl fmt::Display for OrderByExpr { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Offset { @@ -1186,7 +1186,7 @@ impl fmt::Display for Offset { } /// Stores the keyword after `OFFSET ` -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum OffsetRows { @@ -1206,7 +1206,7 @@ impl fmt::Display for OffsetRows { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Fetch { @@ -1227,7 +1227,7 @@ impl fmt::Display for Fetch { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct LockClause { @@ -1249,7 +1249,7 @@ impl fmt::Display for LockClause { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum LockType { @@ -1267,7 +1267,7 @@ impl fmt::Display for LockType { } } -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum NonBlock { @@ -1285,7 +1285,7 @@ impl fmt::Display for NonBlock { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Distinct { @@ -1308,7 +1308,7 @@ impl fmt::Display for Distinct { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Top { @@ -1320,7 +1320,7 @@ pub struct Top { pub quantity: Option, } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TopQuantity { @@ -1347,7 +1347,7 @@ impl fmt::Display for Top { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Values { @@ -1371,7 +1371,7 @@ impl fmt::Display for Values { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct SelectInto { @@ -1391,7 +1391,7 @@ impl fmt::Display for SelectInto { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum GroupByExpr { @@ -1419,7 +1419,7 @@ impl fmt::Display for GroupByExpr { /// FOR XML or FOR JSON clause, specific to MSSQL /// (formats the output of a query as XML or JSON) -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ForClause { @@ -1489,7 +1489,7 @@ impl fmt::Display for ForClause { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ForXml { @@ -1522,7 +1522,7 @@ impl fmt::Display for ForXml { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ForJson { @@ -1549,7 +1549,7 @@ impl fmt::Display for ForJson { /// ) /// ) AS jt; /// ``` -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct JsonTableColumn { @@ -1589,7 +1589,7 @@ impl fmt::Display for JsonTableColumn { /// Stores the error handling clause of a `JSON_TABLE` table valued function: /// {NULL | DEFAULT json_string | ERROR} ON {ERROR | EMPTY } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum JsonTableColumnErrorHandling { @@ -1614,7 +1614,7 @@ impl fmt::Display for JsonTableColumnErrorHandling { /// `SELECT AS STRUCT` /// `SELECT AS VALUE` /// -#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum ValueTableMode { diff --git a/src/ast/value.rs b/src/ast/value.rs index a9c74d4a8..c3f257f25 100644 --- a/src/ast/value.rs +++ b/src/ast/value.rs @@ -14,7 +14,7 @@ use alloc::string::String; use core::fmt; -#[cfg(feature = "bigdecimal")] +#[cfg(feature = "bigdecimal-sql")] use bigdecimal::BigDecimal; #[cfg(feature = "serde")] @@ -23,15 +23,23 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; +use lazy_static::lazy_static; +use regex::Regex; + +use crate::parser::ParserError; + +use crate::ast::Convert; +use crate::ast::DFConvert; + /// Primitive SQL values such as number and string -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Value { /// Numeric literal - #[cfg(not(feature = "bigdecimal"))] + #[cfg(not(feature = "bigdecimal-sql"))] Number(String, bool), - #[cfg(feature = "bigdecimal")] + #[cfg(feature = "bigdecimal-sql")] // HINT: use `test_utils::number` to make an instance of // Value::Number This might help if you your tests pass locally // but fail on CI with the `--all-features` flag enabled @@ -88,7 +96,7 @@ impl fmt::Display for Value { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct DollarQuotedString { @@ -109,7 +117,7 @@ impl fmt::Display for DollarQuotedString { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum DateTimeField { @@ -293,7 +301,7 @@ pub fn escape_escaped_string(s: &str) -> EscapeEscapedStringLiteral<'_> { EscapeEscapedStringLiteral(s) } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DFConvert)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum TrimWhereField { @@ -312,3 +320,72 @@ impl fmt::Display for TrimWhereField { }) } } + +// Checks if Value is a valid Duration string, Regular Expression Reference: https://github.com/GreptimeTeam/promql-parser/blob/main/src/util/duration.rs +lazy_static! { + static ref DURATION_RE: Regex = Regex::new( + r"(?x) +^ +((?P[0-9]+)y)? +((?P[0-9]+)w)? +((?P[0-9]+)d)? +((?P[0-9]+)h)? +((?P[0-9]+)m)? +((?P[0-9]+)s)? +((?P[0-9]+)ms)? +$", + ) + .unwrap(); +} + +impl Value { + /// check this value is a valid duration string + pub fn verify_duration(&self) -> Result<(), ParserError> { + match self { + Value::SingleQuotedString(s) | Value::DoubleQuotedString(s) => { + validate_duration(s.as_str()).map_err(ParserError::ParserError) + } + _ => Err(ParserError::ParserError(format!( + "not a valid duration string: {self}" + ))), + } + } +} + +/// validate a string is Duration. +fn validate_duration(ds: &str) -> Result<(), String> { + if ds.is_empty() { + return Err("empty duration string".into()); + } + + if ds == "0" { + return Err("duration must be greater than 0".into()); + } + + if !DURATION_RE.is_match(ds) { + return Err(format!("not a valid duration string: {ds}")); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_duration_regex() { + // valid regex + let res = vec![ + "1y", "2w", "3d", "4h", "5m", "6s", "7ms", "1y2w3d", "4h30m", "3600ms", + ]; + for re in res { + assert!(validate_duration(re).is_ok()) + } + + // invalid regex + let res = vec!["1", "1y1m1d", "-1w", "1.5d", "d"]; + for re in res { + assert!(validate_duration(re).is_err()) + } + } +} diff --git a/src/ast/visitor.rs b/src/ast/visitor.rs index c4f9c494d..97b81fb06 100644 --- a/src/ast/visitor.rs +++ b/src/ast/visitor.rs @@ -110,7 +110,7 @@ macro_rules! visit_noop { visit_noop!(u8, u16, u32, u64, i8, i16, i32, i64, char, bool, String); -#[cfg(feature = "bigdecimal")] +#[cfg(feature = "bigdecimal-sql")] visit_noop!(bigdecimal::BigDecimal); /// A visitor that can be used to walk an AST tree. diff --git a/src/keywords.rs b/src/keywords.rs index c94a6227c..5dbace8a9 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -28,6 +28,8 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "visitor")] use sqlparser_derive::{Visit, VisitMut}; +use sqlparser_derive::DFConvert; + /// Defines a string constant for a single keyword: `kw_def!(SELECT);` /// expands to `pub const SELECT = "SELECT";` macro_rules! kw_def { @@ -43,15 +45,19 @@ macro_rules! kw_def { /// and defines an ALL_KEYWORDS array of the defined constants. macro_rules! define_keywords { ($( - $ident:ident $(= $string_keyword:expr)? + $ident:ident $(= $string_keyword:expr)? $( => $meta:meta)* ),*) => { - #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)] + #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] + #[df_path(df_sqlparser::keywords)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] #[allow(non_camel_case_types)] pub enum Keyword { NoKeyword, - $($ident),* + $( + $(#[$meta])* + $ident, + )* } pub const ALL_KEYWORDS_INDEX: &[Keyword] = &[ @@ -74,6 +80,7 @@ define_keywords!( ADD, ADMIN, AGAINST, + ALIGN => ignore_item, ALL, ALLOCATE, ALTER, @@ -286,6 +293,7 @@ define_keywords!( FILE, FILES, FILE_FORMAT, + FILL => ignore_item, FILTER, FIRST, FIRST_VALUE, @@ -797,6 +805,9 @@ pub const RESERVED_FOR_TABLE_ALIAS: &[Keyword] = &[ Keyword::FOR, // for MYSQL PARTITION SELECTION Keyword::PARTITION, + // for GreptimeDB Range select + Keyword::ALIGN, + Keyword::FILL, ]; /// Can't be used as a column alias, so that `SELECT alias` @@ -828,4 +839,7 @@ pub const RESERVED_FOR_COLUMN_ALIAS: &[Keyword] = &[ Keyword::FROM, Keyword::INTO, Keyword::END, + // for GreptimeDB Range select + Keyword::RANGE, + Keyword::FILL, ]; diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 6d7ac3604..3451c7e51 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -20,7 +20,10 @@ use alloc::{ vec, vec::Vec, }; +#[cfg(feature = "bigdecimal-sql")] +use bigdecimal::BigDecimal; use core::fmt; +use std::collections::BTreeSet; use log::debug; @@ -789,6 +792,7 @@ impl<'a> Parser<'a> { let mut expr = self.parse_prefix()?; debug!("prefix: {:?}", expr); loop { + expr = self.parse_range_expr(expr)?; let next_precedence = self.get_next_precedence()?; debug!("next precedence: {:?}", next_precedence); @@ -801,6 +805,75 @@ impl<'a> Parser<'a> { Ok(expr) } + /// Parse Range clause with format `RANGE [ Duration literal | (INTERVAL [interval expr]) ] FILL [ NULL | PREV .....]` + fn parse_range_expr(&mut self, expr: Expr) -> Result { + let index = self.index; + let range = if self.parse_keyword(Keyword::RANGE) { + // Make sure Range followed by a value or interval expr, or it will be confused with window function syntax + // e.g. `COUNT(*) OVER (ORDER BY a RANGE BETWEEN INTERVAL '1 DAY' PRECEDING AND INTERVAL '1 DAY' FOLLOWING)` + if self.consume_token(&Token::LParen) { + self.expect_keyword(Keyword::INTERVAL)?; + let interval = self.parse_interval()?; + self.expect_token(&Token::RParen)?; + interval + } else if let Ok(value) = self.parse_value() { + value.verify_duration()?; + Expr::Value(value) + } else { + self.index = index; + return Ok(expr); + } + } else if self.parse_keyword(Keyword::FILL) { + return Err(ParserError::ParserError( + "Detect FILL keyword in SELECT Expr, but no RANGE given or RANGE after FILL".into(), + )); + } else { + return Ok(expr); + }; + let fill = if self.parse_keyword(Keyword::FILL) { + Value::SingleQuotedString(self.next_token().to_string()) + } else { + Value::SingleQuotedString(String::new()) + }; + // Recursively rewrite function nested in expr to range function when RANGE keyword appear in Expr + // Treat Function Argument as scalar function, not execute rewrite + // follow the pattern of `range_fn(func, range, fill)` + // if `fill` is `None`, the last parameter will be a empty single quoted string for placeholder + // rate(metrics) RANGE '5m' -> range_fn(rate(metrics), '5m', '') + // rate() RANGE '5m' FILL MAX -> range_fn(rate(), '5m', 'MAX') + let mut rewrite_count = 0; + let expr = rewrite_calculation_expr(&expr, false, &mut |e: &Expr| { + if matches!(e, Expr::Function(..)) { + let args = vec![ + FunctionArg::Unnamed(FunctionArgExpr::Expr(e.clone())), + FunctionArg::Unnamed(FunctionArgExpr::Expr(range.clone())), + FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(fill.clone()))), + ]; + let range_func = Function { + name: ObjectName(vec![Ident::new("range_fn")]), + args, + over: None, + distinct: false, + special: false, + order_by: vec![], + filter: None, + null_treatment: None, + }; + rewrite_count += 1; + Ok(Some(Expr::Function(range_func))) + } else { + Ok(None) + } + })?; + if rewrite_count == 0 { + return Err(ParserError::ParserError(format!( + "Can't use the RANGE keyword in Expr {} without function", + expr + ))); + } + Ok(expr) + } + pub fn parse_interval_expr(&mut self) -> Result { let precedence = 0; let mut expr = self.parse_prefix()?; @@ -6018,9 +6091,9 @@ impl<'a> Parser<'a> { Ok(Expr::Value(Value::SingleQuotedString(value))) } Token::SingleQuotedString(s) => Ok(Expr::Value(Value::SingleQuotedString(s))), - #[cfg(not(feature = "bigdecimal"))] + #[cfg(not(feature = "bigdecimal-sql"))] Token::Number(s, _) => Ok(Expr::Value(Value::Number(s, false))), - #[cfg(feature = "bigdecimal")] + #[cfg(feature = "bigdecimal-sql")] Token::Number(s, _) => Ok(Expr::Value(Value::Number(s.parse().unwrap(), false))), _ => self.expected("literal string, number or function", next_token), } @@ -7308,7 +7381,7 @@ impl<'a> Parser<'a> { None }; - let group_by = if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) { + let mut group_by = if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) { if self.parse_keyword(Keyword::ALL) { GroupByExpr::All } else { @@ -7329,6 +7402,168 @@ impl<'a> Parser<'a> { } else { vec![] }; + // triple means (align duration, to, by) + let mut align: Option<(Expr, Expr, Vec)> = None; + let mut fill: Option = None; + for _ in 0..2 { + if self.parse_keyword(Keyword::ALIGN) { + if align.is_some() { + return Err(ParserError::ParserError( + "Duplicate ALIGN keyword detected in SELECT clause.".into(), + )); + } + // Must use parentheses in interval, otherwise it will cause syntax conflicts. + // `INTERVAL '1-1' YEAR TO MONTH` are conflict with + // `ALIGN INTERVAL '1' day TO '1970-01-01T00:00:00+08:00'` + let value = if self.consume_token(&Token::LParen) { + self.expect_keyword(Keyword::INTERVAL)?; + let interval = self.parse_interval()?; + self.expect_token(&Token::RParen)?; + interval + } else { + let value = self.parse_value()?; + value.verify_duration()?; + Expr::Value(value) + }; + let to = if self.parse_keyword(Keyword::TO) { + let value = self.next_token().to_string(); + Expr::Value(Value::SingleQuotedString( + value.trim_matches(|x| x == '\'' || x == '"').to_string(), + )) + } else { + Expr::Value(Value::SingleQuotedString(String::new())) + }; + let by = if self.parse_keyword(Keyword::BY) { + self.expect_token(&Token::LParen)?; + if self.consume_token(&Token::RParen) { + // for case like `by ()` + // The user explicitly specifies that the aggregation key is empty. In this case, there is no aggregation key. + // All data will be aggregated into a group, which is equivalent to using a random constant as the aggregation key. + // Therefore, in this case, the constant 1 is used directly as the aggregation key. + // `()` == `(1)` + #[cfg(not(feature = "bigdecimal-sql"))] + { + vec![Expr::Value(Value::Number("1".into(), false))] + } + #[cfg(feature = "bigdecimal-sql")] + { + vec![Expr::Value(Value::Number(BigDecimal::from(1), false))] + } + } else { + let by = self.parse_comma_separated(Parser::parse_expr)?; + self.expect_token(&Token::RParen)?; + by + } + } else { + vec![] + }; + align = Some((value, to, by)); + } + if self.parse_keyword(Keyword::FILL) { + if fill.is_some() { + return Err(ParserError::ParserError( + "Duplicate FILL keyword detected in SELECT clause.".into(), + )); + } + fill = Some(self.next_token().to_string()); + } + } + if align.is_none() && fill.is_some() { + return Err(ParserError::ParserError( + "ALIGN argument cannot be omitted in the range select query".into(), + )); + } + let projection = if let Some((align, to, by)) = align { + let fill = fill.unwrap_or_default(); + let by_num = FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value( + Value::SingleQuotedString(by.len().to_string()), + ))); + let mut fake_group_by = BTreeSet::new(); + let by = by + .into_iter() + .map(|x| { + collect_column_from_expr(&x, &mut fake_group_by, false); + FunctionArg::Unnamed(FunctionArgExpr::Expr(x)) + }) + .collect::>(); + // range_fn(func, range, fill, byc, [byv], align, to) + // byc are length of variadic arguments [byv] + let mut rewrite_count = 0; + let mut align_fill_rewrite = + |expr: Expr, columns: &mut BTreeSet| { + rewrite_calculation_expr(&expr, true, &mut |e: &Expr| match e { + Expr::Function(func) => { + if let Some(name) = func.name.0.first() { + if name.value.as_str() == "range_fn" { + let mut range_func = func.clone(); + // remove aggr func args columns from group by + if let Some(FunctionArg::Unnamed(FunctionArgExpr::Expr(expr))) = + range_func.args.first() + { + collect_column_from_expr(expr, columns, true); + } + // use global fill if fill not given in range select item + if let Some(FunctionArg::Unnamed(FunctionArgExpr::Expr( + Expr::Value(Value::SingleQuotedString(value)), + ))) = range_func.args.last_mut() + { + if value.is_empty() { + *value = fill.clone(); + } + } + range_func.args.push(by_num.clone()); + range_func.args.extend(by.clone()); + range_func.args.push(FunctionArg::Unnamed( + FunctionArgExpr::Expr(align.clone()), + )); + range_func.args.push(FunctionArg::Unnamed( + FunctionArgExpr::Expr(to.clone()), + )); + rewrite_count += 1; + return Ok(Some(Expr::Function(range_func))); + } + } + Ok(None) + } + _ => Ok(None), + }) + }; + let rewrite_projection = projection + .into_iter() + .map(|select_item| { + if let SelectItem::UnnamedExpr(expr) | SelectItem::ExprWithAlias { expr, .. } = + &select_item + { + // collect all columns from select items + collect_column_from_expr(expr, &mut fake_group_by, false); + } + match select_item { + SelectItem::UnnamedExpr(expr) => Ok(SelectItem::UnnamedExpr( + align_fill_rewrite(expr, &mut fake_group_by)?, + )), + SelectItem::ExprWithAlias { expr, alias } => { + Ok(SelectItem::ExprWithAlias { + expr: align_fill_rewrite(expr, &mut fake_group_by)?, + alias, + }) + } + _ => Err(ParserError::ParserError( + "Wildcard `*` is not allowed in range select query".into(), + )), + } + }) + .collect::, ParserError>>()?; + if rewrite_count == 0 { + return Err(ParserError::ParserError( + "Illegal Range select, no RANGE keyword found in any SelectItem".into(), + )); + } else { + group_by = GroupByExpr::Expressions(fake_group_by.into_iter().collect()); + } + rewrite_projection + } else { + projection + }; let sort_by = if self.parse_keywords(&[Keyword::SORT, Keyword::BY]) { self.parse_comma_separated(Parser::parse_expr)? @@ -8643,6 +8878,7 @@ impl<'a> Parser<'a> { } else { expr }; + self.parse_optional_alias(keywords::RESERVED_FOR_COLUMN_ALIAS) .map(|alias| match alias { Some(alias) => SelectItem::ExprWithAlias { expr, alias }, @@ -9490,6 +9726,167 @@ impl Word { } } +/// Recursively rewrite a nested calculation `Expr` +/// +/// The function's return type is `Result>>`, where: +/// +/// * `Ok(Some(replacement_expr))`: A replacement `Expr` is provided, use replacement `Expr`. +/// * `Ok(None)`: A replacement `Expr` is not provided, use old `Expr`. +/// * `Err(err)`: Any error returned. +fn rewrite_calculation_expr( + expr: &Expr, + rewrite_func_expr: bool, + replacement_fn: &mut F, +) -> Result +where + F: FnMut(&Expr) -> Result, ParserError>, +{ + match replacement_fn(expr)? { + Some(replacement) => Ok(replacement), + None => match expr { + Expr::BinaryOp { left, op, right } => Ok(Expr::BinaryOp { + left: Box::new(rewrite_calculation_expr( + left, + rewrite_func_expr, + replacement_fn, + )?), + op: op.clone(), + right: Box::new(rewrite_calculation_expr( + right, + rewrite_func_expr, + replacement_fn, + )?), + }), + Expr::Nested(expr) => Ok(Expr::Nested(Box::new(rewrite_calculation_expr( + expr, + rewrite_func_expr, + replacement_fn, + )?))), + Expr::Cast { + expr, + data_type, + format, + } => Ok(Expr::Cast { + expr: Box::new(rewrite_calculation_expr( + expr, + rewrite_func_expr, + replacement_fn, + )?), + data_type: data_type.clone(), + format: format.clone(), + }), + Expr::TryCast { + expr, + data_type, + format, + } => Ok(Expr::TryCast { + expr: Box::new(rewrite_calculation_expr( + expr, + rewrite_func_expr, + replacement_fn, + )?), + data_type: data_type.clone(), + format: format.clone(), + }), + Expr::SafeCast { + expr, + data_type, + format, + } => Ok(Expr::SafeCast { + expr: Box::new(rewrite_calculation_expr( + expr, + rewrite_func_expr, + replacement_fn, + )?), + data_type: data_type.clone(), + format: format.clone(), + }), + // Scalar function `ceil(val)` will be parse as `Expr::Ceil` instead of `Expr::Function` + Expr::Ceil { expr, field } => Ok(Expr::Ceil { + expr: Box::new(rewrite_calculation_expr( + expr, + rewrite_func_expr, + replacement_fn, + )?), + field: *field, + }), + // Scalar function `floor(val)` will be parse as `Expr::Floor` instead of `Expr::Function` + Expr::Floor { expr, field } => Ok(Expr::Floor { + expr: Box::new(rewrite_calculation_expr( + expr, + rewrite_func_expr, + replacement_fn, + )?), + field: *field, + }), + Expr::Function(func) if rewrite_func_expr => { + let mut func = func.clone(); + for fn_arg in &mut func.args { + if let FunctionArg::Named { + arg: FunctionArgExpr::Expr(expr), + .. + } + | FunctionArg::Unnamed(FunctionArgExpr::Expr(expr)) = fn_arg + { + *expr = rewrite_calculation_expr(expr, rewrite_func_expr, replacement_fn)?; + } + } + Ok(Expr::Function(func)) + } + expr => Ok(expr.clone()), + }, + } +} + +// walk the whole expr to collect info +fn walk_expr(expr: &Expr, apply_fn: &mut F) -> Result<(), ParserError> +where + F: FnMut(&Expr) -> Result<(), ParserError>, +{ + match expr { + Expr::BinaryOp { left, right, .. } => { + walk_expr(left, apply_fn)?; + walk_expr(right, apply_fn)?; + } + Expr::Nested(expr) + | Expr::Cast { expr, .. } + | Expr::TryCast { expr, .. } + | Expr::SafeCast { expr, .. } + | Expr::Ceil { expr, .. } + | Expr::Floor { expr, .. } => { + walk_expr(expr, apply_fn)?; + } + Expr::Function(func) => { + for fn_arg in &func.args { + if let FunctionArg::Named { + arg: FunctionArgExpr::Expr(expr), + .. + } + | FunctionArg::Unnamed(FunctionArgExpr::Expr(expr)) = fn_arg + { + walk_expr(expr, apply_fn)?; + } + } + } + _ => (), + }; + apply_fn(expr)?; + Ok(()) +} + +fn collect_column_from_expr(expr: &Expr, columns: &mut BTreeSet, remove: bool) { + let _ = walk_expr(expr, &mut |e| { + if matches!(e, Expr::CompoundIdentifier(_) | Expr::Identifier(_)) { + if remove { + columns.remove(e); + } else { + columns.insert(e.clone()); + } + } + Ok(()) + }); +} + #[cfg(test)] mod tests { use crate::test_utils::{all_dialects, TestedDialects}; diff --git a/src/tokenizer.rs b/src/tokenizer.rs index a1a2eae2d..f2d0e4616 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -27,6 +27,7 @@ use alloc::{ use core::fmt; use core::iter::Peekable; use core::str::Chars; +use sqlparser_derive::DFConvert; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -41,8 +42,11 @@ use crate::dialect::{ use crate::dialect::{Dialect, MySqlDialect}; use crate::keywords::{Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX}; +use crate::ast::Convert; + /// SQL Token enumeration -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::tokenizer)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Token { @@ -303,7 +307,8 @@ impl Token { } /// A keyword (like SELECT) or an optionally quoted SQL identifier -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::tokenizer)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub struct Word { @@ -342,7 +347,8 @@ impl Word { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, DFConvert)] +#[df_path(df_sqlparser::tokenizer)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] pub enum Whitespace { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index f81456849..0cd8043c4 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1263,13 +1263,13 @@ fn parse_escaped_single_quote_string_predicate_with_no_escape() { fn parse_number() { let expr = verified_expr("1.0"); - #[cfg(feature = "bigdecimal")] + #[cfg(feature = "bigdecimal-sql")] assert_eq!( expr, Expr::Value(Value::Number(bigdecimal::BigDecimal::from(1), false)) ); - #[cfg(not(feature = "bigdecimal"))] + #[cfg(not(feature = "bigdecimal-sql"))] assert_eq!(expr, Expr::Value(Value::Number("1.0".into(), false))); } @@ -8556,3 +8556,239 @@ fn test_buffer_reuse() { p.parse_statements().unwrap(); let _ = p.into_tokens(); } + +fn assert_sql(s: &'static str, result: &'static str) { + let statements = Parser::parse_sql(&GenericDialect {}, s).unwrap(); + assert_eq!(statements.len(), 1); + assert_eq!(result, format!("{}", statements[0])); +} + +fn assert_sql_err(s: &'static str, result: &'static str) { + let error = Parser::parse_sql(&GenericDialect {}, s) + .unwrap_err() + .to_string(); + assert_eq!(result, error); +} + +#[test] +fn parse_range_select() { + // rewrite format `range_fn(func_name, argc, [argv], range, fill, byc, [byv], align, to)` + // regular without by + assert_sql("SELECT rate(metrics) RANGE '5m', sum(metrics) RANGE '10m' FILL MAX, sum(metrics) RANGE '10m' FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(rate(metrics), '5m', 'NULL', '0', '1h', ''), range_fn(sum(metrics), '10m', 'MAX', '0', '1h', ''), range_fn(sum(metrics), '10m', 'NULL', '0', '1h', '') FROM t"); + + // regular with by + assert_sql("SELECT rate(metrics) RANGE '5m', sum(metrics) RANGE '10m' FILL MAX, sum(metrics) RANGE '10m' FROM t ALIGN '1h' by ((a+1)/2, b) FILL NULL;", + "SELECT range_fn(rate(metrics), '5m', 'NULL', '2', (a + 1) / 2, b, '1h', ''), range_fn(sum(metrics), '10m', 'MAX', '2', (a + 1) / 2, b, '1h', ''), range_fn(sum(metrics), '10m', 'NULL', '2', (a + 1) / 2, b, '1h', '') FROM t GROUP BY a, b"); + + // explicit empty by + assert_sql("SELECT rate(metrics) RANGE '5m', sum(metrics) RANGE '10m' FILL MAX, sum(metrics) RANGE '10m' FROM t ALIGN '1h' by () FILL NULL;", + "SELECT range_fn(rate(metrics), '5m', 'NULL', '1', 1, '1h', ''), range_fn(sum(metrics), '10m', 'MAX', '1', 1, '1h', ''), range_fn(sum(metrics), '10m', 'NULL', '1', 1, '1h', '') FROM t"); + + // expression1 + assert_sql( + "SELECT avg(a/2 + 1) RANGE '5m' FILL NULL FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(avg(a / 2 + 1), '5m', 'NULL', '0', '1h', '') FROM t", + ); + + // expression2 + assert_sql( + "SELECT avg(a) RANGE '5m' FILL NULL + 1 FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(avg(a), '5m', 'NULL', '0', '1h', '') + 1 FROM t", + ); + + // expression3 + assert_sql( + "SELECT ((avg(a) + sum(b))/2) RANGE '5m' FILL NULL FROM t ALIGN '1h' FILL NULL;", + "SELECT ((range_fn(avg(a), '5m', 'NULL', '0', '1h', '') + range_fn(sum(b), '5m', 'NULL', '0', '1h', '')) / 2) FROM t", + ); + + // expression4 + assert_sql( + "SELECT covariance(a, b) RANGE '5m' FILL NULL FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(covariance(a, b), '5m', 'NULL', '0', '1h', '') FROM t", + ); + + // expression5 + assert_sql( + "SELECT covariance(cos(a), sin(b)) RANGE '5m' FILL NULL FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(covariance(cos(a), sin(b)), '5m', 'NULL', '0', '1h', '') FROM t", + ); + + // expression6 + assert_sql( + "SELECT ((covariance(a+1, b/2) + sum(b))/2) RANGE '5m' FILL NULL FROM t ALIGN '1h' FILL NULL;", + "SELECT ((range_fn(covariance(a + 1, b / 2), '5m', 'NULL', '0', '1h', '') + range_fn(sum(b), '5m', 'NULL', '0', '1h', '')) / 2) FROM t", + ); + + // FILL... ALIGN... + assert_sql( + "SELECT sum(metrics) RANGE '10m' FROM t FILL NULL ALIGN '1h';", + "SELECT range_fn(sum(metrics), '10m', 'NULL', '0', '1h', '') FROM t", + ); + + // FILL ... FILL ... + assert_sql_err( + "SELECT sum(metrics) RANGE '10m' FILL MAX FROM t FILL NULL FILL NULL;", + "sql parser error: Duplicate FILL keyword detected in SELECT clause.", + ); + + // ALIGN ... ALIGN ... + assert_sql_err( + "SELECT sum(metrics) RANGE '10m' FILL MAX FROM t ALIGN '1h' ALIGN '1h';", + "sql parser error: Duplicate ALIGN keyword detected in SELECT clause.", + ); + + // FILL without RANGE + assert_sql_err( + "SELECT sum(metrics) FILL MAX FROM t FILL NULL ALIGN '1h';", + "sql parser error: Detect FILL keyword in SELECT Expr, but no RANGE given or RANGE after FILL", + ); + + // RANGE after FILL + assert_sql_err( + "SELECT sum(metrics) FILL MAX RANGE '10m' FROM t FILL NULL ALIGN '1h';", + "sql parser error: Detect FILL keyword in SELECT Expr, but no RANGE given or RANGE after FILL", + ); + + // INVALID Duration String + assert_sql_err( + "SELECT sum(metrics) RANGE '10m' FILL MAX FROM t FILL NULL ALIGN '1ff';", + "sql parser error: not a valid duration string: 1ff", + ); + assert_sql_err( + "SELECT sum(metrics) RANGE '1regr' FILL MAX FROM t FILL NULL ALIGN '1h';", + "sql parser error: not a valid duration string: 1regr", + ); + + // omit RANGE + assert_sql_err( + "SELECT sum(metrics) FROM t ALIGN '1h' FILL NULL;", + "sql parser error: Illegal Range select, no RANGE keyword found in any SelectItem", + ); + + // omit ALIGN + assert_sql_err( + "SELECT sum(metrics) RANGE '10m' FILL MAX FROM t FILL NULL;", + "sql parser error: ALIGN argument cannot be omitted in the range select query", + ); + + assert_sql_err( + "SELECT sum(metrics) RANGE '10m', * FROM t FILL NULL ALIGN '1h';", + "sql parser error: Wildcard `*` is not allowed in range select query", + ); +} + +#[test] +fn parse_range_in_expr() { + // use range in expr + assert_sql( + "SELECT rate(a) RANGE '6m' + 1 FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(rate(a), '6m', 'NULL', '0', '1h', '') + 1 FROM t", + ); + + assert_sql( + "SELECT sin(rate(a) RANGE '6m' + 1) FROM t ALIGN '1h' FILL NULL;", + "SELECT sin(range_fn(rate(a), '6m', 'NULL', '0', '1h', '') + 1) FROM t", + ); + + assert_sql( + "SELECT sin(first_value(a ORDER BY b ASC NULLS LAST) RANGE '6m' + 1) FROM t ALIGN '1h' by (tag0, tag1) FILL NULL;", + "SELECT sin(range_fn(first_value(a ORDER BY b ASC NULLS LAST), '6m', 'NULL', '2', tag0, tag1, '1h', '') + 1) FROM t GROUP BY tag0, tag1", + ); + + assert_sql( + "SELECT sin(count(distinct a) RANGE '6m' + 1) FROM t ALIGN '1h' by (tag0, tag1) FILL NULL;", + "SELECT sin(range_fn(count(DISTINCT a), '6m', 'NULL', '2', tag0, tag1, '1h', '') + 1) FROM t GROUP BY tag0, tag1", + ); + + assert_sql( + "SELECT sin(rank() OVER (PARTITION BY a ORDER BY b DESC) RANGE '6m' + 1) FROM t ALIGN '1h' by (tag0, tag1) FILL NULL;", + "SELECT sin(range_fn(rank() OVER (PARTITION BY a ORDER BY b DESC), '6m', 'NULL', '2', tag0, tag1, '1h', '') + 1) FROM t GROUP BY tag0, tag1", + ); + + assert_sql( + "SELECT sin(cos(round(sin(avg(a + b) RANGE '5m' + 1)))) FROM test ALIGN '1h' by (tag_0,tag_1);", + "SELECT sin(cos(round(sin(range_fn(avg(a + b), '5m', '', '2', tag_0, tag_1, '1h', '') + 1)))) FROM test GROUP BY tag_0, tag_1", + ); + + assert_sql("SELECT rate(a) RANGE '6m' + rate(a) RANGE '5m' FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(rate(a), '6m', 'NULL', '0', '1h', '') + range_fn(rate(a), '5m', 'NULL', '0', '1h', '') FROM t"); + + assert_sql("SELECT (rate(a) RANGE '6m' + rate(a) RANGE '5m')/b + b * rate(a) RANGE '5m' FROM t ALIGN '1h' FILL NULL;", + "SELECT (range_fn(rate(a), '6m', 'NULL', '0', '1h', '') + range_fn(rate(a), '5m', 'NULL', '0', '1h', '')) / b + b * range_fn(rate(a), '5m', 'NULL', '0', '1h', '') FROM t GROUP BY b"); + + assert_sql("SELECT round(max(a+1) Range '5m' FILL NULL), sin((max(a) + 1) Range '5m' FILL NULL) from t ALIGN '1h' by (b) FILL NULL;", + "SELECT round(range_fn(max(a + 1), '5m', 'NULL', '1', b, '1h', '')), sin((range_fn(max(a), '5m', 'NULL', '1', b, '1h', '') + 1)) FROM t GROUP BY b"); + + assert_sql( + "SELECT floor(ceil((min(a * 2) + max(a *2)) RANGE '20s' + 1.0)) FROM t ALIGN '1h';", + "SELECT FLOOR(CEIL((range_fn(min(a * 2), '20s', '', '0', '1h', '') + range_fn(max(a * 2), '20s', '', '0', '1h', '')) + 1.0)) FROM t", + ); + + assert_sql( + "SELECT gcd(CAST(max(a + 1) Range '5m' FILL NULL AS INT64), CAST(b AS INT64)) + round(max(c+1) Range '6m' FILL NULL + 1) + max(d+3) Range '10m' FILL NULL * CAST(e AS FLOAT64) + 1 FROM test ALIGN '1h' by (f, g);", + "SELECT gcd(CAST(range_fn(max(a + 1), '5m', 'NULL', '2', f, g, '1h', '') AS INT64), CAST(b AS INT64)) + round(range_fn(max(c + 1), '6m', 'NULL', '2', f, g, '1h', '') + 1) + range_fn(max(d + 3), '10m', 'NULL', '2', f, g, '1h', '') * CAST(e AS FLOAT64) + 1 FROM test GROUP BY b, e, f, g", + ); + + // Legal syntax but illegal semantic, nested range semantics are problematic, leave semantic problem to greptimedb + assert_sql( + "SELECT rate(max(a) RANGE '6m') RANGE '6m' + 1 FROM t ALIGN '1h' FILL NULL;", + "SELECT range_fn(rate(range_fn(max(a), '6m', '')), '6m', 'NULL', '0', '1h', '') + 1 FROM t", + ); + + assert_sql_err( + "SELECT rate(a) RANGE '6m' RANGE '6m' + 1 FROM t ALIGN '1h' FILL NULL;", + "sql parser error: Expected end of statement, found: RANGE at Line: 1, Column 27", + ); + + assert_sql_err( + "SELECT rate(a) + 1 RANGE '5m' FROM t ALIGN '1h' FILL NULL;", + "sql parser error: Can't use the RANGE keyword in Expr 1 without function", + ); + + assert_sql_err( + "SELECT 1 RANGE '5m' FILL NULL FROM t ALIGN '1h' FILL NULL;", + "sql parser error: Can't use the RANGE keyword in Expr 1 without function", + ); +} + +#[test] +fn parse_range_interval() { + assert_sql( + "SELECT rate(a) RANGE (INTERVAL '1 year 2 hours 3 minutes') FROM t ALIGN (INTERVAL '1 year 2 hours 3 minutes') FILL NULL;", + "SELECT range_fn(rate(a), INTERVAL '1 year 2 hours 3 minutes', 'NULL', '0', INTERVAL '1 year 2 hours 3 minutes', '') FROM t", + ); + assert_sql( + "SELECT rate(a) RANGE (INTERVAL '1' YEAR) FROM t ALIGN (INTERVAL '1' YEAR) FILL NULL;", + "SELECT range_fn(rate(a), INTERVAL '1' YEAR, 'NULL', '0', INTERVAL '1' YEAR, '') FROM t", + ); + assert_sql( + "SELECT sin(count(distinct a) RANGE (INTERVAL '1 year 2 hours 3 minutes') + 1) FROM t ALIGN (INTERVAL '1 year 2 hours 3 minutes') FILL NULL;", + "SELECT sin(range_fn(count(DISTINCT a), INTERVAL '1 year 2 hours 3 minutes', 'NULL', '0', INTERVAL '1 year 2 hours 3 minutes', '') + 1) FROM t", + ); + assert_sql( + "SELECT rate(a) RANGE (INTERVAL '1' YEAR) FROM t ALIGN (INTERVAL '1' YEAR) TO '1970-01-01T00:00:00+08:00' BY (b, c) FILL NULL;", + "SELECT range_fn(rate(a), INTERVAL '1' YEAR, 'NULL', '2', b, c, INTERVAL '1' YEAR, '1970-01-01T00:00:00+08:00') FROM t GROUP BY b, c", + ); + assert_sql_err( + "SELECT rate(a) RANGE INTERVAL '1 year 2 hours 3 minutes' FROM t ALIGN '1h' FILL NULL;", + "sql parser error: Expected end of statement, found: RANGE at Line: 1, Column 16", + ); +} + +#[test] +fn parse_range_to() { + assert_sql( + "SELECT rate(a) RANGE '6m' FROM t ALIGN '1h' TO NOW FILL NULL;", + "SELECT range_fn(rate(a), '6m', 'NULL', '0', '1h', 'NOW') FROM t", + ); + assert_sql( + "SELECT rate(a) RANGE '6m' FROM t ALIGN '1h' TO CALENDAR FILL NULL;", + "SELECT range_fn(rate(a), '6m', 'NULL', '0', '1h', 'CALENDAR') FROM t", + ); + assert_sql( + "SELECT rate(a) RANGE '6m' FROM t ALIGN '1h' TO '2021-07-01 00:00:00' FILL NULL;", + "SELECT range_fn(rate(a), '6m', 'NULL', '0', '1h', '2021-07-01 00:00:00') FROM t", + ); +} diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 06982be49..b900f201e 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -1599,7 +1599,7 @@ fn parse_select_with_numeric_prefix_column_name() { // // left: `"SELECT 123e4, 123col_$@123abc FROM \"table\""`, // right: `"SELECT 1230000, 123col_$@123abc FROM \"table\""`', src/test_utils.rs:114:13 -#[cfg(not(feature = "bigdecimal"))] +#[cfg(not(feature = "bigdecimal-sql"))] #[test] fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() { let sql = "SELECT 123e4, 123col_$@123abc FROM \"table\"";