mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Add derive based AST visitor (#765)
* Add derive based AST visitor * Fix BigDecimal * Fix no visitor feature * Add test * Rename visit_table to visit_relation * Review feedback * Add pre and post visit Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
3e990466f8
commit
dec3c2b818
16 changed files with 771 additions and 11 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,6 +2,7 @@
|
|||
# will have compiled files and executables
|
||||
/target/
|
||||
/sqlparser_bench/target/
|
||||
/derive/target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
|
||||
|
|
|
@ -5,7 +5,7 @@ version = "0.28.0"
|
|||
authors = ["Andy Grove <andygrove73@gmail.com>"]
|
||||
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
|
||||
documentation = "https://docs.rs/sqlparser/"
|
||||
keywords = [ "ansi", "sql", "lexer", "parser" ]
|
||||
keywords = ["ansi", "sql", "lexer", "parser"]
|
||||
repository = "https://github.com/sqlparser-rs/sqlparser-rs"
|
||||
license = "Apache-2.0"
|
||||
include = [
|
||||
|
@ -23,6 +23,7 @@ default = ["std"]
|
|||
std = []
|
||||
# Enable JSON output in the `cli` example:
|
||||
json_example = ["serde_json", "serde"]
|
||||
visitor = ["sqlparser_derive"]
|
||||
|
||||
[dependencies]
|
||||
bigdecimal = { version = "0.3", features = ["serde"], optional = true }
|
||||
|
@ -32,6 +33,7 @@ serde = { version = "1.0", features = ["derive"], optional = true }
|
|||
# of dev-dependencies because of
|
||||
# https://github.com/rust-lang/cargo/issues/1596
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
sqlparser_derive = { version = "0.1", path = "derive", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
simple_logger = "4.0"
|
||||
|
|
23
derive/Cargo.toml
Normal file
23
derive/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "sqlparser_derive"
|
||||
description = "proc macro for sqlparser"
|
||||
version = "0.1.0"
|
||||
authors = ["Andy Grove <andygrove73@gmail.com>"]
|
||||
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
|
||||
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",
|
||||
]
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "1.0"
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
79
derive/README.md
Normal file
79
derive/README.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# SQL Parser Derive Macro
|
||||
|
||||
## Visit
|
||||
|
||||
This crate contains a procedural macro that can automatically derive implementations of the `Visit` trait
|
||||
|
||||
```rust
|
||||
#[derive(Visit)]
|
||||
struct Foo {
|
||||
boolean: bool,
|
||||
bar: Bar,
|
||||
}
|
||||
|
||||
#[derive(Visit)]
|
||||
enum Bar {
|
||||
A(),
|
||||
B(String, bool),
|
||||
C { named: i32 },
|
||||
}
|
||||
```
|
||||
|
||||
Will generate code akin to
|
||||
|
||||
```rust
|
||||
impl Visit for Foo {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
self.boolean.visit(visitor)?;
|
||||
self.bar.visit(visitor)?;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit for Bar {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
match self {
|
||||
Self::A() => {}
|
||||
Self::B(_1, _2) => {
|
||||
_1.visit(visitor)?;
|
||||
_2.visit(visitor)?;
|
||||
}
|
||||
Self::C { named } => {
|
||||
named.visit(visitor)?;
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Additionally certain types may wish to call a corresponding method on visitor before recursing
|
||||
|
||||
```rust
|
||||
#[derive(Visit)]
|
||||
#[visit(with = "visit_expr")]
|
||||
enum Expr {
|
||||
A(),
|
||||
B(String, #[cfg_attr(feature = "visitor", visit(with = "visit_relation"))] ObjectName, bool),
|
||||
}
|
||||
```
|
||||
|
||||
Will generate
|
||||
|
||||
```rust
|
||||
impl Visit for Bar {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
visitor.visit_expr(self)?;
|
||||
match self {
|
||||
Self::A() => {}
|
||||
Self::B(_1, _2, _3) => {
|
||||
_1.visit(visitor)?;
|
||||
visitor.visit_relation(_3)?;
|
||||
_2.visit(visitor)?;
|
||||
_3.visit(visitor)?;
|
||||
}
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
```
|
184
derive/src/lib.rs
Normal file
184
derive/src/lib.rs
Normal file
|
@ -0,0 +1,184 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, quote_spanned, ToTokens};
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{
|
||||
parse_macro_input, parse_quote, Attribute, Data, DeriveInput, Fields, GenericParam, Generics,
|
||||
Ident, Index, Lit, Meta, MetaNameValue, NestedMeta,
|
||||
};
|
||||
|
||||
/// Implementation of `[#derive(Visit)]`
|
||||
#[proc_macro_derive(Visit, attributes(visit))]
|
||||
pub fn derive_visit(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
// Parse the input tokens into a syntax tree.
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = input.ident;
|
||||
|
||||
let attributes = Attributes::parse(&input.attrs);
|
||||
// Add a bound `T: HeapSize` to every type parameter T.
|
||||
let generics = add_trait_bounds(input.generics);
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
|
||||
let (pre_visit, post_visit) = attributes.visit(quote!(self));
|
||||
let children = visit_children(&input.data);
|
||||
|
||||
let expanded = quote! {
|
||||
// The generated impl.
|
||||
impl #impl_generics sqlparser::ast::Visit for #name #ty_generics #where_clause {
|
||||
fn visit<V: sqlparser::ast::Visitor>(&self, visitor: &mut V) -> ::std::ops::ControlFlow<V::Break> {
|
||||
#pre_visit
|
||||
#children
|
||||
#post_visit
|
||||
::std::ops::ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
/// Parses attributes that can be provided to this macro
|
||||
///
|
||||
/// `#[visit(leaf, with = "visit_expr")]`
|
||||
#[derive(Default)]
|
||||
struct Attributes {
|
||||
/// Content for the `with` attribute
|
||||
with: Option<Ident>,
|
||||
}
|
||||
|
||||
impl Attributes {
|
||||
fn parse(attrs: &[Attribute]) -> Self {
|
||||
let mut out = Self::default();
|
||||
for attr in attrs.iter().filter(|a| a.path.is_ident("visit")) {
|
||||
let meta = attr.parse_meta().expect("visit attribute");
|
||||
match meta {
|
||||
Meta::List(l) => {
|
||||
for nested in &l.nested {
|
||||
match nested {
|
||||
NestedMeta::Meta(Meta::NameValue(v)) => out.parse_name_value(v),
|
||||
_ => panic!("Expected #[visit(key = \"value\")]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected #[visit(...)]"),
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// Updates self with a name value attribute
|
||||
fn parse_name_value(&mut self, v: &MetaNameValue) {
|
||||
if v.path.is_ident("with") {
|
||||
match &v.lit {
|
||||
Lit::Str(s) => self.with = Some(format_ident!("{}", s.value(), span = s.span())),
|
||||
_ => panic!("Expected a string value, got {}", v.lit.to_token_stream()),
|
||||
}
|
||||
return;
|
||||
}
|
||||
panic!("Unrecognised kv attribute {}", v.path.to_token_stream())
|
||||
}
|
||||
|
||||
/// Returns the pre and post visit token streams
|
||||
fn visit(&self, s: TokenStream) -> (Option<TokenStream>, Option<TokenStream>) {
|
||||
let pre_visit = self.with.as_ref().map(|m| {
|
||||
let m = format_ident!("pre_{}", m);
|
||||
quote!(visitor.#m(#s)?;)
|
||||
});
|
||||
let post_visit = self.with.as_ref().map(|m| {
|
||||
let m = format_ident!("post_{}", m);
|
||||
quote!(visitor.#m(#s)?;)
|
||||
});
|
||||
(pre_visit, post_visit)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a bound `T: Visit` to every type parameter T.
|
||||
fn add_trait_bounds(mut generics: Generics) -> 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));
|
||||
}
|
||||
}
|
||||
generics
|
||||
}
|
||||
|
||||
// Generate the body of the visit implementation for the given type
|
||||
fn visit_children(data: &Data) -> TokenStream {
|
||||
match data {
|
||||
Data::Struct(data) => match &data.fields {
|
||||
Fields::Named(fields) => {
|
||||
let recurse = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
let attributes = Attributes::parse(&f.attrs);
|
||||
let (pre_visit, post_visit) = attributes.visit(quote!(&self.#name));
|
||||
quote_spanned!(f.span() => #pre_visit sqlparser::ast::Visit::visit(&self.#name, visitor)?; #post_visit)
|
||||
});
|
||||
quote! {
|
||||
#(#recurse)*
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||
let index = Index::from(i);
|
||||
let attributes = Attributes::parse(&f.attrs);
|
||||
let (pre_visit, post_visit) = attributes.visit(quote!(&self.#index));
|
||||
quote_spanned!(f.span() => #pre_visit sqlparser::ast::Visit::visit(&self.#index, visitor)?; #post_visit)
|
||||
});
|
||||
quote! {
|
||||
#(#recurse)*
|
||||
}
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote!()
|
||||
}
|
||||
},
|
||||
Data::Enum(data) => {
|
||||
let statements = data.variants.iter().map(|v| {
|
||||
let name = &v.ident;
|
||||
match &v.fields {
|
||||
Fields::Named(fields) => {
|
||||
let names = fields.named.iter().map(|f| &f.ident);
|
||||
let visit = fields.named.iter().map(|f| {
|
||||
let name = &f.ident;
|
||||
let attributes = Attributes::parse(&f.attrs);
|
||||
let (pre_visit, post_visit) = attributes.visit(quote!(&#name));
|
||||
quote_spanned!(f.span() => #pre_visit sqlparser::ast::Visit::visit(#name, visitor)?; #post_visit)
|
||||
});
|
||||
|
||||
quote!(
|
||||
Self::#name { #(#names),* } => {
|
||||
#(#visit)*
|
||||
}
|
||||
)
|
||||
}
|
||||
Fields::Unnamed(fields) => {
|
||||
let names = fields.unnamed.iter().enumerate().map(|(i, f)| format_ident!("_{}", i, span = f.span()));
|
||||
let visit = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
||||
let name = format_ident!("_{}", i);
|
||||
let attributes = Attributes::parse(&f.attrs);
|
||||
let (pre_visit, post_visit) = attributes.visit(quote!(&#name));
|
||||
quote_spanned!(f.span() => #pre_visit sqlparser::ast::Visit::visit(#name, visitor)?; #post_visit)
|
||||
});
|
||||
|
||||
quote! {
|
||||
Self::#name ( #(#names),*) => {
|
||||
#(#visit)*
|
||||
}
|
||||
}
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote! {
|
||||
Self::#name => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
match self {
|
||||
#(#statements),*
|
||||
}
|
||||
}
|
||||
}
|
||||
Data::Union(_) => unimplemented!(),
|
||||
}
|
||||
}
|
|
@ -17,6 +17,9 @@ use core::fmt;
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
use crate::ast::ObjectName;
|
||||
|
||||
use super::value::escape_single_quote_string;
|
||||
|
@ -24,6 +27,7 @@ use super::value::escape_single_quote_string;
|
|||
/// SQL data types
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum DataType {
|
||||
/// Fixed-length character type e.g. CHARACTER(10)
|
||||
Character(Option<CharacterLength>),
|
||||
|
@ -337,6 +341,7 @@ fn format_datetime_precision_and_tz(
|
|||
/// guarantee compatibility with the input query we must maintain its exact information.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TimezoneInfo {
|
||||
/// No information about time zone. E.g., TIMESTAMP
|
||||
None,
|
||||
|
@ -384,6 +389,7 @@ impl fmt::Display for TimezoneInfo {
|
|||
/// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ExactNumberInfo {
|
||||
/// No additional information e.g. `DECIMAL`
|
||||
None,
|
||||
|
@ -414,6 +420,7 @@ impl fmt::Display for ExactNumberInfo {
|
|||
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-length
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct CharacterLength {
|
||||
/// Default (if VARYING) or maximum (if not VARYING) length
|
||||
pub length: u64,
|
||||
|
@ -436,6 +443,7 @@ impl fmt::Display for CharacterLength {
|
|||
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#char-length-units
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CharLengthUnits {
|
||||
/// CHARACTERS unit
|
||||
Characters,
|
||||
|
|
|
@ -20,6 +20,9 @@ use core::fmt;
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
use crate::ast::value::escape_single_quote_string;
|
||||
use crate::ast::{display_comma_separated, display_separated, DataType, Expr, Ident, ObjectName};
|
||||
use crate::tokenizer::Token;
|
||||
|
@ -27,6 +30,7 @@ use crate::tokenizer::Token;
|
|||
/// An `ALTER TABLE` (`Statement::AlterTable`) operation
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum AlterTableOperation {
|
||||
/// `ADD <table_constraint>`
|
||||
AddConstraint(TableConstraint),
|
||||
|
@ -96,6 +100,7 @@ pub enum AlterTableOperation {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum AlterIndexOperation {
|
||||
RenameIndex { index_name: ObjectName },
|
||||
}
|
||||
|
@ -219,6 +224,7 @@ impl fmt::Display for AlterIndexOperation {
|
|||
/// An `ALTER COLUMN` (`Statement::AlterTable`) operation
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum AlterColumnOperation {
|
||||
/// `SET NOT NULL`
|
||||
SetNotNull,
|
||||
|
@ -262,6 +268,7 @@ impl fmt::Display for AlterColumnOperation {
|
|||
/// `ALTER TABLE ADD <constraint>` statement.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TableConstraint {
|
||||
/// `[ CONSTRAINT <name> ] { PRIMARY KEY | UNIQUE } (<columns>)`
|
||||
Unique {
|
||||
|
@ -425,6 +432,7 @@ impl fmt::Display for TableConstraint {
|
|||
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/create-table.html
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum KeyOrIndexDisplay {
|
||||
/// Nothing to display
|
||||
None,
|
||||
|
@ -460,6 +468,7 @@ impl fmt::Display for KeyOrIndexDisplay {
|
|||
/// [3]: https://www.postgresql.org/docs/14/sql-createindex.html
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum IndexType {
|
||||
BTree,
|
||||
Hash,
|
||||
|
@ -478,6 +487,7 @@ impl fmt::Display for IndexType {
|
|||
/// SQL column definition
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct ColumnDef {
|
||||
pub name: Ident,
|
||||
pub data_type: DataType,
|
||||
|
@ -513,6 +523,7 @@ impl fmt::Display for ColumnDef {
|
|||
/// "column options," and we allow any column option to be named.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct ColumnOptionDef {
|
||||
pub name: Option<Ident>,
|
||||
pub option: ColumnOption,
|
||||
|
@ -528,6 +539,7 @@ impl fmt::Display for ColumnOptionDef {
|
|||
/// TABLE` statement.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ColumnOption {
|
||||
/// `NULL`
|
||||
Null,
|
||||
|
@ -617,6 +629,7 @@ fn display_constraint_name(name: &'_ Option<Ident>) -> impl fmt::Display + '_ {
|
|||
/// Used in foreign key constraints in `ON UPDATE` and `ON DELETE` options.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ReferentialAction {
|
||||
Restrict,
|
||||
Cascade,
|
||||
|
|
|
@ -4,6 +4,9 @@ use alloc::{boxed::Box, format, string::String, vec, vec::Vec};
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
use crate::ast::{
|
||||
ColumnDef, FileFormat, HiveDistributionStyle, HiveFormat, ObjectName, OnCommit, Query,
|
||||
SqlOption, Statement, TableConstraint,
|
||||
|
@ -40,6 +43,7 @@ use crate::parser::ParserError;
|
|||
/// [1]: crate::ast::Statement::CreateTable
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct CreateTableBuilder {
|
||||
pub or_replace: bool,
|
||||
pub temporary: bool,
|
||||
|
|
106
src/ast/mod.rs
106
src/ast/mod.rs
|
@ -22,6 +22,9 @@ use core::fmt;
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
pub use self::data_type::{
|
||||
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, TimezoneInfo,
|
||||
};
|
||||
|
@ -38,6 +41,9 @@ pub use self::query::{
|
|||
};
|
||||
pub use self::value::{escape_quoted_string, DateTimeField, TrimWhereField, Value};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
pub use visitor::*;
|
||||
|
||||
mod data_type;
|
||||
mod ddl;
|
||||
pub mod helpers;
|
||||
|
@ -45,6 +51,9 @@ mod operator;
|
|||
mod query;
|
||||
mod value;
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
mod visitor;
|
||||
|
||||
struct DisplaySeparated<'a, T>
|
||||
where
|
||||
T: fmt::Display,
|
||||
|
@ -85,6 +94,7 @@ where
|
|||
/// An identifier, decomposed into its value or character data and the quote style.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Ident {
|
||||
/// The value of the identifier without quotes.
|
||||
pub value: String,
|
||||
|
@ -145,6 +155,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)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct ObjectName(pub Vec<Ident>);
|
||||
|
||||
impl fmt::Display for ObjectName {
|
||||
|
@ -153,10 +164,11 @@ impl fmt::Display for ObjectName {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
/// Represents an Array Expression, either
|
||||
/// `ARRAY[..]`, or `[..]`
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Array {
|
||||
/// The list of expressions between brackets
|
||||
pub elem: Vec<Expr>,
|
||||
|
@ -179,6 +191,7 @@ impl fmt::Display for Array {
|
|||
/// JsonOperator
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum JsonOperator {
|
||||
/// -> keeps the value as json
|
||||
Arrow,
|
||||
|
@ -242,6 +255,7 @@ impl fmt::Display for JsonOperator {
|
|||
/// inappropriate type, like `WHERE 1` or `SELECT 1=1`, as necessary.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit), visit(with = "visit_expr"))]
|
||||
pub enum Expr {
|
||||
/// Identifier e.g. table name or column name
|
||||
Identifier(Ident),
|
||||
|
@ -882,6 +896,7 @@ impl fmt::Display for Expr {
|
|||
/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`)
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct WindowSpec {
|
||||
pub partition_by: Vec<Expr>,
|
||||
pub order_by: Vec<OrderByExpr>,
|
||||
|
@ -927,6 +942,7 @@ impl fmt::Display for WindowSpec {
|
|||
/// reject invalid bounds like `ROWS UNBOUNDED FOLLOWING` before execution.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct WindowFrame {
|
||||
pub units: WindowFrameUnits,
|
||||
pub start_bound: WindowFrameBound,
|
||||
|
@ -952,6 +968,7 @@ impl Default for WindowFrame {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum WindowFrameUnits {
|
||||
Rows,
|
||||
Range,
|
||||
|
@ -971,6 +988,7 @@ impl fmt::Display for WindowFrameUnits {
|
|||
/// Specifies [WindowFrame]'s `start_bound` and `end_bound`
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum WindowFrameBound {
|
||||
/// `CURRENT ROW`
|
||||
CurrentRow,
|
||||
|
@ -994,6 +1012,7 @@ impl fmt::Display for WindowFrameBound {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum AddDropSync {
|
||||
ADD,
|
||||
DROP,
|
||||
|
@ -1012,6 +1031,7 @@ impl fmt::Display for AddDropSync {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ShowCreateObject {
|
||||
Event,
|
||||
Function,
|
||||
|
@ -1036,6 +1056,7 @@ impl fmt::Display for ShowCreateObject {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CommentObject {
|
||||
Column,
|
||||
Table,
|
||||
|
@ -1052,6 +1073,7 @@ impl fmt::Display for CommentObject {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum Password {
|
||||
Password(Expr),
|
||||
NullPassword,
|
||||
|
@ -1061,9 +1083,11 @@ pub enum Password {
|
|||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit), visit(with = "visit_statement"))]
|
||||
pub enum Statement {
|
||||
/// Analyze (Hive)
|
||||
Analyze {
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
partitions: Option<Vec<Expr>>,
|
||||
for_columns: bool,
|
||||
|
@ -1074,11 +1098,13 @@ pub enum Statement {
|
|||
},
|
||||
/// Truncate (Hive)
|
||||
Truncate {
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
partitions: Option<Vec<Expr>>,
|
||||
},
|
||||
/// Msck (Hive)
|
||||
Msck {
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
repair: bool,
|
||||
partition_action: Option<AddDropSync>,
|
||||
|
@ -1092,6 +1118,7 @@ pub enum Statement {
|
|||
/// INTO - optional keyword
|
||||
into: bool,
|
||||
/// TABLE
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
/// COLUMNS
|
||||
columns: Vec<Ident>,
|
||||
|
@ -1119,6 +1146,7 @@ pub enum Statement {
|
|||
},
|
||||
Copy {
|
||||
/// TABLE
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
/// COLUMNS
|
||||
columns: Vec<Ident>,
|
||||
|
@ -1181,6 +1209,7 @@ pub enum Statement {
|
|||
global: Option<bool>,
|
||||
if_not_exists: bool,
|
||||
/// Table name
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
name: ObjectName,
|
||||
/// Optional schema
|
||||
columns: Vec<ColumnDef>,
|
||||
|
@ -1205,6 +1234,7 @@ pub enum Statement {
|
|||
},
|
||||
/// SQLite's `CREATE VIRTUAL TABLE .. USING <module_name> (<module_args>)`
|
||||
CreateVirtualTable {
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
name: ObjectName,
|
||||
if_not_exists: bool,
|
||||
module_name: Ident,
|
||||
|
@ -1214,6 +1244,7 @@ pub enum Statement {
|
|||
CreateIndex {
|
||||
/// index name
|
||||
name: ObjectName,
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
using: Option<Ident>,
|
||||
columns: Vec<OrderByExpr>,
|
||||
|
@ -1247,6 +1278,7 @@ pub enum Statement {
|
|||
/// ALTER TABLE
|
||||
AlterTable {
|
||||
/// Table name
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
name: ObjectName,
|
||||
operation: AlterTableOperation,
|
||||
},
|
||||
|
@ -1383,6 +1415,7 @@ pub enum Statement {
|
|||
ShowColumns {
|
||||
extended: bool,
|
||||
full: bool,
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
filter: Option<ShowStatementFilter>,
|
||||
},
|
||||
|
@ -1498,9 +1531,10 @@ pub enum Statement {
|
|||
/// EXPLAIN TABLE
|
||||
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/explain.html>
|
||||
ExplainTable {
|
||||
// If true, query used the MySQL `DESCRIBE` alias for explain
|
||||
/// If true, query used the MySQL `DESCRIBE` alias for explain
|
||||
describe_alias: bool,
|
||||
// Table name
|
||||
/// Table name
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
},
|
||||
/// EXPLAIN / DESCRIBE for select_statement
|
||||
|
@ -1534,19 +1568,22 @@ pub enum Statement {
|
|||
/// CACHE [ FLAG ] TABLE <table_name> [ OPTIONS('K1' = 'V1', 'K2' = V2) ] [ AS ] [ <query> ]
|
||||
/// Based on Spark SQL,see <https://docs.databricks.com/spark/latest/spark-sql/language-manual/sql-ref-syntax-aux-cache-cache-table.html>
|
||||
Cache {
|
||||
// Table flag
|
||||
/// Table flag
|
||||
table_flag: Option<ObjectName>,
|
||||
// Table name
|
||||
/// Table name
|
||||
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
has_as: bool,
|
||||
// Table confs
|
||||
/// Table confs
|
||||
options: Vec<SqlOption>,
|
||||
// Cache table as a Query
|
||||
/// Cache table as a Query
|
||||
query: Option<Query>,
|
||||
},
|
||||
/// UNCACHE TABLE [ IF EXISTS ] <table_name>
|
||||
UNCache {
|
||||
// Table name
|
||||
/// Table name
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
table_name: ObjectName,
|
||||
if_exists: bool,
|
||||
},
|
||||
|
@ -2673,6 +2710,7 @@ impl fmt::Display for Statement {
|
|||
/// [ START [ WITH ] start ] [ CACHE cache ] [ [ NO ] CYCLE ]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SequenceOptions {
|
||||
IncrementBy(Expr, bool),
|
||||
MinValue(MinMaxValue),
|
||||
|
@ -2737,6 +2775,7 @@ impl fmt::Display for SequenceOptions {
|
|||
/// [ MINVALUE minvalue | NO MINVALUE ] [ MAXVALUE maxvalue | NO MAXVALUE ]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum MinMaxValue {
|
||||
// clause is not specified
|
||||
Empty,
|
||||
|
@ -2748,6 +2787,7 @@ pub enum MinMaxValue {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
#[non_exhaustive]
|
||||
pub enum OnInsert {
|
||||
/// ON DUPLICATE KEY UPDATE (MySQL when the key already exists, then execute an update instead)
|
||||
|
@ -2758,18 +2798,21 @@ pub enum OnInsert {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct OnConflict {
|
||||
pub conflict_target: Option<ConflictTarget>,
|
||||
pub action: OnConflictAction,
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ConflictTarget {
|
||||
Columns(Vec<Ident>),
|
||||
OnConstraint(ObjectName),
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum OnConflictAction {
|
||||
DoNothing,
|
||||
DoUpdate(DoUpdate),
|
||||
|
@ -2777,6 +2820,7 @@ pub enum OnConflictAction {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct DoUpdate {
|
||||
/// Column assignments
|
||||
pub assignments: Vec<Assignment>,
|
||||
|
@ -2838,6 +2882,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)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum Privileges {
|
||||
/// All privileges applicable to the object type
|
||||
All {
|
||||
|
@ -2874,6 +2919,7 @@ impl fmt::Display for Privileges {
|
|||
/// Specific direction for FETCH statement
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum FetchDirection {
|
||||
Count { limit: Value },
|
||||
Next,
|
||||
|
@ -2937,6 +2983,7 @@ impl fmt::Display for FetchDirection {
|
|||
/// A privilege on a database object (table, sequence, etc.).
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum Action {
|
||||
Connect,
|
||||
Create,
|
||||
|
@ -2986,6 +3033,7 @@ impl fmt::Display for Action {
|
|||
/// Objects on which privileges are granted in a GRANT statement.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum GrantObjects {
|
||||
/// Grant privileges on `ALL SEQUENCES IN SCHEMA <schema_name> [, ...]`
|
||||
AllSequencesInSchema { schemas: Vec<ObjectName> },
|
||||
|
@ -3032,6 +3080,7 @@ impl fmt::Display for GrantObjects {
|
|||
/// SQL assignment `foo = expr` as used in SQLUpdate
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Assignment {
|
||||
pub id: Vec<Ident>,
|
||||
pub value: Expr,
|
||||
|
@ -3045,6 +3094,7 @@ impl fmt::Display for Assignment {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum FunctionArgExpr {
|
||||
Expr(Expr),
|
||||
/// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
|
||||
|
@ -3065,6 +3115,7 @@ impl fmt::Display for FunctionArgExpr {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum FunctionArg {
|
||||
Named { name: Ident, arg: FunctionArgExpr },
|
||||
Unnamed(FunctionArgExpr),
|
||||
|
@ -3081,6 +3132,7 @@ impl fmt::Display for FunctionArg {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CloseCursor {
|
||||
All,
|
||||
Specific { name: Ident },
|
||||
|
@ -3098,6 +3150,7 @@ impl fmt::Display for CloseCursor {
|
|||
/// A function call
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Function {
|
||||
pub name: ObjectName,
|
||||
pub args: Vec<FunctionArg>,
|
||||
|
@ -3111,6 +3164,7 @@ pub struct Function {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum AnalyzeFormat {
|
||||
TEXT,
|
||||
GRAPHVIZ,
|
||||
|
@ -3152,6 +3206,7 @@ impl fmt::Display for Function {
|
|||
/// External table's available file format
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum FileFormat {
|
||||
TEXTFILE,
|
||||
SEQUENCEFILE,
|
||||
|
@ -3181,6 +3236,7 @@ impl fmt::Display for FileFormat {
|
|||
/// [ WITHIN GROUP (ORDER BY <within_group1>[, ...] ) ]`
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct ListAgg {
|
||||
pub distinct: bool,
|
||||
pub expr: Box<Expr>,
|
||||
|
@ -3218,6 +3274,7 @@ impl fmt::Display for ListAgg {
|
|||
/// The `ON OVERFLOW` clause of a LISTAGG invocation
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ListAggOnOverflow {
|
||||
/// `ON OVERFLOW ERROR`
|
||||
Error,
|
||||
|
@ -3255,6 +3312,7 @@ impl fmt::Display for ListAggOnOverflow {
|
|||
/// ORDER BY position is defined differently for BigQuery, Postgres and Snowflake.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct ArrayAgg {
|
||||
pub distinct: bool,
|
||||
pub expr: Box<Expr>,
|
||||
|
@ -3291,6 +3349,7 @@ impl fmt::Display for ArrayAgg {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ObjectType {
|
||||
Table,
|
||||
View,
|
||||
|
@ -3315,6 +3374,7 @@ impl fmt::Display for ObjectType {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum KillType {
|
||||
Connection,
|
||||
Query,
|
||||
|
@ -3335,6 +3395,7 @@ impl fmt::Display for KillType {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum HiveDistributionStyle {
|
||||
PARTITIONED {
|
||||
columns: Vec<ColumnDef>,
|
||||
|
@ -3354,14 +3415,15 @@ pub enum HiveDistributionStyle {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum HiveRowFormat {
|
||||
SERDE { class: String },
|
||||
DELIMITED,
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum HiveIOFormat {
|
||||
IOF {
|
||||
|
@ -3375,6 +3437,7 @@ pub enum HiveIOFormat {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct HiveFormat {
|
||||
pub row_format: Option<HiveRowFormat>,
|
||||
pub storage: Option<HiveIOFormat>,
|
||||
|
@ -3383,6 +3446,7 @@ pub struct HiveFormat {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct SqlOption {
|
||||
pub name: Ident,
|
||||
pub value: Value,
|
||||
|
@ -3396,6 +3460,7 @@ impl fmt::Display for SqlOption {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TransactionMode {
|
||||
AccessMode(TransactionAccessMode),
|
||||
IsolationLevel(TransactionIsolationLevel),
|
||||
|
@ -3413,6 +3478,7 @@ impl fmt::Display for TransactionMode {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TransactionAccessMode {
|
||||
ReadOnly,
|
||||
ReadWrite,
|
||||
|
@ -3430,6 +3496,7 @@ impl fmt::Display for TransactionAccessMode {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TransactionIsolationLevel {
|
||||
ReadUncommitted,
|
||||
ReadCommitted,
|
||||
|
@ -3451,6 +3518,7 @@ impl fmt::Display for TransactionIsolationLevel {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ShowStatementFilter {
|
||||
Like(String),
|
||||
ILike(String),
|
||||
|
@ -3473,6 +3541,7 @@ impl fmt::Display for ShowStatementFilter {
|
|||
/// https://sqlite.org/lang_conflict.html
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SqliteOnConflict {
|
||||
Rollback,
|
||||
Abort,
|
||||
|
@ -3496,6 +3565,7 @@ impl fmt::Display for SqliteOnConflict {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CopyTarget {
|
||||
Stdin,
|
||||
Stdout,
|
||||
|
@ -3527,6 +3597,7 @@ impl fmt::Display for CopyTarget {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum OnCommit {
|
||||
DeleteRows,
|
||||
PreserveRows,
|
||||
|
@ -3538,6 +3609,7 @@ pub enum OnCommit {
|
|||
/// <https://www.postgresql.org/docs/14/sql-copy.html>
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CopyOption {
|
||||
/// FORMAT format_name
|
||||
Format(Ident),
|
||||
|
@ -3591,6 +3663,7 @@ impl fmt::Display for CopyOption {
|
|||
/// <https://www.postgresql.org/docs/8.4/sql-copy.html>
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CopyLegacyOption {
|
||||
/// BINARY
|
||||
Binary,
|
||||
|
@ -3619,6 +3692,7 @@ impl fmt::Display for CopyLegacyOption {
|
|||
/// <https://www.postgresql.org/docs/8.4/sql-copy.html>
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CopyLegacyCsvOption {
|
||||
/// HEADER
|
||||
Header,
|
||||
|
@ -3650,6 +3724,7 @@ impl fmt::Display for CopyLegacyCsvOption {
|
|||
///
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum MergeClause {
|
||||
MatchedUpdate {
|
||||
predicate: Option<Expr>,
|
||||
|
@ -3711,6 +3786,7 @@ impl fmt::Display for MergeClause {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum DiscardObject {
|
||||
ALL,
|
||||
PLANS,
|
||||
|
@ -3732,6 +3808,7 @@ impl fmt::Display for DiscardObject {
|
|||
/// Optional context modifier for statements that can be or `LOCAL`, or `SESSION`.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ContextModifier {
|
||||
/// No context defined. Each dialect defines the default in this scenario.
|
||||
None,
|
||||
|
@ -3777,6 +3854,7 @@ impl fmt::Display for DropFunctionOption {
|
|||
/// Function describe in DROP FUNCTION.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct DropFunctionDesc {
|
||||
pub name: ObjectName,
|
||||
pub args: Option<Vec<OperateFunctionArg>>,
|
||||
|
@ -3795,6 +3873,7 @@ impl fmt::Display for DropFunctionDesc {
|
|||
/// Function argument in CREATE OR DROP FUNCTION.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct OperateFunctionArg {
|
||||
pub mode: Option<ArgMode>,
|
||||
pub name: Option<Ident>,
|
||||
|
@ -3843,6 +3922,7 @@ impl fmt::Display for OperateFunctionArg {
|
|||
/// The mode of an argument in CREATE FUNCTION.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ArgMode {
|
||||
In,
|
||||
Out,
|
||||
|
@ -3862,6 +3942,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)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum FunctionBehavior {
|
||||
Immutable,
|
||||
Stable,
|
||||
|
@ -3880,6 +3961,7 @@ impl fmt::Display for FunctionBehavior {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum FunctionDefinition {
|
||||
SingleQuotedDef(String),
|
||||
DoubleDollarDef(String),
|
||||
|
@ -3898,6 +3980,7 @@ impl fmt::Display for FunctionDefinition {
|
|||
/// Postgres: https://www.postgresql.org/docs/15/sql-createfunction.html
|
||||
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct CreateFunctionBody {
|
||||
/// LANGUAGE lang_name
|
||||
pub language: Option<Ident>,
|
||||
|
@ -3936,6 +4019,7 @@ impl fmt::Display for CreateFunctionBody {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum CreateFunctionUsing {
|
||||
Jar(String),
|
||||
File(String),
|
||||
|
@ -3958,6 +4042,7 @@ impl fmt::Display for CreateFunctionUsing {
|
|||
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#schema-definition
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SchemaName {
|
||||
/// Only schema name specified: `<schema name>`.
|
||||
Simple(ObjectName),
|
||||
|
@ -3988,6 +4073,7 @@ impl fmt::Display for SchemaName {
|
|||
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html#function_match
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SearchModifier {
|
||||
/// `IN NATURAL LANGUAGE MODE`.
|
||||
InNaturalLanguageMode,
|
||||
|
|
|
@ -14,14 +14,19 @@ use core::fmt;
|
|||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
use super::display_separated;
|
||||
|
||||
/// Unary operators
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum UnaryOperator {
|
||||
Plus,
|
||||
Minus,
|
||||
|
@ -59,6 +64,7 @@ impl fmt::Display for UnaryOperator {
|
|||
/// Binary operators
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum BinaryOperator {
|
||||
Plus,
|
||||
Minus,
|
||||
|
|
|
@ -16,12 +16,16 @@ use alloc::{boxed::Box, vec::Vec};
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
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)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Query {
|
||||
/// WITH (common table expressions, or CTEs)
|
||||
pub with: Option<With>,
|
||||
|
@ -69,6 +73,7 @@ impl fmt::Display for Query {
|
|||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SetExpr {
|
||||
/// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
|
||||
Select(Box<Select>),
|
||||
|
@ -117,6 +122,7 @@ impl fmt::Display for SetExpr {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SetOperator {
|
||||
Union,
|
||||
Except,
|
||||
|
@ -138,6 +144,7 @@ impl fmt::Display for SetOperator {
|
|||
// For example, BigQuery does not support `DISTINCT` for `EXCEPT` and `INTERSECT`
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SetQuantifier {
|
||||
All,
|
||||
Distinct,
|
||||
|
@ -157,6 +164,7 @@ impl fmt::Display for SetQuantifier {
|
|||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[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))]
|
||||
pub struct Table {
|
||||
pub table_name: Option<String>,
|
||||
pub schema_name: Option<String>,
|
||||
|
@ -183,6 +191,7 @@ impl fmt::Display for Table {
|
|||
/// to a set operation like `UNION`.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Select {
|
||||
pub distinct: bool,
|
||||
/// MSSQL syntax: `TOP (<N>) [ PERCENT ] [ WITH TIES ]`
|
||||
|
@ -267,6 +276,7 @@ impl fmt::Display for Select {
|
|||
/// A hive LATERAL VIEW with potential column aliases
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct LateralView {
|
||||
/// LATERAL VIEW
|
||||
pub lateral_view: Expr,
|
||||
|
@ -300,6 +310,7 @@ impl fmt::Display for LateralView {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct With {
|
||||
pub recursive: bool,
|
||||
pub cte_tables: Vec<Cte>,
|
||||
|
@ -322,6 +333,7 @@ impl fmt::Display for With {
|
|||
/// number of columns in the query matches the number of columns in the query.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Cte {
|
||||
pub alias: TableAlias,
|
||||
pub query: Box<Query>,
|
||||
|
@ -341,6 +353,7 @@ impl fmt::Display for Cte {
|
|||
/// One item of the comma-separated list following `SELECT`
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum SelectItem {
|
||||
/// Any expression, not followed by `[ AS ] alias`
|
||||
UnnamedExpr(Expr),
|
||||
|
@ -355,6 +368,7 @@ pub enum SelectItem {
|
|||
/// Additional options for wildcards, e.g. Snowflake `EXCLUDE` and Bigquery `EXCEPT`.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct WildcardAdditionalOptions {
|
||||
/// `[EXCLUDE...]`.
|
||||
pub opt_exclude: Option<ExcludeSelectItem>,
|
||||
|
@ -383,6 +397,7 @@ impl fmt::Display for WildcardAdditionalOptions {
|
|||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum ExcludeSelectItem {
|
||||
/// Single column name without parenthesis.
|
||||
///
|
||||
|
@ -422,6 +437,7 @@ impl fmt::Display for ExcludeSelectItem {
|
|||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct ExceptSelectItem {
|
||||
/// First guaranteed column.
|
||||
pub fist_elemnt: Ident,
|
||||
|
@ -467,6 +483,7 @@ impl fmt::Display for SelectItem {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct TableWithJoins {
|
||||
pub relation: TableFactor,
|
||||
pub joins: Vec<Join>,
|
||||
|
@ -485,8 +502,10 @@ impl fmt::Display for TableWithJoins {
|
|||
/// A table name or a parenthesized subquery with an optional alias
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TableFactor {
|
||||
Table {
|
||||
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
|
||||
name: ObjectName,
|
||||
alias: Option<TableAlias>,
|
||||
/// Arguments of a table-valued function, as supported by Postgres
|
||||
|
@ -612,6 +631,7 @@ impl fmt::Display for TableFactor {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct TableAlias {
|
||||
pub name: Ident,
|
||||
pub columns: Vec<Ident>,
|
||||
|
@ -629,6 +649,7 @@ impl fmt::Display for TableAlias {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Join {
|
||||
pub relation: TableFactor,
|
||||
pub join_operator: JoinOperator,
|
||||
|
@ -723,6 +744,7 @@ impl fmt::Display for Join {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum JoinOperator {
|
||||
Inner(JoinConstraint),
|
||||
LeftOuter(JoinConstraint),
|
||||
|
@ -745,6 +767,7 @@ pub enum JoinOperator {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum JoinConstraint {
|
||||
On(Expr),
|
||||
Using(Vec<Ident>),
|
||||
|
@ -755,6 +778,7 @@ pub enum JoinConstraint {
|
|||
/// An `ORDER BY` expression
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct OrderByExpr {
|
||||
pub expr: Expr,
|
||||
/// Optional `ASC` or `DESC`
|
||||
|
@ -782,6 +806,7 @@ impl fmt::Display for OrderByExpr {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Offset {
|
||||
pub value: Expr,
|
||||
pub rows: OffsetRows,
|
||||
|
@ -796,6 +821,7 @@ impl fmt::Display for Offset {
|
|||
/// Stores the keyword after `OFFSET <number>`
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum OffsetRows {
|
||||
/// Omitting ROW/ROWS is non-standard MySQL quirk.
|
||||
None,
|
||||
|
@ -815,6 +841,7 @@ impl fmt::Display for OffsetRows {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Fetch {
|
||||
pub with_ties: bool,
|
||||
pub percent: bool,
|
||||
|
@ -835,6 +862,7 @@ impl fmt::Display for Fetch {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct LockClause {
|
||||
pub lock_type: LockType,
|
||||
pub of: Option<ObjectName>,
|
||||
|
@ -856,6 +884,7 @@ impl fmt::Display for LockClause {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum LockType {
|
||||
Share,
|
||||
Update,
|
||||
|
@ -873,6 +902,7 @@ impl fmt::Display for LockType {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum NonBlock {
|
||||
Nowait,
|
||||
SkipLocked,
|
||||
|
@ -890,6 +920,7 @@ impl fmt::Display for NonBlock {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Top {
|
||||
/// SQL semantic equivalent of LIMIT but with same structure as FETCH.
|
||||
pub with_ties: bool,
|
||||
|
@ -911,6 +942,7 @@ impl fmt::Display for Top {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Values {
|
||||
/// Was there an explict ROWs keyword (MySQL)?
|
||||
/// <https://dev.mysql.com/doc/refman/8.0/en/values.html>
|
||||
|
@ -934,6 +966,7 @@ impl fmt::Display for Values {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct SelectInto {
|
||||
pub temporary: bool,
|
||||
pub unlogged: bool,
|
||||
|
|
|
@ -16,12 +16,17 @@ use core::fmt;
|
|||
|
||||
#[cfg(feature = "bigdecimal")]
|
||||
use bigdecimal::BigDecimal;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
/// Primitive SQL values such as number and string
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum Value {
|
||||
/// Numeric literal
|
||||
#[cfg(not(feature = "bigdecimal"))]
|
||||
|
@ -68,6 +73,7 @@ impl fmt::Display for Value {
|
|||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum DateTimeField {
|
||||
Year,
|
||||
Month,
|
||||
|
@ -198,6 +204,7 @@ pub fn escape_escaped_string(s: &str) -> EscapeEscapedStringLiteral<'_> {
|
|||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum TrimWhereField {
|
||||
Both,
|
||||
Leading,
|
||||
|
|
301
src/ast/visitor.rs
Normal file
301
src/ast/visitor.rs
Normal file
|
@ -0,0 +1,301 @@
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::ast::{Expr, ObjectName, Statement};
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
/// A type that can be visited by a `visitor`
|
||||
pub trait Visit {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break>;
|
||||
}
|
||||
|
||||
impl<T: Visit> Visit for Option<T> {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
if let Some(s) = self {
|
||||
s.visit(visitor)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Visit> Visit for Vec<T> {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
for v in self {
|
||||
v.visit(visitor)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Visit> Visit for Box<T> {
|
||||
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
T::visit(self, visitor)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! visit_noop {
|
||||
($($t:ty),+) => {
|
||||
$(impl Visit for $t {
|
||||
fn visit<V: Visitor>(&self, _visitor: &mut V) -> ControlFlow<V::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
visit_noop!(u8, u16, u32, u64, i8, i16, i32, i64, char, bool, String);
|
||||
|
||||
#[cfg(feature = "bigdecimal")]
|
||||
visit_noop!(bigdecimal::BigDecimal);
|
||||
|
||||
/// A visitor that can be used to walk an AST tree
|
||||
pub trait Visitor {
|
||||
type Break;
|
||||
|
||||
/// Invoked for any relations (e.g. tables) that appear in the AST before visiting children
|
||||
fn pre_visit_relation(&mut self, _relation: &ObjectName) -> ControlFlow<Self::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Invoked for any relations (e.g. tables) that appear in the AST after visiting children
|
||||
fn post_visit_relation(&mut self, _relation: &ObjectName) -> ControlFlow<Self::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Invoked for any expressions that appear in the AST before visiting children
|
||||
fn pre_visit_expr(&mut self, _expr: &Expr) -> ControlFlow<Self::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Invoked for any expressions that appear in the AST
|
||||
fn post_visit_expr(&mut self, _expr: &Expr) -> ControlFlow<Self::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Invoked for any statements that appear in the AST before visiting children
|
||||
fn pre_visit_statement(&mut self, _statement: &Statement) -> ControlFlow<Self::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
/// Invoked for any statements that appear in the AST after visiting children
|
||||
fn post_visit_statement(&mut self, _statement: &Statement) -> ControlFlow<Self::Break> {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
struct RelationVisitor<F>(F);
|
||||
|
||||
impl<E, F: FnMut(&ObjectName) -> ControlFlow<E>> Visitor for RelationVisitor<F> {
|
||||
type Break = E;
|
||||
|
||||
fn pre_visit_relation(&mut self, relation: &ObjectName) -> ControlFlow<Self::Break> {
|
||||
self.0(relation)
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes the provided closure on all relations present in v
|
||||
pub fn visit_relations<V, E, F>(v: &V, f: F) -> ControlFlow<E>
|
||||
where
|
||||
V: Visit,
|
||||
F: FnMut(&ObjectName) -> ControlFlow<E>,
|
||||
{
|
||||
let mut visitor = RelationVisitor(f);
|
||||
v.visit(&mut visitor)?;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
struct ExprVisitor<F>(F);
|
||||
|
||||
impl<E, F: FnMut(&Expr) -> ControlFlow<E>> Visitor for ExprVisitor<F> {
|
||||
type Break = E;
|
||||
|
||||
fn pre_visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::Break> {
|
||||
self.0(expr)
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes the provided closure on all expressions present in v
|
||||
pub fn visit_expressions<V, E, F>(v: &V, f: F) -> ControlFlow<E>
|
||||
where
|
||||
V: Visit,
|
||||
F: FnMut(&Expr) -> ControlFlow<E>,
|
||||
{
|
||||
let mut visitor = ExprVisitor(f);
|
||||
v.visit(&mut visitor)?;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
struct StatementVisitor<F>(F);
|
||||
|
||||
impl<E, F: FnMut(&Statement) -> ControlFlow<E>> Visitor for StatementVisitor<F> {
|
||||
type Break = E;
|
||||
|
||||
fn pre_visit_statement(&mut self, statement: &Statement) -> ControlFlow<Self::Break> {
|
||||
self.0(statement)
|
||||
}
|
||||
}
|
||||
|
||||
/// Invokes the provided closure on all statements present in v
|
||||
pub fn visit_statements<V, E, F>(v: &V, f: F) -> ControlFlow<E>
|
||||
where
|
||||
V: Visit,
|
||||
F: FnMut(&Statement) -> ControlFlow<E>,
|
||||
{
|
||||
let mut visitor = StatementVisitor(f);
|
||||
v.visit(&mut visitor)?;
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::dialect::GenericDialect;
|
||||
use crate::parser::Parser;
|
||||
use crate::tokenizer::Tokenizer;
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestVisitor {
|
||||
visited: Vec<String>,
|
||||
}
|
||||
|
||||
impl Visitor for TestVisitor {
|
||||
type Break = ();
|
||||
|
||||
fn pre_visit_relation(&mut self, relation: &ObjectName) -> ControlFlow<Self::Break> {
|
||||
self.visited.push(format!("PRE: RELATION: {}", relation));
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn post_visit_relation(&mut self, relation: &ObjectName) -> ControlFlow<Self::Break> {
|
||||
self.visited.push(format!("POST: RELATION: {}", relation));
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn pre_visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::Break> {
|
||||
self.visited.push(format!("PRE: EXPR: {}", expr));
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn post_visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::Break> {
|
||||
self.visited.push(format!("POST: EXPR: {}", expr));
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn pre_visit_statement(&mut self, statement: &Statement) -> ControlFlow<Self::Break> {
|
||||
self.visited.push(format!("PRE: STATEMENT: {}", statement));
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
fn post_visit_statement(&mut self, statement: &Statement) -> ControlFlow<Self::Break> {
|
||||
self.visited.push(format!("POST: STATEMENT: {}", statement));
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
fn do_visit(sql: &str) -> Vec<String> {
|
||||
let dialect = GenericDialect {};
|
||||
let mut tokenizer = Tokenizer::new(&dialect, sql);
|
||||
let tokens = tokenizer.tokenize().unwrap();
|
||||
let s = Parser::new(&dialect)
|
||||
.with_tokens(tokens)
|
||||
.parse_statement()
|
||||
.unwrap();
|
||||
|
||||
let mut visitor = TestVisitor::default();
|
||||
s.visit(&mut visitor);
|
||||
visitor.visited
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sql() {
|
||||
let tests = vec![
|
||||
(
|
||||
"SELECT * from table_name",
|
||||
vec![
|
||||
"PRE: STATEMENT: SELECT * FROM table_name",
|
||||
"PRE: RELATION: table_name",
|
||||
"POST: RELATION: table_name",
|
||||
"POST: STATEMENT: SELECT * FROM table_name",
|
||||
],
|
||||
),
|
||||
(
|
||||
"SELECT * from t1 join t2 on t1.id = t2.t1_id",
|
||||
vec![
|
||||
"PRE: STATEMENT: SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id",
|
||||
"PRE: RELATION: t1",
|
||||
"POST: RELATION: t1",
|
||||
"PRE: RELATION: t2",
|
||||
"POST: RELATION: t2",
|
||||
"PRE: EXPR: t1.id = t2.t1_id",
|
||||
"PRE: EXPR: t1.id",
|
||||
"POST: EXPR: t1.id",
|
||||
"PRE: EXPR: t2.t1_id",
|
||||
"POST: EXPR: t2.t1_id",
|
||||
"POST: EXPR: t1.id = t2.t1_id",
|
||||
"POST: STATEMENT: SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id",
|
||||
],
|
||||
),
|
||||
(
|
||||
"SELECT * from t1 where EXISTS(SELECT column from t2)",
|
||||
vec![
|
||||
"PRE: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
|
||||
"PRE: RELATION: t1",
|
||||
"POST: RELATION: t1",
|
||||
"PRE: EXPR: EXISTS (SELECT column FROM t2)",
|
||||
"PRE: EXPR: column",
|
||||
"POST: EXPR: column",
|
||||
"PRE: RELATION: t2",
|
||||
"POST: RELATION: t2",
|
||||
"POST: EXPR: EXISTS (SELECT column FROM t2)",
|
||||
"POST: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
|
||||
],
|
||||
),
|
||||
(
|
||||
"SELECT * from t1 where EXISTS(SELECT column from t2)",
|
||||
vec![
|
||||
"PRE: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
|
||||
"PRE: RELATION: t1",
|
||||
"POST: RELATION: t1",
|
||||
"PRE: EXPR: EXISTS (SELECT column FROM t2)",
|
||||
"PRE: EXPR: column",
|
||||
"POST: EXPR: column",
|
||||
"PRE: RELATION: t2",
|
||||
"POST: RELATION: t2",
|
||||
"POST: EXPR: EXISTS (SELECT column FROM t2)",
|
||||
"POST: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2)",
|
||||
],
|
||||
),
|
||||
(
|
||||
"SELECT * from t1 where EXISTS(SELECT column from t2) UNION SELECT * from t3",
|
||||
vec![
|
||||
"PRE: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2) UNION SELECT * FROM t3",
|
||||
"PRE: RELATION: t1",
|
||||
"POST: RELATION: t1",
|
||||
"PRE: EXPR: EXISTS (SELECT column FROM t2)",
|
||||
"PRE: EXPR: column",
|
||||
"POST: EXPR: column",
|
||||
"PRE: RELATION: t2",
|
||||
"POST: RELATION: t2",
|
||||
"POST: EXPR: EXISTS (SELECT column FROM t2)",
|
||||
"PRE: RELATION: t3",
|
||||
"POST: RELATION: t3",
|
||||
"POST: STATEMENT: SELECT * FROM t1 WHERE EXISTS (SELECT column FROM t2) UNION SELECT * FROM t3",
|
||||
],
|
||||
),
|
||||
];
|
||||
for (sql, expected) in tests {
|
||||
let actual = do_visit(sql);
|
||||
let actual: Vec<_> = actual.iter().map(|x| x.as_str()).collect();
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,9 @@
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
/// Defines a string constant for a single keyword: `kw_def!(SELECT);`
|
||||
/// expands to `pub const SELECT = "SELECT";`
|
||||
macro_rules! kw_def {
|
||||
|
@ -46,6 +49,7 @@ macro_rules! define_keywords {
|
|||
),*) => {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum Keyword {
|
||||
NoKeyword,
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
// Allow proc-macros to find this crate
|
||||
extern crate self as sqlparser;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
extern crate alloc;
|
||||
|
||||
|
|
|
@ -31,6 +31,9 @@ use core::str::Chars;
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "visitor")]
|
||||
use sqlparser_derive::Visit;
|
||||
|
||||
use crate::dialect::SnowflakeDialect;
|
||||
use crate::dialect::{Dialect, MySqlDialect};
|
||||
use crate::keywords::{Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX};
|
||||
|
@ -38,6 +41,7 @@ use crate::keywords::{Keyword, ALL_KEYWORDS, ALL_KEYWORDS_INDEX};
|
|||
/// SQL Token enumeration
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum Token {
|
||||
/// An end-of-file marker, not a real token
|
||||
EOF,
|
||||
|
@ -264,6 +268,7 @@ impl Token {
|
|||
/// A keyword (like SELECT) or an optionally quoted SQL identifier
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub struct Word {
|
||||
/// The value of the token, without the enclosing quotes, and with the
|
||||
/// escape sequences (if any) processed (TODO: escapes are not handled)
|
||||
|
@ -302,6 +307,7 @@ impl Word {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit))]
|
||||
pub enum Whitespace {
|
||||
Space,
|
||||
Newline,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue