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:
Raphael Taylor-Davies 2022-12-28 15:07:12 +00:00 committed by GitHub
parent 3e990466f8
commit dec3c2b818
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 771 additions and 11 deletions

1
.gitignore vendored
View file

@ -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

View file

@ -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
View 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
View 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
View 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!(),
}
}

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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
View 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)
}
}
}

View file

@ -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,

View file

@ -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;

View file

@ -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,