mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-25 16:34:04 +00:00
Merge pull request #105 from benesch/renames
Remove "SQL" from types (and other renames)
This commit is contained in:
commit
bafb20746f
19 changed files with 887 additions and 905 deletions
|
@ -19,7 +19,7 @@ use simple_logger;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use sqlparser::dialect::*;
|
use sqlparser::dialect::*;
|
||||||
use sqlparser::sqlparser::Parser;
|
use sqlparser::parser::Parser;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
simple_logger::init().unwrap();
|
simple_logger::init().unwrap();
|
||||||
|
@ -30,10 +30,10 @@ fn main() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let dialect: Box<dyn Dialect> = match std::env::args().nth(2).unwrap_or_default().as_ref() {
|
let dialect: Box<dyn Dialect> = match std::env::args().nth(2).unwrap_or_default().as_ref() {
|
||||||
"--ansi" => Box::new(AnsiSqlDialect {}),
|
"--ansi" => Box::new(AnsiDialect {}),
|
||||||
"--postgres" => Box::new(PostgreSqlDialect {}),
|
"--postgres" => Box::new(PostgreSqlDialect {}),
|
||||||
"--ms" => Box::new(MsSqlDialect {}),
|
"--ms" => Box::new(MsSqlDialect {}),
|
||||||
"--generic" | "" => Box::new(GenericSqlDialect {}),
|
"--generic" | "" => Box::new(GenericDialect {}),
|
||||||
s => panic!("Unexpected parameter: {}", s),
|
s => panic!("Unexpected parameter: {}", s),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
|
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
|
|
||||||
use sqlparser::dialect::GenericSqlDialect;
|
use sqlparser::dialect::GenericDialect;
|
||||||
use sqlparser::sqlparser::*;
|
use sqlparser::parser::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let sql = "SELECT a, b, 123, myfunc(b) \
|
let sql = "SELECT a, b, 123, myfunc(b) \
|
||||||
|
@ -21,7 +21,7 @@ fn main() {
|
||||||
WHERE a > b AND b < 100 \
|
WHERE a > b AND b < 100 \
|
||||||
ORDER BY a DESC, b";
|
ORDER BY a DESC, b";
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
|
|
||||||
let ast = Parser::parse_sql(&dialect, sql.to_string()).unwrap();
|
let ast = Parser::parse_sql(&dialect, sql.to_string()).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use super::SQLObjectName;
|
use super::ObjectName;
|
||||||
|
|
||||||
/// SQL data types
|
/// SQL data types
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLType {
|
pub enum DataType {
|
||||||
/// Fixed-length character type e.g. CHAR(10)
|
/// Fixed-length character type e.g. CHAR(10)
|
||||||
Char(Option<u64>),
|
Char(Option<u64>),
|
||||||
/// Variable-length character type e.g. VARCHAR(10)
|
/// Variable-length character type e.g. VARCHAR(10)
|
||||||
|
@ -60,44 +60,44 @@ pub enum SQLType {
|
||||||
/// Bytea
|
/// Bytea
|
||||||
Bytea,
|
Bytea,
|
||||||
/// Custom type such as enums
|
/// Custom type such as enums
|
||||||
Custom(SQLObjectName),
|
Custom(ObjectName),
|
||||||
/// Arrays
|
/// Arrays
|
||||||
Array(Box<SQLType>),
|
Array(Box<DataType>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLType {
|
impl ToString for DataType {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLType::Char(size) => format_type_with_optional_length("char", size),
|
DataType::Char(size) => format_type_with_optional_length("char", size),
|
||||||
SQLType::Varchar(size) => format_type_with_optional_length("character varying", size),
|
DataType::Varchar(size) => format_type_with_optional_length("character varying", size),
|
||||||
SQLType::Uuid => "uuid".to_string(),
|
DataType::Uuid => "uuid".to_string(),
|
||||||
SQLType::Clob(size) => format!("clob({})", size),
|
DataType::Clob(size) => format!("clob({})", size),
|
||||||
SQLType::Binary(size) => format!("binary({})", size),
|
DataType::Binary(size) => format!("binary({})", size),
|
||||||
SQLType::Varbinary(size) => format!("varbinary({})", size),
|
DataType::Varbinary(size) => format!("varbinary({})", size),
|
||||||
SQLType::Blob(size) => format!("blob({})", size),
|
DataType::Blob(size) => format!("blob({})", size),
|
||||||
SQLType::Decimal(precision, scale) => {
|
DataType::Decimal(precision, scale) => {
|
||||||
if let Some(scale) = scale {
|
if let Some(scale) = scale {
|
||||||
format!("numeric({},{})", precision.unwrap(), scale)
|
format!("numeric({},{})", precision.unwrap(), scale)
|
||||||
} else {
|
} else {
|
||||||
format_type_with_optional_length("numeric", precision)
|
format_type_with_optional_length("numeric", precision)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SQLType::Float(size) => format_type_with_optional_length("float", size),
|
DataType::Float(size) => format_type_with_optional_length("float", size),
|
||||||
SQLType::SmallInt => "smallint".to_string(),
|
DataType::SmallInt => "smallint".to_string(),
|
||||||
SQLType::Int => "int".to_string(),
|
DataType::Int => "int".to_string(),
|
||||||
SQLType::BigInt => "bigint".to_string(),
|
DataType::BigInt => "bigint".to_string(),
|
||||||
SQLType::Real => "real".to_string(),
|
DataType::Real => "real".to_string(),
|
||||||
SQLType::Double => "double".to_string(),
|
DataType::Double => "double".to_string(),
|
||||||
SQLType::Boolean => "boolean".to_string(),
|
DataType::Boolean => "boolean".to_string(),
|
||||||
SQLType::Date => "date".to_string(),
|
DataType::Date => "date".to_string(),
|
||||||
SQLType::Time => "time".to_string(),
|
DataType::Time => "time".to_string(),
|
||||||
SQLType::Timestamp => "timestamp".to_string(),
|
DataType::Timestamp => "timestamp".to_string(),
|
||||||
SQLType::Interval => "interval".to_string(),
|
DataType::Interval => "interval".to_string(),
|
||||||
SQLType::Regclass => "regclass".to_string(),
|
DataType::Regclass => "regclass".to_string(),
|
||||||
SQLType::Text => "text".to_string(),
|
DataType::Text => "text".to_string(),
|
||||||
SQLType::Bytea => "bytea".to_string(),
|
DataType::Bytea => "bytea".to_string(),
|
||||||
SQLType::Array(ty) => format!("{}[]", ty.to_string()),
|
DataType::Array(ty) => format!("{}[]", ty.to_string()),
|
||||||
SQLType::Custom(ty) => ty.to_string(),
|
DataType::Custom(ty) => ty.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
//! AST types specific to CREATE/ALTER variants of `SQLStatement`
|
//! AST types specific to CREATE/ALTER variants of `SQLStatement`
|
||||||
//! (commonly referred to as Data Definition Language, or DDL)
|
//! (commonly referred to as Data Definition Language, or DDL)
|
||||||
use super::{Expr, SQLIdent, SQLObjectName, SQLType};
|
use super::{DataType, Expr, Ident, ObjectName};
|
||||||
|
|
||||||
/// An `ALTER TABLE` (`SQLStatement::SQLAlterTable`) operation
|
/// An `ALTER TABLE` (`SQLStatement::SQLAlterTable`) operation
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
|
@ -8,7 +8,7 @@ pub enum AlterTableOperation {
|
||||||
/// `ADD <table_constraint>`
|
/// `ADD <table_constraint>`
|
||||||
AddConstraint(TableConstraint),
|
AddConstraint(TableConstraint),
|
||||||
/// TODO: implement `DROP CONSTRAINT <name>`
|
/// TODO: implement `DROP CONSTRAINT <name>`
|
||||||
DropConstraint { name: SQLIdent },
|
DropConstraint { name: Ident },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for AlterTableOperation {
|
impl ToString for AlterTableOperation {
|
||||||
|
@ -26,22 +26,22 @@ impl ToString for AlterTableOperation {
|
||||||
pub enum TableConstraint {
|
pub enum TableConstraint {
|
||||||
/// `[ CONSTRAINT <name> ] { PRIMARY KEY | UNIQUE } (<columns>)`
|
/// `[ CONSTRAINT <name> ] { PRIMARY KEY | UNIQUE } (<columns>)`
|
||||||
Unique {
|
Unique {
|
||||||
name: Option<SQLIdent>,
|
name: Option<Ident>,
|
||||||
columns: Vec<SQLIdent>,
|
columns: Vec<Ident>,
|
||||||
/// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
|
/// Whether this is a `PRIMARY KEY` or just a `UNIQUE` constraint
|
||||||
is_primary: bool,
|
is_primary: bool,
|
||||||
},
|
},
|
||||||
/// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
|
/// A referential integrity constraint (`[ CONSTRAINT <name> ] FOREIGN KEY (<columns>)
|
||||||
/// REFERENCES <foreign_table> (<referred_columns>)`)
|
/// REFERENCES <foreign_table> (<referred_columns>)`)
|
||||||
ForeignKey {
|
ForeignKey {
|
||||||
name: Option<SQLIdent>,
|
name: Option<Ident>,
|
||||||
columns: Vec<SQLIdent>,
|
columns: Vec<Ident>,
|
||||||
foreign_table: SQLObjectName,
|
foreign_table: ObjectName,
|
||||||
referred_columns: Vec<SQLIdent>,
|
referred_columns: Vec<Ident>,
|
||||||
},
|
},
|
||||||
/// `[ CONSTRAINT <name> ] CHECK (<expr>)`
|
/// `[ CONSTRAINT <name> ] CHECK (<expr>)`
|
||||||
Check {
|
Check {
|
||||||
name: Option<SQLIdent>,
|
name: Option<Ident>,
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -82,14 +82,14 @@ impl ToString for TableConstraint {
|
||||||
|
|
||||||
/// SQL column definition
|
/// SQL column definition
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLColumnDef {
|
pub struct ColumnDef {
|
||||||
pub name: SQLIdent,
|
pub name: Ident,
|
||||||
pub data_type: SQLType,
|
pub data_type: DataType,
|
||||||
pub collation: Option<SQLObjectName>,
|
pub collation: Option<ObjectName>,
|
||||||
pub options: Vec<ColumnOptionDef>,
|
pub options: Vec<ColumnOptionDef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLColumnDef {
|
impl ToString for ColumnDef {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
format!(
|
format!(
|
||||||
"{} {}{}",
|
"{} {}{}",
|
||||||
|
@ -122,7 +122,7 @@ impl ToString for SQLColumnDef {
|
||||||
/// "column options," and we allow any column option to be named.
|
/// "column options," and we allow any column option to be named.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct ColumnOptionDef {
|
pub struct ColumnOptionDef {
|
||||||
pub name: Option<SQLIdent>,
|
pub name: Option<Ident>,
|
||||||
pub option: ColumnOption,
|
pub option: ColumnOption,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +153,8 @@ pub enum ColumnOption {
|
||||||
/// A referential integrity constraint (`[FOREIGN KEY REFERENCES
|
/// A referential integrity constraint (`[FOREIGN KEY REFERENCES
|
||||||
/// <foreign_table> (<referred_columns>)`).
|
/// <foreign_table> (<referred_columns>)`).
|
||||||
ForeignKey {
|
ForeignKey {
|
||||||
foreign_table: SQLObjectName,
|
foreign_table: ObjectName,
|
||||||
referred_columns: Vec<SQLIdent>,
|
referred_columns: Vec<Ident>,
|
||||||
},
|
},
|
||||||
// `CHECK (<expr>)`
|
// `CHECK (<expr>)`
|
||||||
Check(Expr),
|
Check(Expr),
|
||||||
|
@ -187,7 +187,7 @@ impl ToString for ColumnOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_constraint_name(name: &Option<SQLIdent>) -> String {
|
fn format_constraint_name(name: &Option<Ident>) -> String {
|
||||||
name.as_ref()
|
name.as_ref()
|
||||||
.map(|name| format!("CONSTRAINT {} ", name))
|
.map(|name| format!("CONSTRAINT {} ", name))
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
|
@ -12,23 +12,23 @@
|
||||||
|
|
||||||
//! SQL Abstract Syntax Tree (AST) types
|
//! SQL Abstract Syntax Tree (AST) types
|
||||||
|
|
||||||
|
mod data_type;
|
||||||
mod ddl;
|
mod ddl;
|
||||||
|
mod operator;
|
||||||
mod query;
|
mod query;
|
||||||
mod sql_operator;
|
|
||||||
mod sqltype;
|
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
pub use self::data_type::DataType;
|
||||||
pub use self::ddl::{
|
pub use self::ddl::{
|
||||||
AlterTableOperation, ColumnOption, ColumnOptionDef, SQLColumnDef, TableConstraint,
|
AlterTableOperation, ColumnDef, ColumnOption, ColumnOptionDef, TableConstraint,
|
||||||
};
|
};
|
||||||
|
pub use self::operator::{BinaryOperator, UnaryOperator};
|
||||||
pub use self::query::{
|
pub use self::query::{
|
||||||
Cte, Fetch, Join, JoinConstraint, JoinOperator, SQLOrderByExpr, SQLQuery, SQLSelect,
|
Cte, Fetch, Join, JoinConstraint, JoinOperator, OrderByExpr, Query, Select, SelectItem,
|
||||||
SQLSelectItem, SQLSetExpr, SQLSetOperator, SQLValues, TableAlias, TableFactor, TableWithJoins,
|
SetExpr, SetOperator, TableAlias, TableFactor, TableWithJoins, Values,
|
||||||
};
|
};
|
||||||
pub use self::sql_operator::{SQLBinaryOperator, SQLUnaryOperator};
|
|
||||||
pub use self::sqltype::SQLType;
|
|
||||||
pub use self::value::{SQLDateTimeField, Value};
|
pub use self::value::{SQLDateTimeField, Value};
|
||||||
|
|
||||||
/// Like `vec.join(", ")`, but for any types implementing ToString.
|
/// Like `vec.join(", ")`, but for any types implementing ToString.
|
||||||
|
@ -45,7 +45,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Identifier name, in the originally quoted form (e.g. `"id"`)
|
/// Identifier name, in the originally quoted form (e.g. `"id"`)
|
||||||
pub type SQLIdent = String;
|
pub type Ident = String;
|
||||||
|
|
||||||
/// An SQL expression of any type.
|
/// An SQL expression of any type.
|
||||||
///
|
///
|
||||||
|
@ -55,76 +55,76 @@ pub type SQLIdent = String;
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// Identifier e.g. table name or column name
|
/// Identifier e.g. table name or column name
|
||||||
SQLIdentifier(SQLIdent),
|
Identifier(Ident),
|
||||||
/// Unqualified wildcard (`*`). SQL allows this in limited contexts, such as:
|
/// Unqualified wildcard (`*`). SQL allows this in limited contexts, such as:
|
||||||
/// - right after `SELECT` (which is represented as a [SQLSelectItem::Wildcard] instead)
|
/// - right after `SELECT` (which is represented as a [SQLSelectItem::Wildcard] instead)
|
||||||
/// - or as part of an aggregate function, e.g. `COUNT(*)`,
|
/// - or as part of an aggregate function, e.g. `COUNT(*)`,
|
||||||
///
|
///
|
||||||
/// ...but we currently also accept it in contexts where it doesn't make
|
/// ...but we currently also accept it in contexts where it doesn't make
|
||||||
/// sense, such as `* + *`
|
/// sense, such as `* + *`
|
||||||
SQLWildcard,
|
Wildcard,
|
||||||
/// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
|
/// Qualified wildcard, e.g. `alias.*` or `schema.table.*`.
|
||||||
/// (Same caveats apply to SQLQualifiedWildcard as to SQLWildcard.)
|
/// (Same caveats apply to SQLQualifiedWildcard as to SQLWildcard.)
|
||||||
SQLQualifiedWildcard(Vec<SQLIdent>),
|
QualifiedWildcard(Vec<Ident>),
|
||||||
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
|
/// Multi-part identifier, e.g. `table_alias.column` or `schema.table.col`
|
||||||
SQLCompoundIdentifier(Vec<SQLIdent>),
|
CompoundIdentifier(Vec<Ident>),
|
||||||
/// `IS NULL` expression
|
/// `IS NULL` expression
|
||||||
SQLIsNull(Box<Expr>),
|
IsNull(Box<Expr>),
|
||||||
/// `IS NOT NULL` expression
|
/// `IS NOT NULL` expression
|
||||||
SQLIsNotNull(Box<Expr>),
|
IsNotNull(Box<Expr>),
|
||||||
/// `[ NOT ] IN (val1, val2, ...)`
|
/// `[ NOT ] IN (val1, val2, ...)`
|
||||||
SQLInList {
|
InList {
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
list: Vec<Expr>,
|
list: Vec<Expr>,
|
||||||
negated: bool,
|
negated: bool,
|
||||||
},
|
},
|
||||||
/// `[ NOT ] IN (SELECT ...)`
|
/// `[ NOT ] IN (SELECT ...)`
|
||||||
SQLInSubquery {
|
InSubquery {
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
subquery: Box<SQLQuery>,
|
subquery: Box<Query>,
|
||||||
negated: bool,
|
negated: bool,
|
||||||
},
|
},
|
||||||
/// `<expr> [ NOT ] BETWEEN <low> AND <high>`
|
/// `<expr> [ NOT ] BETWEEN <low> AND <high>`
|
||||||
SQLBetween {
|
Between {
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
negated: bool,
|
negated: bool,
|
||||||
low: Box<Expr>,
|
low: Box<Expr>,
|
||||||
high: Box<Expr>,
|
high: Box<Expr>,
|
||||||
},
|
},
|
||||||
/// Binary operation e.g. `1 + 1` or `foo > bar`
|
/// Binary operation e.g. `1 + 1` or `foo > bar`
|
||||||
SQLBinaryOp {
|
BinaryOp {
|
||||||
left: Box<Expr>,
|
left: Box<Expr>,
|
||||||
op: SQLBinaryOperator,
|
op: BinaryOperator,
|
||||||
right: Box<Expr>,
|
right: Box<Expr>,
|
||||||
},
|
},
|
||||||
/// Unary operation e.g. `NOT foo`
|
/// Unary operation e.g. `NOT foo`
|
||||||
SQLUnaryOp {
|
UnaryOp { op: UnaryOperator, expr: Box<Expr> },
|
||||||
op: SQLUnaryOperator,
|
|
||||||
expr: Box<Expr>,
|
|
||||||
},
|
|
||||||
/// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
|
/// CAST an expression to a different data type e.g. `CAST(foo AS VARCHAR(123))`
|
||||||
SQLCast { expr: Box<Expr>, data_type: SQLType },
|
Cast {
|
||||||
SQLExtract {
|
expr: Box<Expr>,
|
||||||
|
data_type: DataType,
|
||||||
|
},
|
||||||
|
Extract {
|
||||||
field: SQLDateTimeField,
|
field: SQLDateTimeField,
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
},
|
},
|
||||||
/// `expr COLLATE collation`
|
/// `expr COLLATE collation`
|
||||||
SQLCollate {
|
Collate {
|
||||||
expr: Box<Expr>,
|
expr: Box<Expr>,
|
||||||
collation: SQLObjectName,
|
collation: ObjectName,
|
||||||
},
|
},
|
||||||
/// Nested expression e.g. `(foo > bar)` or `(1)`
|
/// Nested expression e.g. `(foo > bar)` or `(1)`
|
||||||
SQLNested(Box<Expr>),
|
Nested(Box<Expr>),
|
||||||
/// SQLValue
|
/// SQLValue
|
||||||
SQLValue(Value),
|
Value(Value),
|
||||||
/// Scalar function call e.g. `LEFT(foo, 5)`
|
/// Scalar function call e.g. `LEFT(foo, 5)`
|
||||||
SQLFunction(SQLFunction),
|
Function(Function),
|
||||||
/// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
|
/// `CASE [<operand>] WHEN <condition> THEN <result> ... [ELSE <result>] END`
|
||||||
///
|
///
|
||||||
/// Note we only recognize a complete single expression as `<condition>`,
|
/// Note we only recognize a complete single expression as `<condition>`,
|
||||||
/// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
|
/// not `< 0` nor `1, 2, 3` as allowed in a `<simple when clause>` per
|
||||||
/// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
|
/// <https://jakewheat.github.io/sql-overview/sql-2011-foundation-grammar.html#simple-when-clause>
|
||||||
SQLCase {
|
Case {
|
||||||
operand: Option<Box<Expr>>,
|
operand: Option<Box<Expr>>,
|
||||||
conditions: Vec<Expr>,
|
conditions: Vec<Expr>,
|
||||||
results: Vec<Expr>,
|
results: Vec<Expr>,
|
||||||
|
@ -132,22 +132,22 @@ pub enum Expr {
|
||||||
},
|
},
|
||||||
/// An exists expression `EXISTS(SELECT ...)`, used in expressions like
|
/// An exists expression `EXISTS(SELECT ...)`, used in expressions like
|
||||||
/// `WHERE EXISTS (SELECT ...)`.
|
/// `WHERE EXISTS (SELECT ...)`.
|
||||||
SQLExists(Box<SQLQuery>),
|
Exists(Box<Query>),
|
||||||
/// A parenthesized subquery `(SELECT ...)`, used in expression like
|
/// A parenthesized subquery `(SELECT ...)`, used in expression like
|
||||||
/// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
|
/// `SELECT (subquery) AS x` or `WHERE (subquery) = x`
|
||||||
SQLSubquery(Box<SQLQuery>),
|
Subquery(Box<Query>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Expr {
|
impl ToString for Expr {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Expr::SQLIdentifier(s) => s.to_string(),
|
Expr::Identifier(s) => s.to_string(),
|
||||||
Expr::SQLWildcard => "*".to_string(),
|
Expr::Wildcard => "*".to_string(),
|
||||||
Expr::SQLQualifiedWildcard(q) => q.join(".") + ".*",
|
Expr::QualifiedWildcard(q) => q.join(".") + ".*",
|
||||||
Expr::SQLCompoundIdentifier(s) => s.join("."),
|
Expr::CompoundIdentifier(s) => s.join("."),
|
||||||
Expr::SQLIsNull(ast) => format!("{} IS NULL", ast.as_ref().to_string()),
|
Expr::IsNull(ast) => format!("{} IS NULL", ast.as_ref().to_string()),
|
||||||
Expr::SQLIsNotNull(ast) => format!("{} IS NOT NULL", ast.as_ref().to_string()),
|
Expr::IsNotNull(ast) => format!("{} IS NOT NULL", ast.as_ref().to_string()),
|
||||||
Expr::SQLInList {
|
Expr::InList {
|
||||||
expr,
|
expr,
|
||||||
list,
|
list,
|
||||||
negated,
|
negated,
|
||||||
|
@ -157,7 +157,7 @@ impl ToString for Expr {
|
||||||
if *negated { "NOT " } else { "" },
|
if *negated { "NOT " } else { "" },
|
||||||
comma_separated_string(list)
|
comma_separated_string(list)
|
||||||
),
|
),
|
||||||
Expr::SQLInSubquery {
|
Expr::InSubquery {
|
||||||
expr,
|
expr,
|
||||||
subquery,
|
subquery,
|
||||||
negated,
|
negated,
|
||||||
|
@ -167,7 +167,7 @@ impl ToString for Expr {
|
||||||
if *negated { "NOT " } else { "" },
|
if *negated { "NOT " } else { "" },
|
||||||
subquery.to_string()
|
subquery.to_string()
|
||||||
),
|
),
|
||||||
Expr::SQLBetween {
|
Expr::Between {
|
||||||
expr,
|
expr,
|
||||||
negated,
|
negated,
|
||||||
low,
|
low,
|
||||||
|
@ -179,32 +179,32 @@ impl ToString for Expr {
|
||||||
low.to_string(),
|
low.to_string(),
|
||||||
high.to_string()
|
high.to_string()
|
||||||
),
|
),
|
||||||
Expr::SQLBinaryOp { left, op, right } => format!(
|
Expr::BinaryOp { left, op, right } => format!(
|
||||||
"{} {} {}",
|
"{} {} {}",
|
||||||
left.as_ref().to_string(),
|
left.as_ref().to_string(),
|
||||||
op.to_string(),
|
op.to_string(),
|
||||||
right.as_ref().to_string()
|
right.as_ref().to_string()
|
||||||
),
|
),
|
||||||
Expr::SQLUnaryOp { op, expr } => {
|
Expr::UnaryOp { op, expr } => {
|
||||||
format!("{} {}", op.to_string(), expr.as_ref().to_string())
|
format!("{} {}", op.to_string(), expr.as_ref().to_string())
|
||||||
}
|
}
|
||||||
Expr::SQLCast { expr, data_type } => format!(
|
Expr::Cast { expr, data_type } => format!(
|
||||||
"CAST({} AS {})",
|
"CAST({} AS {})",
|
||||||
expr.as_ref().to_string(),
|
expr.as_ref().to_string(),
|
||||||
data_type.to_string()
|
data_type.to_string()
|
||||||
),
|
),
|
||||||
Expr::SQLExtract { field, expr } => {
|
Expr::Extract { field, expr } => {
|
||||||
format!("EXTRACT({} FROM {})", field.to_string(), expr.to_string())
|
format!("EXTRACT({} FROM {})", field.to_string(), expr.to_string())
|
||||||
}
|
}
|
||||||
Expr::SQLCollate { expr, collation } => format!(
|
Expr::Collate { expr, collation } => format!(
|
||||||
"{} COLLATE {}",
|
"{} COLLATE {}",
|
||||||
expr.as_ref().to_string(),
|
expr.as_ref().to_string(),
|
||||||
collation.to_string()
|
collation.to_string()
|
||||||
),
|
),
|
||||||
Expr::SQLNested(ast) => format!("({})", ast.as_ref().to_string()),
|
Expr::Nested(ast) => format!("({})", ast.as_ref().to_string()),
|
||||||
Expr::SQLValue(v) => v.to_string(),
|
Expr::Value(v) => v.to_string(),
|
||||||
Expr::SQLFunction(f) => f.to_string(),
|
Expr::Function(f) => f.to_string(),
|
||||||
Expr::SQLCase {
|
Expr::Case {
|
||||||
operand,
|
operand,
|
||||||
conditions,
|
conditions,
|
||||||
results,
|
results,
|
||||||
|
@ -225,21 +225,21 @@ impl ToString for Expr {
|
||||||
}
|
}
|
||||||
s + " END"
|
s + " END"
|
||||||
}
|
}
|
||||||
Expr::SQLExists(s) => format!("EXISTS ({})", s.to_string()),
|
Expr::Exists(s) => format!("EXISTS ({})", s.to_string()),
|
||||||
Expr::SQLSubquery(s) => format!("({})", s.to_string()),
|
Expr::Subquery(s) => format!("({})", s.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`)
|
/// A window specification (i.e. `OVER (PARTITION BY .. ORDER BY .. etc.)`)
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLWindowSpec {
|
pub struct WindowSpec {
|
||||||
pub partition_by: Vec<Expr>,
|
pub partition_by: Vec<Expr>,
|
||||||
pub order_by: Vec<SQLOrderByExpr>,
|
pub order_by: Vec<OrderByExpr>,
|
||||||
pub window_frame: Option<SQLWindowFrame>,
|
pub window_frame: Option<WindowFrame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLWindowSpec {
|
impl ToString for WindowSpec {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
let mut clauses = vec![];
|
let mut clauses = vec![];
|
||||||
if !self.partition_by.is_empty() {
|
if !self.partition_by.is_empty() {
|
||||||
|
@ -277,39 +277,39 @@ impl ToString for SQLWindowSpec {
|
||||||
/// Specifies the data processed by a window function, e.g.
|
/// Specifies the data processed by a window function, e.g.
|
||||||
/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
|
/// `RANGE UNBOUNDED PRECEDING` or `ROWS BETWEEN 5 PRECEDING AND CURRENT ROW`.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLWindowFrame {
|
pub struct WindowFrame {
|
||||||
pub units: SQLWindowFrameUnits,
|
pub units: WindowFrameUnits,
|
||||||
pub start_bound: SQLWindowFrameBound,
|
pub start_bound: WindowFrameBound,
|
||||||
/// The right bound of the `BETWEEN .. AND` clause.
|
/// The right bound of the `BETWEEN .. AND` clause.
|
||||||
pub end_bound: Option<SQLWindowFrameBound>,
|
pub end_bound: Option<WindowFrameBound>,
|
||||||
// TBD: EXCLUDE
|
// TBD: EXCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLWindowFrameUnits {
|
pub enum WindowFrameUnits {
|
||||||
Rows,
|
Rows,
|
||||||
Range,
|
Range,
|
||||||
Groups,
|
Groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLWindowFrameUnits {
|
impl ToString for WindowFrameUnits {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLWindowFrameUnits::Rows => "ROWS".to_string(),
|
WindowFrameUnits::Rows => "ROWS".to_string(),
|
||||||
SQLWindowFrameUnits::Range => "RANGE".to_string(),
|
WindowFrameUnits::Range => "RANGE".to_string(),
|
||||||
SQLWindowFrameUnits::Groups => "GROUPS".to_string(),
|
WindowFrameUnits::Groups => "GROUPS".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for SQLWindowFrameUnits {
|
impl FromStr for WindowFrameUnits {
|
||||||
type Err = ParserError;
|
type Err = ParserError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
"ROWS" => Ok(SQLWindowFrameUnits::Rows),
|
"ROWS" => Ok(WindowFrameUnits::Rows),
|
||||||
"RANGE" => Ok(SQLWindowFrameUnits::Range),
|
"RANGE" => Ok(WindowFrameUnits::Range),
|
||||||
"GROUPS" => Ok(SQLWindowFrameUnits::Groups),
|
"GROUPS" => Ok(WindowFrameUnits::Groups),
|
||||||
_ => Err(ParserError::ParserError(format!(
|
_ => Err(ParserError::ParserError(format!(
|
||||||
"Expected ROWS, RANGE, or GROUPS, found: {}",
|
"Expected ROWS, RANGE, or GROUPS, found: {}",
|
||||||
s
|
s
|
||||||
|
@ -319,7 +319,7 @@ impl FromStr for SQLWindowFrameUnits {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLWindowFrameBound {
|
pub enum WindowFrameBound {
|
||||||
/// "CURRENT ROW"
|
/// "CURRENT ROW"
|
||||||
CurrentRow,
|
CurrentRow,
|
||||||
/// "<N> PRECEDING" or "UNBOUNDED PRECEDING"
|
/// "<N> PRECEDING" or "UNBOUNDED PRECEDING"
|
||||||
|
@ -329,14 +329,14 @@ pub enum SQLWindowFrameBound {
|
||||||
Following(Option<u64>),
|
Following(Option<u64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLWindowFrameBound {
|
impl ToString for WindowFrameBound {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLWindowFrameBound::CurrentRow => "CURRENT ROW".to_string(),
|
WindowFrameBound::CurrentRow => "CURRENT ROW".to_string(),
|
||||||
SQLWindowFrameBound::Preceding(None) => "UNBOUNDED PRECEDING".to_string(),
|
WindowFrameBound::Preceding(None) => "UNBOUNDED PRECEDING".to_string(),
|
||||||
SQLWindowFrameBound::Following(None) => "UNBOUNDED FOLLOWING".to_string(),
|
WindowFrameBound::Following(None) => "UNBOUNDED FOLLOWING".to_string(),
|
||||||
SQLWindowFrameBound::Preceding(Some(n)) => format!("{} PRECEDING", n),
|
WindowFrameBound::Preceding(Some(n)) => format!("{} PRECEDING", n),
|
||||||
SQLWindowFrameBound::Following(Some(n)) => format!("{} FOLLOWING", n),
|
WindowFrameBound::Following(Some(n)) => format!("{} FOLLOWING", n),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,91 +344,91 @@ impl ToString for SQLWindowFrameBound {
|
||||||
/// A top-level statement (SELECT, INSERT, CREATE, etc.)
|
/// A top-level statement (SELECT, INSERT, CREATE, etc.)
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLStatement {
|
pub enum Statement {
|
||||||
/// SELECT
|
/// SELECT
|
||||||
SQLQuery(Box<SQLQuery>),
|
Query(Box<Query>),
|
||||||
/// INSERT
|
/// INSERT
|
||||||
SQLInsert {
|
Insert {
|
||||||
/// TABLE
|
/// TABLE
|
||||||
table_name: SQLObjectName,
|
table_name: ObjectName,
|
||||||
/// COLUMNS
|
/// COLUMNS
|
||||||
columns: Vec<SQLIdent>,
|
columns: Vec<Ident>,
|
||||||
/// A SQL query that specifies what to insert
|
/// A SQL query that specifies what to insert
|
||||||
source: Box<SQLQuery>,
|
source: Box<Query>,
|
||||||
},
|
},
|
||||||
SQLCopy {
|
Copy {
|
||||||
/// TABLE
|
/// TABLE
|
||||||
table_name: SQLObjectName,
|
table_name: ObjectName,
|
||||||
/// COLUMNS
|
/// COLUMNS
|
||||||
columns: Vec<SQLIdent>,
|
columns: Vec<Ident>,
|
||||||
/// VALUES a vector of values to be copied
|
/// VALUES a vector of values to be copied
|
||||||
values: Vec<Option<String>>,
|
values: Vec<Option<String>>,
|
||||||
},
|
},
|
||||||
/// UPDATE
|
/// UPDATE
|
||||||
SQLUpdate {
|
Update {
|
||||||
/// TABLE
|
/// TABLE
|
||||||
table_name: SQLObjectName,
|
table_name: ObjectName,
|
||||||
/// Column assignments
|
/// Column assignments
|
||||||
assignments: Vec<SQLAssignment>,
|
assignments: Vec<Assignment>,
|
||||||
/// WHERE
|
/// WHERE
|
||||||
selection: Option<Expr>,
|
selection: Option<Expr>,
|
||||||
},
|
},
|
||||||
/// DELETE
|
/// DELETE
|
||||||
SQLDelete {
|
Delete {
|
||||||
/// FROM
|
/// FROM
|
||||||
table_name: SQLObjectName,
|
table_name: ObjectName,
|
||||||
/// WHERE
|
/// WHERE
|
||||||
selection: Option<Expr>,
|
selection: Option<Expr>,
|
||||||
},
|
},
|
||||||
/// CREATE VIEW
|
/// CREATE VIEW
|
||||||
SQLCreateView {
|
CreateView {
|
||||||
/// View name
|
/// View name
|
||||||
name: SQLObjectName,
|
name: ObjectName,
|
||||||
columns: Vec<SQLIdent>,
|
columns: Vec<Ident>,
|
||||||
query: Box<SQLQuery>,
|
query: Box<Query>,
|
||||||
materialized: bool,
|
materialized: bool,
|
||||||
with_options: Vec<SQLOption>,
|
with_options: Vec<SqlOption>,
|
||||||
},
|
},
|
||||||
/// CREATE TABLE
|
/// CREATE TABLE
|
||||||
SQLCreateTable {
|
CreateTable {
|
||||||
/// Table name
|
/// Table name
|
||||||
name: SQLObjectName,
|
name: ObjectName,
|
||||||
/// Optional schema
|
/// Optional schema
|
||||||
columns: Vec<SQLColumnDef>,
|
columns: Vec<ColumnDef>,
|
||||||
constraints: Vec<TableConstraint>,
|
constraints: Vec<TableConstraint>,
|
||||||
with_options: Vec<SQLOption>,
|
with_options: Vec<SqlOption>,
|
||||||
external: bool,
|
external: bool,
|
||||||
file_format: Option<FileFormat>,
|
file_format: Option<FileFormat>,
|
||||||
location: Option<String>,
|
location: Option<String>,
|
||||||
},
|
},
|
||||||
/// ALTER TABLE
|
/// ALTER TABLE
|
||||||
SQLAlterTable {
|
AlterTable {
|
||||||
/// Table name
|
/// Table name
|
||||||
name: SQLObjectName,
|
name: ObjectName,
|
||||||
operation: AlterTableOperation,
|
operation: AlterTableOperation,
|
||||||
},
|
},
|
||||||
/// DROP TABLE
|
/// DROP TABLE
|
||||||
SQLDrop {
|
Drop {
|
||||||
object_type: SQLObjectType,
|
object_type: ObjectType,
|
||||||
if_exists: bool,
|
if_exists: bool,
|
||||||
names: Vec<SQLObjectName>,
|
names: Vec<ObjectName>,
|
||||||
cascade: bool,
|
cascade: bool,
|
||||||
},
|
},
|
||||||
/// `{ BEGIN [ TRANSACTION | WORK ] | START TRANSACTION } ...`
|
/// `{ BEGIN [ TRANSACTION | WORK ] | START TRANSACTION } ...`
|
||||||
SQLStartTransaction { modes: Vec<TransactionMode> },
|
StartTransaction { modes: Vec<TransactionMode> },
|
||||||
/// `SET TRANSACTION ...`
|
/// `SET TRANSACTION ...`
|
||||||
SQLSetTransaction { modes: Vec<TransactionMode> },
|
SetTransaction { modes: Vec<TransactionMode> },
|
||||||
/// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
|
/// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
|
||||||
SQLCommit { chain: bool },
|
Commit { chain: bool },
|
||||||
/// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
|
/// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
|
||||||
SQLRollback { chain: bool },
|
Rollback { chain: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLStatement {
|
impl ToString for Statement {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLStatement::SQLQuery(s) => s.to_string(),
|
Statement::Query(s) => s.to_string(),
|
||||||
SQLStatement::SQLInsert {
|
Statement::Insert {
|
||||||
table_name,
|
table_name,
|
||||||
columns,
|
columns,
|
||||||
source,
|
source,
|
||||||
|
@ -440,7 +440,7 @@ impl ToString for SQLStatement {
|
||||||
s += &source.to_string();
|
s += &source.to_string();
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
SQLStatement::SQLCopy {
|
Statement::Copy {
|
||||||
table_name,
|
table_name,
|
||||||
columns,
|
columns,
|
||||||
values,
|
values,
|
||||||
|
@ -463,7 +463,7 @@ impl ToString for SQLStatement {
|
||||||
s += "\n\\.";
|
s += "\n\\.";
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
SQLStatement::SQLUpdate {
|
Statement::Update {
|
||||||
table_name,
|
table_name,
|
||||||
assignments,
|
assignments,
|
||||||
selection,
|
selection,
|
||||||
|
@ -478,7 +478,7 @@ impl ToString for SQLStatement {
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
SQLStatement::SQLDelete {
|
Statement::Delete {
|
||||||
table_name,
|
table_name,
|
||||||
selection,
|
selection,
|
||||||
} => {
|
} => {
|
||||||
|
@ -488,7 +488,7 @@ impl ToString for SQLStatement {
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
SQLStatement::SQLCreateView {
|
Statement::CreateView {
|
||||||
name,
|
name,
|
||||||
columns,
|
columns,
|
||||||
query,
|
query,
|
||||||
|
@ -515,7 +515,7 @@ impl ToString for SQLStatement {
|
||||||
query.to_string(),
|
query.to_string(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SQLStatement::SQLCreateTable {
|
Statement::CreateTable {
|
||||||
name,
|
name,
|
||||||
columns,
|
columns,
|
||||||
constraints,
|
constraints,
|
||||||
|
@ -546,10 +546,10 @@ impl ToString for SQLStatement {
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
SQLStatement::SQLAlterTable { name, operation } => {
|
Statement::AlterTable { name, operation } => {
|
||||||
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
|
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
|
||||||
}
|
}
|
||||||
SQLStatement::SQLDrop {
|
Statement::Drop {
|
||||||
object_type,
|
object_type,
|
||||||
if_exists,
|
if_exists,
|
||||||
names,
|
names,
|
||||||
|
@ -561,7 +561,7 @@ impl ToString for SQLStatement {
|
||||||
comma_separated_string(names),
|
comma_separated_string(names),
|
||||||
if *cascade { " CASCADE" } else { "" },
|
if *cascade { " CASCADE" } else { "" },
|
||||||
),
|
),
|
||||||
SQLStatement::SQLStartTransaction { modes } => format!(
|
Statement::StartTransaction { modes } => format!(
|
||||||
"START TRANSACTION{}",
|
"START TRANSACTION{}",
|
||||||
if modes.is_empty() {
|
if modes.is_empty() {
|
||||||
"".into()
|
"".into()
|
||||||
|
@ -569,7 +569,7 @@ impl ToString for SQLStatement {
|
||||||
format!(" {}", comma_separated_string(modes))
|
format!(" {}", comma_separated_string(modes))
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
SQLStatement::SQLSetTransaction { modes } => format!(
|
Statement::SetTransaction { modes } => format!(
|
||||||
"SET TRANSACTION{}",
|
"SET TRANSACTION{}",
|
||||||
if modes.is_empty() {
|
if modes.is_empty() {
|
||||||
"".into()
|
"".into()
|
||||||
|
@ -577,10 +577,10 @@ impl ToString for SQLStatement {
|
||||||
format!(" {}", comma_separated_string(modes))
|
format!(" {}", comma_separated_string(modes))
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
SQLStatement::SQLCommit { chain } => {
|
Statement::Commit { chain } => {
|
||||||
format!("COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
|
format!("COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
|
||||||
}
|
}
|
||||||
SQLStatement::SQLRollback { chain } => {
|
Statement::Rollback { chain } => {
|
||||||
format!("ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
|
format!("ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -589,9 +589,9 @@ impl ToString for SQLStatement {
|
||||||
|
|
||||||
/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
|
/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLObjectName(pub Vec<SQLIdent>);
|
pub struct ObjectName(pub Vec<Ident>);
|
||||||
|
|
||||||
impl ToString for SQLObjectName {
|
impl ToString for ObjectName {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
self.0.join(".")
|
self.0.join(".")
|
||||||
}
|
}
|
||||||
|
@ -599,12 +599,12 @@ impl ToString for SQLObjectName {
|
||||||
|
|
||||||
/// SQL assignment `foo = expr` as used in SQLUpdate
|
/// SQL assignment `foo = expr` as used in SQLUpdate
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLAssignment {
|
pub struct Assignment {
|
||||||
pub id: SQLIdent,
|
pub id: Ident,
|
||||||
pub value: Expr,
|
pub value: Expr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLAssignment {
|
impl ToString for Assignment {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
format!("{} = {}", self.id, self.value.to_string())
|
format!("{} = {}", self.id, self.value.to_string())
|
||||||
}
|
}
|
||||||
|
@ -612,15 +612,15 @@ impl ToString for SQLAssignment {
|
||||||
|
|
||||||
/// SQL function
|
/// SQL function
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLFunction {
|
pub struct Function {
|
||||||
pub name: SQLObjectName,
|
pub name: ObjectName,
|
||||||
pub args: Vec<Expr>,
|
pub args: Vec<Expr>,
|
||||||
pub over: Option<SQLWindowSpec>,
|
pub over: Option<WindowSpec>,
|
||||||
// aggregate functions may specify eg `COUNT(DISTINCT x)`
|
// aggregate functions may specify eg `COUNT(DISTINCT x)`
|
||||||
pub distinct: bool,
|
pub distinct: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLFunction {
|
impl ToString for Function {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
let mut s = format!(
|
let mut s = format!(
|
||||||
"{}({}{})",
|
"{}({}{})",
|
||||||
|
@ -662,7 +662,7 @@ impl ToString for FileFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::sqlparser::ParserError;
|
use crate::parser::ParserError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
impl FromStr for FileFormat {
|
impl FromStr for FileFormat {
|
||||||
type Err = ParserError;
|
type Err = ParserError;
|
||||||
|
@ -686,27 +686,27 @@ impl FromStr for FileFormat {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLObjectType {
|
pub enum ObjectType {
|
||||||
Table,
|
Table,
|
||||||
View,
|
View,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SQLObjectType {
|
impl ObjectType {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLObjectType::Table => "TABLE".into(),
|
ObjectType::Table => "TABLE".into(),
|
||||||
SQLObjectType::View => "VIEW".into(),
|
ObjectType::View => "VIEW".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLOption {
|
pub struct SqlOption {
|
||||||
pub name: SQLIdent,
|
pub name: Ident,
|
||||||
pub value: Value,
|
pub value: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLOption {
|
impl ToString for SqlOption {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
format!("{} = {}", self.name.to_string(), self.value.to_string())
|
format!("{} = {}", self.name.to_string(), self.value.to_string())
|
||||||
}
|
}
|
71
src/ast/operator.rs
Normal file
71
src/ast/operator.rs
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/// Unary operators
|
||||||
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
|
pub enum UnaryOperator {
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Not,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for UnaryOperator {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
UnaryOperator::Plus => "+".to_string(),
|
||||||
|
UnaryOperator::Minus => "-".to_string(),
|
||||||
|
UnaryOperator::Not => "NOT".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Binary operators
|
||||||
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
|
pub enum BinaryOperator {
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Multiply,
|
||||||
|
Divide,
|
||||||
|
Modulus,
|
||||||
|
Gt,
|
||||||
|
Lt,
|
||||||
|
GtEq,
|
||||||
|
LtEq,
|
||||||
|
Eq,
|
||||||
|
NotEq,
|
||||||
|
And,
|
||||||
|
Or,
|
||||||
|
Like,
|
||||||
|
NotLike,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for BinaryOperator {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
BinaryOperator::Plus => "+".to_string(),
|
||||||
|
BinaryOperator::Minus => "-".to_string(),
|
||||||
|
BinaryOperator::Multiply => "*".to_string(),
|
||||||
|
BinaryOperator::Divide => "/".to_string(),
|
||||||
|
BinaryOperator::Modulus => "%".to_string(),
|
||||||
|
BinaryOperator::Gt => ">".to_string(),
|
||||||
|
BinaryOperator::Lt => "<".to_string(),
|
||||||
|
BinaryOperator::GtEq => ">=".to_string(),
|
||||||
|
BinaryOperator::LtEq => "<=".to_string(),
|
||||||
|
BinaryOperator::Eq => "=".to_string(),
|
||||||
|
BinaryOperator::NotEq => "<>".to_string(),
|
||||||
|
BinaryOperator::And => "AND".to_string(),
|
||||||
|
BinaryOperator::Or => "OR".to_string(),
|
||||||
|
BinaryOperator::Like => "LIKE".to_string(),
|
||||||
|
BinaryOperator::NotLike => "NOT LIKE".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,13 +15,13 @@ use super::*;
|
||||||
/// The most complete variant of a `SELECT` query expression, optionally
|
/// The most complete variant of a `SELECT` query expression, optionally
|
||||||
/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
|
/// including `WITH`, `UNION` / other set operations, and `ORDER BY`.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLQuery {
|
pub struct Query {
|
||||||
/// WITH (common table expressions, or CTEs)
|
/// WITH (common table expressions, or CTEs)
|
||||||
pub ctes: Vec<Cte>,
|
pub ctes: Vec<Cte>,
|
||||||
/// SELECT or UNION / EXCEPT / INTECEPT
|
/// SELECT or UNION / EXCEPT / INTECEPT
|
||||||
pub body: SQLSetExpr,
|
pub body: SetExpr,
|
||||||
/// ORDER BY
|
/// ORDER BY
|
||||||
pub order_by: Vec<SQLOrderByExpr>,
|
pub order_by: Vec<OrderByExpr>,
|
||||||
/// `LIMIT { <N> | ALL }`
|
/// `LIMIT { <N> | ALL }`
|
||||||
pub limit: Option<Expr>,
|
pub limit: Option<Expr>,
|
||||||
/// `OFFSET <N> { ROW | ROWS }`
|
/// `OFFSET <N> { ROW | ROWS }`
|
||||||
|
@ -30,7 +30,7 @@ pub struct SQLQuery {
|
||||||
pub fetch: Option<Fetch>,
|
pub fetch: Option<Fetch>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLQuery {
|
impl ToString for Query {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
if !self.ctes.is_empty() {
|
if !self.ctes.is_empty() {
|
||||||
|
@ -57,30 +57,30 @@ impl ToString for SQLQuery {
|
||||||
/// A node in a tree, representing a "query body" expression, roughly:
|
/// A node in a tree, representing a "query body" expression, roughly:
|
||||||
/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
|
/// `SELECT ... [ {UNION|EXCEPT|INTERSECT} SELECT ...]`
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLSetExpr {
|
pub enum SetExpr {
|
||||||
/// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
|
/// Restricted SELECT .. FROM .. HAVING (no ORDER BY or set operations)
|
||||||
Select(Box<SQLSelect>),
|
Select(Box<Select>),
|
||||||
/// Parenthesized SELECT subquery, which may include more set operations
|
/// Parenthesized SELECT subquery, which may include more set operations
|
||||||
/// in its body and an optional ORDER BY / LIMIT.
|
/// in its body and an optional ORDER BY / LIMIT.
|
||||||
Query(Box<SQLQuery>),
|
Query(Box<Query>),
|
||||||
/// UNION/EXCEPT/INTERSECT of two queries
|
/// UNION/EXCEPT/INTERSECT of two queries
|
||||||
SetOperation {
|
SetOperation {
|
||||||
op: SQLSetOperator,
|
op: SetOperator,
|
||||||
all: bool,
|
all: bool,
|
||||||
left: Box<SQLSetExpr>,
|
left: Box<SetExpr>,
|
||||||
right: Box<SQLSetExpr>,
|
right: Box<SetExpr>,
|
||||||
},
|
},
|
||||||
Values(SQLValues),
|
Values(Values),
|
||||||
// TODO: ANSI SQL supports `TABLE` here.
|
// TODO: ANSI SQL supports `TABLE` here.
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLSetExpr {
|
impl ToString for SetExpr {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLSetExpr::Select(s) => s.to_string(),
|
SetExpr::Select(s) => s.to_string(),
|
||||||
SQLSetExpr::Query(q) => format!("({})", q.to_string()),
|
SetExpr::Query(q) => format!("({})", q.to_string()),
|
||||||
SQLSetExpr::Values(v) => v.to_string(),
|
SetExpr::Values(v) => v.to_string(),
|
||||||
SQLSetExpr::SetOperation {
|
SetExpr::SetOperation {
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
op,
|
op,
|
||||||
|
@ -100,18 +100,18 @@ impl ToString for SQLSetExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLSetOperator {
|
pub enum SetOperator {
|
||||||
Union,
|
Union,
|
||||||
Except,
|
Except,
|
||||||
Intersect,
|
Intersect,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLSetOperator {
|
impl ToString for SetOperator {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SQLSetOperator::Union => "UNION".to_string(),
|
SetOperator::Union => "UNION".to_string(),
|
||||||
SQLSetOperator::Except => "EXCEPT".to_string(),
|
SetOperator::Except => "EXCEPT".to_string(),
|
||||||
SQLSetOperator::Intersect => "INTERSECT".to_string(),
|
SetOperator::Intersect => "INTERSECT".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,10 +120,10 @@ impl ToString for SQLSetOperator {
|
||||||
/// appear either as the only body item of an `SQLQuery`, or as an operand
|
/// appear either as the only body item of an `SQLQuery`, or as an operand
|
||||||
/// to a set operation like `UNION`.
|
/// to a set operation like `UNION`.
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLSelect {
|
pub struct Select {
|
||||||
pub distinct: bool,
|
pub distinct: bool,
|
||||||
/// projection expressions
|
/// projection expressions
|
||||||
pub projection: Vec<SQLSelectItem>,
|
pub projection: Vec<SelectItem>,
|
||||||
/// FROM
|
/// FROM
|
||||||
pub from: Vec<TableWithJoins>,
|
pub from: Vec<TableWithJoins>,
|
||||||
/// WHERE
|
/// WHERE
|
||||||
|
@ -134,7 +134,7 @@ pub struct SQLSelect {
|
||||||
pub having: Option<Expr>,
|
pub having: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLSelect {
|
impl ToString for Select {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
let mut s = format!(
|
let mut s = format!(
|
||||||
"SELECT{} {}",
|
"SELECT{} {}",
|
||||||
|
@ -164,7 +164,7 @@ impl ToString for SQLSelect {
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct Cte {
|
pub struct Cte {
|
||||||
pub alias: TableAlias,
|
pub alias: TableAlias,
|
||||||
pub query: SQLQuery,
|
pub query: Query,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Cte {
|
impl ToString for Cte {
|
||||||
|
@ -175,26 +175,26 @@ impl ToString for Cte {
|
||||||
|
|
||||||
/// One item of the comma-separated list following `SELECT`
|
/// One item of the comma-separated list following `SELECT`
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum SQLSelectItem {
|
pub enum SelectItem {
|
||||||
/// Any expression, not followed by `[ AS ] alias`
|
/// Any expression, not followed by `[ AS ] alias`
|
||||||
UnnamedExpr(Expr),
|
UnnamedExpr(Expr),
|
||||||
/// An expression, followed by `[ AS ] alias`
|
/// An expression, followed by `[ AS ] alias`
|
||||||
ExprWithAlias { expr: Expr, alias: SQLIdent },
|
ExprWithAlias { expr: Expr, alias: Ident },
|
||||||
/// `alias.*` or even `schema.table.*`
|
/// `alias.*` or even `schema.table.*`
|
||||||
QualifiedWildcard(SQLObjectName),
|
QualifiedWildcard(ObjectName),
|
||||||
/// An unqualified `*`
|
/// An unqualified `*`
|
||||||
Wildcard,
|
Wildcard,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLSelectItem {
|
impl ToString for SelectItem {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match &self {
|
match &self {
|
||||||
SQLSelectItem::UnnamedExpr(expr) => expr.to_string(),
|
SelectItem::UnnamedExpr(expr) => expr.to_string(),
|
||||||
SQLSelectItem::ExprWithAlias { expr, alias } => {
|
SelectItem::ExprWithAlias { expr, alias } => {
|
||||||
format!("{} AS {}", expr.to_string(), alias)
|
format!("{} AS {}", expr.to_string(), alias)
|
||||||
}
|
}
|
||||||
SQLSelectItem::QualifiedWildcard(prefix) => format!("{}.*", prefix.to_string()),
|
SelectItem::QualifiedWildcard(prefix) => format!("{}.*", prefix.to_string()),
|
||||||
SQLSelectItem::Wildcard => "*".to_string(),
|
SelectItem::Wildcard => "*".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ impl ToString for TableWithJoins {
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum TableFactor {
|
pub enum TableFactor {
|
||||||
Table {
|
Table {
|
||||||
name: SQLObjectName,
|
name: ObjectName,
|
||||||
alias: Option<TableAlias>,
|
alias: Option<TableAlias>,
|
||||||
/// Arguments of a table-valued function, as supported by Postgres
|
/// Arguments of a table-valued function, as supported by Postgres
|
||||||
/// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
|
/// and MSSQL. Note that deprecated MSSQL `FROM foo (NOLOCK)` syntax
|
||||||
|
@ -230,7 +230,7 @@ pub enum TableFactor {
|
||||||
},
|
},
|
||||||
Derived {
|
Derived {
|
||||||
lateral: bool,
|
lateral: bool,
|
||||||
subquery: Box<SQLQuery>,
|
subquery: Box<Query>,
|
||||||
alias: Option<TableAlias>,
|
alias: Option<TableAlias>,
|
||||||
},
|
},
|
||||||
/// Represents a parenthesized join expression, such as
|
/// Represents a parenthesized join expression, such as
|
||||||
|
@ -285,8 +285,8 @@ impl ToString for TableFactor {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct TableAlias {
|
pub struct TableAlias {
|
||||||
pub name: SQLIdent,
|
pub name: Ident,
|
||||||
pub columns: Vec<SQLIdent>,
|
pub columns: Vec<Ident>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for TableAlias {
|
impl ToString for TableAlias {
|
||||||
|
@ -368,18 +368,18 @@ pub enum JoinOperator {
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub enum JoinConstraint {
|
pub enum JoinConstraint {
|
||||||
On(Expr),
|
On(Expr),
|
||||||
Using(Vec<SQLIdent>),
|
Using(Vec<Ident>),
|
||||||
Natural,
|
Natural,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SQL ORDER BY expression
|
/// SQL ORDER BY expression
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLOrderByExpr {
|
pub struct OrderByExpr {
|
||||||
pub expr: Expr,
|
pub expr: Expr,
|
||||||
pub asc: Option<bool>,
|
pub asc: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLOrderByExpr {
|
impl ToString for OrderByExpr {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self.asc {
|
match self.asc {
|
||||||
Some(true) => format!("{} ASC", self.expr.to_string()),
|
Some(true) => format!("{} ASC", self.expr.to_string()),
|
||||||
|
@ -414,9 +414,9 @@ impl ToString for Fetch {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||||
pub struct SQLValues(pub Vec<Vec<Expr>>);
|
pub struct Values(pub Vec<Vec<Expr>>);
|
||||||
|
|
||||||
impl ToString for SQLValues {
|
impl ToString for Values {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
let rows = self
|
let rows = self
|
||||||
.0
|
.0
|
|
@ -13,9 +13,9 @@
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnsiSqlDialect {}
|
pub struct AnsiDialect {}
|
||||||
|
|
||||||
impl Dialect for AnsiSqlDialect {
|
impl Dialect for AnsiDialect {
|
||||||
fn is_identifier_start(&self, ch: char) -> bool {
|
fn is_identifier_start(&self, ch: char) -> bool {
|
||||||
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|
||||||
}
|
}
|
|
@ -13,9 +13,9 @@
|
||||||
use crate::dialect::Dialect;
|
use crate::dialect::Dialect;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GenericSqlDialect {}
|
pub struct GenericDialect {}
|
||||||
|
|
||||||
impl Dialect for GenericSqlDialect {
|
impl Dialect for GenericDialect {
|
||||||
fn is_identifier_start(&self, ch: char) -> bool {
|
fn is_identifier_start(&self, ch: char) -> bool {
|
||||||
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || ch == '#' || ch == '@'
|
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_' || ch == '#' || ch == '@'
|
||||||
}
|
}
|
|
@ -10,16 +10,16 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
mod ansi_sql;
|
mod ansi;
|
||||||
mod generic_sql;
|
mod generic;
|
||||||
pub mod keywords;
|
pub mod keywords;
|
||||||
mod mssql;
|
mod mssql;
|
||||||
mod postgresql;
|
mod postgresql;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub use self::ansi_sql::AnsiSqlDialect;
|
pub use self::ansi::AnsiDialect;
|
||||||
pub use self::generic_sql::GenericSqlDialect;
|
pub use self::generic::GenericDialect;
|
||||||
pub use self::mssql::MsSqlDialect;
|
pub use self::mssql::MsSqlDialect;
|
||||||
pub use self::postgresql::PostgreSqlDialect;
|
pub use self::postgresql::PostgreSqlDialect;
|
||||||
|
|
||||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -18,10 +18,10 @@
|
||||||
//! Syntax Tree (AST).
|
//! Syntax Tree (AST).
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use sqlparser::dialect::GenericSqlDialect;
|
//! use sqlparser::dialect::GenericDialect;
|
||||||
//! use sqlparser::sqlparser::Parser;
|
//! use sqlparser::parser::Parser;
|
||||||
//!
|
//!
|
||||||
//! let dialect = GenericSqlDialect {}; // or AnsiSqlDialect
|
//! let dialect = GenericDialect {}; // or AnsiSqlDialect
|
||||||
//!
|
//!
|
||||||
//! let sql = "SELECT a, b, 123, myfunc(b) \
|
//! let sql = "SELECT a, b, 123, myfunc(b) \
|
||||||
//! FROM table_1 \
|
//! FROM table_1 \
|
||||||
|
@ -34,10 +34,10 @@
|
||||||
//! ```
|
//! ```
|
||||||
#![warn(clippy::all)]
|
#![warn(clippy::all)]
|
||||||
|
|
||||||
|
pub mod ast;
|
||||||
pub mod dialect;
|
pub mod dialect;
|
||||||
pub mod sqlast;
|
pub mod parser;
|
||||||
pub mod sqlparser;
|
pub mod tokenizer;
|
||||||
pub mod sqltokenizer;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
// This is required to make utilities accessible by both the crate-internal
|
// This is required to make utilities accessible by both the crate-internal
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,71 +0,0 @@
|
||||||
// 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.
|
|
||||||
|
|
||||||
/// Unary operators
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
|
||||||
pub enum SQLUnaryOperator {
|
|
||||||
Plus,
|
|
||||||
Minus,
|
|
||||||
Not,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToString for SQLUnaryOperator {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
SQLUnaryOperator::Plus => "+".to_string(),
|
|
||||||
SQLUnaryOperator::Minus => "-".to_string(),
|
|
||||||
SQLUnaryOperator::Not => "NOT".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Binary operators
|
|
||||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
|
||||||
pub enum SQLBinaryOperator {
|
|
||||||
Plus,
|
|
||||||
Minus,
|
|
||||||
Multiply,
|
|
||||||
Divide,
|
|
||||||
Modulus,
|
|
||||||
Gt,
|
|
||||||
Lt,
|
|
||||||
GtEq,
|
|
||||||
LtEq,
|
|
||||||
Eq,
|
|
||||||
NotEq,
|
|
||||||
And,
|
|
||||||
Or,
|
|
||||||
Like,
|
|
||||||
NotLike,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToString for SQLBinaryOperator {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
SQLBinaryOperator::Plus => "+".to_string(),
|
|
||||||
SQLBinaryOperator::Minus => "-".to_string(),
|
|
||||||
SQLBinaryOperator::Multiply => "*".to_string(),
|
|
||||||
SQLBinaryOperator::Divide => "/".to_string(),
|
|
||||||
SQLBinaryOperator::Modulus => "%".to_string(),
|
|
||||||
SQLBinaryOperator::Gt => ">".to_string(),
|
|
||||||
SQLBinaryOperator::Lt => "<".to_string(),
|
|
||||||
SQLBinaryOperator::GtEq => ">=".to_string(),
|
|
||||||
SQLBinaryOperator::LtEq => "<=".to_string(),
|
|
||||||
SQLBinaryOperator::Eq => "=".to_string(),
|
|
||||||
SQLBinaryOperator::NotEq => "<>".to_string(),
|
|
||||||
SQLBinaryOperator::And => "AND".to_string(),
|
|
||||||
SQLBinaryOperator::Or => "OR".to_string(),
|
|
||||||
SQLBinaryOperator::Like => "LIKE".to_string(),
|
|
||||||
SQLBinaryOperator::NotLike => "NOT LIKE".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,10 +12,10 @@
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use super::ast::*;
|
||||||
use super::dialect::*;
|
use super::dialect::*;
|
||||||
use super::sqlast::*;
|
use super::parser::{Parser, ParserError};
|
||||||
use super::sqlparser::{Parser, ParserError};
|
use super::tokenizer::Tokenizer;
|
||||||
use super::sqltokenizer::Tokenizer;
|
|
||||||
|
|
||||||
/// Tests use the methods on this struct to invoke the parser on one or
|
/// Tests use the methods on this struct to invoke the parser on one or
|
||||||
/// multiple dialects.
|
/// multiple dialects.
|
||||||
|
@ -57,7 +57,7 @@ impl TestedDialects {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_sql_statements(&self, sql: &str) -> Result<Vec<SQLStatement>, ParserError> {
|
pub fn parse_sql_statements(&self, sql: &str) -> Result<Vec<Statement>, ParserError> {
|
||||||
self.one_of_identical_results(|dialect| Parser::parse_sql(dialect, sql.to_string()))
|
self.one_of_identical_results(|dialect| Parser::parse_sql(dialect, sql.to_string()))
|
||||||
// To fail the `ensure_multiple_dialects_are_tested` test:
|
// To fail the `ensure_multiple_dialects_are_tested` test:
|
||||||
// Parser::parse_sql(&**self.dialects.first().unwrap(), sql.to_string())
|
// Parser::parse_sql(&**self.dialects.first().unwrap(), sql.to_string())
|
||||||
|
@ -66,7 +66,7 @@ impl TestedDialects {
|
||||||
/// Ensures that `sql` parses as a single statement, optionally checking
|
/// Ensures that `sql` parses as a single statement, optionally checking
|
||||||
/// that converting AST back to string equals to `canonical` (unless an
|
/// that converting AST back to string equals to `canonical` (unless an
|
||||||
/// empty canonical string is provided).
|
/// empty canonical string is provided).
|
||||||
pub fn one_statement_parses_to(&self, sql: &str, canonical: &str) -> SQLStatement {
|
pub fn one_statement_parses_to(&self, sql: &str, canonical: &str) -> Statement {
|
||||||
let mut statements = self.parse_sql_statements(&sql).unwrap();
|
let mut statements = self.parse_sql_statements(&sql).unwrap();
|
||||||
assert_eq!(statements.len(), 1);
|
assert_eq!(statements.len(), 1);
|
||||||
|
|
||||||
|
@ -79,24 +79,24 @@ impl TestedDialects {
|
||||||
|
|
||||||
/// Ensures that `sql` parses as a single SQLStatement, and is not modified
|
/// Ensures that `sql` parses as a single SQLStatement, and is not modified
|
||||||
/// after a serialization round-trip.
|
/// after a serialization round-trip.
|
||||||
pub fn verified_stmt(&self, query: &str) -> SQLStatement {
|
pub fn verified_stmt(&self, query: &str) -> Statement {
|
||||||
self.one_statement_parses_to(query, query)
|
self.one_statement_parses_to(query, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that `sql` parses as a single SQLQuery, and is not modified
|
/// Ensures that `sql` parses as a single SQLQuery, and is not modified
|
||||||
/// after a serialization round-trip.
|
/// after a serialization round-trip.
|
||||||
pub fn verified_query(&self, sql: &str) -> SQLQuery {
|
pub fn verified_query(&self, sql: &str) -> Query {
|
||||||
match self.verified_stmt(sql) {
|
match self.verified_stmt(sql) {
|
||||||
SQLStatement::SQLQuery(query) => *query,
|
Statement::Query(query) => *query,
|
||||||
_ => panic!("Expected SQLQuery"),
|
_ => panic!("Expected SQLQuery"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensures that `sql` parses as a single SQLSelect, and is not modified
|
/// Ensures that `sql` parses as a single SQLSelect, and is not modified
|
||||||
/// after a serialization round-trip.
|
/// after a serialization round-trip.
|
||||||
pub fn verified_only_select(&self, query: &str) -> SQLSelect {
|
pub fn verified_only_select(&self, query: &str) -> Select {
|
||||||
match self.verified_query(query).body {
|
match self.verified_query(query).body {
|
||||||
SQLSetExpr::Select(s) => *s,
|
SetExpr::Select(s) => *s,
|
||||||
_ => panic!("Expected SQLSetExpr::Select"),
|
_ => panic!("Expected SQLSetExpr::Select"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,10 +113,10 @@ impl TestedDialects {
|
||||||
pub fn all_dialects() -> TestedDialects {
|
pub fn all_dialects() -> TestedDialects {
|
||||||
TestedDialects {
|
TestedDialects {
|
||||||
dialects: vec![
|
dialects: vec![
|
||||||
Box::new(GenericSqlDialect {}),
|
Box::new(GenericDialect {}),
|
||||||
Box::new(PostgreSqlDialect {}),
|
Box::new(PostgreSqlDialect {}),
|
||||||
Box::new(MsSqlDialect {}),
|
Box::new(MsSqlDialect {}),
|
||||||
Box::new(AnsiSqlDialect {}),
|
Box::new(AnsiDialect {}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,9 +130,9 @@ pub fn only<T>(v: impl IntoIterator<Item = T>) -> T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_from_projection(item: &SQLSelectItem) -> &Expr {
|
pub fn expr_from_projection(item: &SelectItem) -> &Expr {
|
||||||
match item {
|
match item {
|
||||||
SQLSelectItem::UnnamedExpr(expr) => expr,
|
SelectItem::UnnamedExpr(expr) => expr,
|
||||||
_ => panic!("Expected UnnamedExpr"),
|
_ => panic!("Expected UnnamedExpr"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use super::dialect::Dialect;
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
/// A keyword (like SELECT) or an optionally quoted SQL identifier
|
/// A keyword (like SELECT) or an optionally quoted SQL identifier
|
||||||
SQLWord(SQLWord),
|
Word(Word),
|
||||||
/// An unsigned numeric literal
|
/// An unsigned numeric literal
|
||||||
Number(String),
|
Number(String),
|
||||||
/// A character that could not be tokenized
|
/// A character that could not be tokenized
|
||||||
|
@ -92,7 +92,7 @@ pub enum Token {
|
||||||
impl ToString for Token {
|
impl ToString for Token {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Token::SQLWord(ref w) => w.to_string(),
|
Token::Word(ref w) => w.to_string(),
|
||||||
Token::Number(ref n) => n.to_string(),
|
Token::Number(ref n) => n.to_string(),
|
||||||
Token::Char(ref c) => c.to_string(),
|
Token::Char(ref c) => c.to_string(),
|
||||||
Token::SingleQuotedString(ref s) => format!("'{}'", s),
|
Token::SingleQuotedString(ref s) => format!("'{}'", s),
|
||||||
|
@ -137,7 +137,7 @@ impl Token {
|
||||||
// not fast but I want the simplicity for now while I experiment with pluggable
|
// not fast but I want the simplicity for now while I experiment with pluggable
|
||||||
// dialects
|
// dialects
|
||||||
let is_keyword = quote_style == None && ALL_KEYWORDS.contains(&word_uppercase.as_str());
|
let is_keyword = quote_style == None && ALL_KEYWORDS.contains(&word_uppercase.as_str());
|
||||||
Token::SQLWord(SQLWord {
|
Token::Word(Word {
|
||||||
value: word.to_string(),
|
value: word.to_string(),
|
||||||
quote_style,
|
quote_style,
|
||||||
keyword: if is_keyword {
|
keyword: if is_keyword {
|
||||||
|
@ -151,7 +151,7 @@ impl Token {
|
||||||
|
|
||||||
/// A keyword (like SELECT) or an optionally quoted SQL identifier
|
/// A keyword (like SELECT) or an optionally quoted SQL identifier
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct SQLWord {
|
pub struct Word {
|
||||||
/// The value of the token, without the enclosing quotes, and with the
|
/// The value of the token, without the enclosing quotes, and with the
|
||||||
/// escape sequences (if any) processed (TODO: escapes are not handled)
|
/// escape sequences (if any) processed (TODO: escapes are not handled)
|
||||||
pub value: String,
|
pub value: String,
|
||||||
|
@ -164,18 +164,18 @@ pub struct SQLWord {
|
||||||
pub keyword: String,
|
pub keyword: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for SQLWord {
|
impl ToString for Word {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self.quote_style {
|
match self.quote_style {
|
||||||
Some(s) if s == '"' || s == '[' || s == '`' => {
|
Some(s) if s == '"' || s == '[' || s == '`' => {
|
||||||
format!("{}{}{}", s, self.value, SQLWord::matching_end_quote(s))
|
format!("{}{}{}", s, self.value, Word::matching_end_quote(s))
|
||||||
}
|
}
|
||||||
None => self.value.clone(),
|
None => self.value.clone(),
|
||||||
_ => panic!("Unexpected quote_style!"),
|
_ => panic!("Unexpected quote_style!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl SQLWord {
|
impl Word {
|
||||||
fn matching_end_quote(ch: char) -> char {
|
fn matching_end_quote(ch: char) -> char {
|
||||||
match ch {
|
match ch {
|
||||||
'"' => '"', // ANSI and most dialects
|
'"' => '"', // ANSI and most dialects
|
||||||
|
@ -244,8 +244,8 @@ impl<'a> Tokenizer<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Whitespace(Whitespace::Tab) => self.col += 4,
|
Token::Whitespace(Whitespace::Tab) => self.col += 4,
|
||||||
Token::SQLWord(w) if w.quote_style == None => self.col += w.value.len() as u64,
|
Token::Word(w) if w.quote_style == None => self.col += w.value.len() as u64,
|
||||||
Token::SQLWord(w) if w.quote_style != None => self.col += w.value.len() as u64 + 2,
|
Token::Word(w) if w.quote_style != None => self.col += w.value.len() as u64 + 2,
|
||||||
Token::Number(s) => self.col += s.len() as u64,
|
Token::Number(s) => self.col += s.len() as u64,
|
||||||
Token::SingleQuotedString(s) => self.col += s.len() as u64,
|
Token::SingleQuotedString(s) => self.col += s.len() as u64,
|
||||||
_ => self.col += 1,
|
_ => self.col += 1,
|
||||||
|
@ -318,7 +318,7 @@ impl<'a> Tokenizer<'a> {
|
||||||
// delimited (quoted) identifier
|
// delimited (quoted) identifier
|
||||||
quote_start if self.dialect.is_delimited_identifier_start(quote_start) => {
|
quote_start if self.dialect.is_delimited_identifier_start(quote_start) => {
|
||||||
chars.next(); // consume the opening quote
|
chars.next(); // consume the opening quote
|
||||||
let quote_end = SQLWord::matching_end_quote(quote_start);
|
let quote_end = Word::matching_end_quote(quote_start);
|
||||||
let s = peeking_take_while(chars, |ch| ch != quote_end);
|
let s = peeking_take_while(chars, |ch| ch != quote_end);
|
||||||
if chars.next() == Some(quote_end) {
|
if chars.next() == Some(quote_end) {
|
||||||
Ok(Some(Token::make_word(&s, Some(quote_start))))
|
Ok(Some(Token::make_word(&s, Some(quote_start))))
|
||||||
|
@ -520,13 +520,13 @@ fn peeking_take_while(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::super::dialect::GenericSqlDialect;
|
use super::super::dialect::GenericDialect;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tokenize_select_1() {
|
fn tokenize_select_1() {
|
||||||
let sql = String::from("SELECT 1");
|
let sql = String::from("SELECT 1");
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
|
|
||||||
|
@ -542,7 +542,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokenize_scalar_function() {
|
fn tokenize_scalar_function() {
|
||||||
let sql = String::from("SELECT sqrt(1)");
|
let sql = String::from("SELECT sqrt(1)");
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
|
|
||||||
|
@ -561,7 +561,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokenize_simple_select() {
|
fn tokenize_simple_select() {
|
||||||
let sql = String::from("SELECT * FROM customer WHERE id = 1 LIMIT 5");
|
let sql = String::from("SELECT * FROM customer WHERE id = 1 LIMIT 5");
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokenize_string_predicate() {
|
fn tokenize_string_predicate() {
|
||||||
let sql = String::from("SELECT * FROM customer WHERE salary != 'Not Provided'");
|
let sql = String::from("SELECT * FROM customer WHERE salary != 'Not Provided'");
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
|
|
||||||
|
@ -622,7 +622,7 @@ mod tests {
|
||||||
fn tokenize_invalid_string() {
|
fn tokenize_invalid_string() {
|
||||||
let sql = String::from("\nمصطفىh");
|
let sql = String::from("\nمصطفىh");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
println!("tokens: {:#?}", tokens);
|
println!("tokens: {:#?}", tokens);
|
||||||
|
@ -642,7 +642,7 @@ mod tests {
|
||||||
fn tokenize_invalid_string_cols() {
|
fn tokenize_invalid_string_cols() {
|
||||||
let sql = String::from("\n\nSELECT * FROM table\tمصطفىh");
|
let sql = String::from("\n\nSELECT * FROM table\tمصطفىh");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
println!("tokens: {:#?}", tokens);
|
println!("tokens: {:#?}", tokens);
|
||||||
|
@ -670,7 +670,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tokenize_is_null() {
|
fn tokenize_is_null() {
|
||||||
let sql = String::from("a IS NULL");
|
let sql = String::from("a IS NULL");
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ mod tests {
|
||||||
fn tokenize_comment() {
|
fn tokenize_comment() {
|
||||||
let sql = String::from("0--this is a comment\n1");
|
let sql = String::from("0--this is a comment\n1");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
|
@ -706,7 +706,7 @@ mod tests {
|
||||||
fn tokenize_comment_at_eof() {
|
fn tokenize_comment_at_eof() {
|
||||||
let sql = String::from("--this is a comment");
|
let sql = String::from("--this is a comment");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
let expected = vec![Token::Whitespace(Whitespace::SingleLineComment(
|
let expected = vec![Token::Whitespace(Whitespace::SingleLineComment(
|
||||||
|
@ -719,7 +719,7 @@ mod tests {
|
||||||
fn tokenize_multiline_comment() {
|
fn tokenize_multiline_comment() {
|
||||||
let sql = String::from("0/*multi-line\n* /comment*/1");
|
let sql = String::from("0/*multi-line\n* /comment*/1");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
|
@ -736,7 +736,7 @@ mod tests {
|
||||||
fn tokenize_multiline_comment_with_even_asterisks() {
|
fn tokenize_multiline_comment_with_even_asterisks() {
|
||||||
let sql = String::from("\n/** Comment **/\n");
|
let sql = String::from("\n/** Comment **/\n");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
|
@ -751,7 +751,7 @@ mod tests {
|
||||||
fn tokenize_mismatched_quotes() {
|
fn tokenize_mismatched_quotes() {
|
||||||
let sql = String::from("\"foo");
|
let sql = String::from("\"foo");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tokenizer.tokenize(),
|
tokenizer.tokenize(),
|
||||||
|
@ -765,7 +765,7 @@ mod tests {
|
||||||
fn tokenize_newlines() {
|
fn tokenize_newlines() {
|
||||||
let sql = String::from("line1\nline2\rline3\r\nline4\r");
|
let sql = String::from("line1\nline2\rline3\r\nline4\r");
|
||||||
|
|
||||||
let dialect = GenericSqlDialect {};
|
let dialect = GenericDialect {};
|
||||||
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
let mut tokenizer = Tokenizer::new(&dialect, &sql);
|
||||||
let tokens = tokenizer.tokenize().unwrap();
|
let tokens = tokenizer.tokenize().unwrap();
|
||||||
let expected = vec![
|
let expected = vec![
|
File diff suppressed because it is too large
Load diff
|
@ -14,8 +14,8 @@
|
||||||
//! Test SQL syntax specific to Microsoft's T-SQL. The parser based on the
|
//! Test SQL syntax specific to Microsoft's T-SQL. The parser based on the
|
||||||
//! generic dialect is also tested (on the inputs it can handle).
|
//! generic dialect is also tested (on the inputs it can handle).
|
||||||
|
|
||||||
use sqlparser::dialect::{GenericSqlDialect, MsSqlDialect};
|
use sqlparser::ast::*;
|
||||||
use sqlparser::sqlast::*;
|
use sqlparser::dialect::{GenericDialect, MsSqlDialect};
|
||||||
use sqlparser::test_utils::*;
|
use sqlparser::test_utils::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -23,11 +23,11 @@ fn parse_mssql_identifiers() {
|
||||||
let sql = "SELECT @@version, _foo$123 FROM ##temp";
|
let sql = "SELECT @@version, _foo$123 FROM ##temp";
|
||||||
let select = ms_and_generic().verified_only_select(sql);
|
let select = ms_and_generic().verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::SQLIdentifier("@@version".to_string()),
|
&Expr::Identifier("@@version".to_string()),
|
||||||
expr_from_projection(&select.projection[0]),
|
expr_from_projection(&select.projection[0]),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&Expr::SQLIdentifier("_foo$123".to_string()),
|
&Expr::Identifier("_foo$123".to_string()),
|
||||||
expr_from_projection(&select.projection[1]),
|
expr_from_projection(&select.projection[1]),
|
||||||
);
|
);
|
||||||
assert_eq!(2, select.projection.len());
|
assert_eq!(2, select.projection.len());
|
||||||
|
@ -75,6 +75,6 @@ fn ms() -> TestedDialects {
|
||||||
}
|
}
|
||||||
fn ms_and_generic() -> TestedDialects {
|
fn ms_and_generic() -> TestedDialects {
|
||||||
TestedDialects {
|
TestedDialects {
|
||||||
dialects: vec![Box::new(MsSqlDialect {}), Box::new(GenericSqlDialect {})],
|
dialects: vec![Box::new(MsSqlDialect {}), Box::new(GenericDialect {})],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
//! Test SQL syntax specific to PostgreSQL. The parser based on the
|
//! Test SQL syntax specific to PostgreSQL. The parser based on the
|
||||||
//! generic dialect is also tested (on the inputs it can handle).
|
//! generic dialect is also tested (on the inputs it can handle).
|
||||||
|
|
||||||
use sqlparser::dialect::{GenericSqlDialect, PostgreSqlDialect};
|
use sqlparser::ast::*;
|
||||||
use sqlparser::sqlast::*;
|
use sqlparser::dialect::{GenericDialect, PostgreSqlDialect};
|
||||||
use sqlparser::test_utils::*;
|
use sqlparser::test_utils::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -33,7 +33,7 @@ fn parse_create_table_with_defaults() {
|
||||||
active integer NOT NULL
|
active integer NOT NULL
|
||||||
) WITH (fillfactor = 20, user_catalog_table = true, autovacuum_vacuum_threshold = 100)";
|
) WITH (fillfactor = 20, user_catalog_table = true, autovacuum_vacuum_threshold = 100)";
|
||||||
match pg_and_generic().one_statement_parses_to(sql, "") {
|
match pg_and_generic().one_statement_parses_to(sql, "") {
|
||||||
SQLStatement::SQLCreateTable {
|
Statement::CreateTable {
|
||||||
name,
|
name,
|
||||||
columns,
|
columns,
|
||||||
constraints,
|
constraints,
|
||||||
|
@ -46,9 +46,9 @@ fn parse_create_table_with_defaults() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
columns,
|
columns,
|
||||||
vec![
|
vec![
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "customer_id".into(),
|
name: "customer_id".into(),
|
||||||
data_type: SQLType::Int,
|
data_type: DataType::Int,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![ColumnOptionDef {
|
options: vec![ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
|
@ -57,56 +57,56 @@ fn parse_create_table_with_defaults() {
|
||||||
)
|
)
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "store_id".into(),
|
name: "store_id".into(),
|
||||||
data_type: SQLType::SmallInt,
|
data_type: DataType::SmallInt,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![ColumnOptionDef {
|
options: vec![ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
option: ColumnOption::NotNull,
|
option: ColumnOption::NotNull,
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "first_name".into(),
|
name: "first_name".into(),
|
||||||
data_type: SQLType::Varchar(Some(45)),
|
data_type: DataType::Varchar(Some(45)),
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![ColumnOptionDef {
|
options: vec![ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
option: ColumnOption::NotNull,
|
option: ColumnOption::NotNull,
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "last_name".into(),
|
name: "last_name".into(),
|
||||||
data_type: SQLType::Varchar(Some(45)),
|
data_type: DataType::Varchar(Some(45)),
|
||||||
collation: Some(SQLObjectName(vec!["\"es_ES\"".into()])),
|
collation: Some(ObjectName(vec!["\"es_ES\"".into()])),
|
||||||
options: vec![ColumnOptionDef {
|
options: vec![ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
option: ColumnOption::NotNull,
|
option: ColumnOption::NotNull,
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "email".into(),
|
name: "email".into(),
|
||||||
data_type: SQLType::Varchar(Some(50)),
|
data_type: DataType::Varchar(Some(50)),
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![],
|
options: vec![],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "address_id".into(),
|
name: "address_id".into(),
|
||||||
data_type: SQLType::SmallInt,
|
data_type: DataType::SmallInt,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![ColumnOptionDef {
|
options: vec![ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
option: ColumnOption::NotNull
|
option: ColumnOption::NotNull
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "activebool".into(),
|
name: "activebool".into(),
|
||||||
data_type: SQLType::Boolean,
|
data_type: DataType::Boolean,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![
|
options: vec![
|
||||||
ColumnOptionDef {
|
ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
option: ColumnOption::Default(Expr::SQLValue(Value::Boolean(true))),
|
option: ColumnOption::Default(Expr::Value(Value::Boolean(true))),
|
||||||
},
|
},
|
||||||
ColumnOptionDef {
|
ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
|
@ -114,9 +114,9 @@ fn parse_create_table_with_defaults() {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "create_date".into(),
|
name: "create_date".into(),
|
||||||
data_type: SQLType::Date,
|
data_type: DataType::Date,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![
|
options: vec![
|
||||||
ColumnOptionDef {
|
ColumnOptionDef {
|
||||||
|
@ -131,9 +131,9 @@ fn parse_create_table_with_defaults() {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "last_update".into(),
|
name: "last_update".into(),
|
||||||
data_type: SQLType::Timestamp,
|
data_type: DataType::Timestamp,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![
|
options: vec![
|
||||||
ColumnOptionDef {
|
ColumnOptionDef {
|
||||||
|
@ -146,9 +146,9 @@ fn parse_create_table_with_defaults() {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
SQLColumnDef {
|
ColumnDef {
|
||||||
name: "active".into(),
|
name: "active".into(),
|
||||||
data_type: SQLType::Int,
|
data_type: DataType::Int,
|
||||||
collation: None,
|
collation: None,
|
||||||
options: vec![ColumnOptionDef {
|
options: vec![ColumnOptionDef {
|
||||||
name: None,
|
name: None,
|
||||||
|
@ -161,15 +161,15 @@ fn parse_create_table_with_defaults() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
with_options,
|
with_options,
|
||||||
vec![
|
vec![
|
||||||
SQLOption {
|
SqlOption {
|
||||||
name: "fillfactor".into(),
|
name: "fillfactor".into(),
|
||||||
value: Value::Long(20)
|
value: Value::Long(20)
|
||||||
},
|
},
|
||||||
SQLOption {
|
SqlOption {
|
||||||
name: "user_catalog_table".into(),
|
name: "user_catalog_table".into(),
|
||||||
value: Value::Boolean(true)
|
value: Value::Boolean(true)
|
||||||
},
|
},
|
||||||
SQLOption {
|
SqlOption {
|
||||||
name: "autovacuum_vacuum_threshold".into(),
|
name: "autovacuum_vacuum_threshold".into(),
|
||||||
value: Value::Long(100)
|
value: Value::Long(100)
|
||||||
},
|
},
|
||||||
|
@ -259,9 +259,6 @@ fn pg() -> TestedDialects {
|
||||||
|
|
||||||
fn pg_and_generic() -> TestedDialects {
|
fn pg_and_generic() -> TestedDialects {
|
||||||
TestedDialects {
|
TestedDialects {
|
||||||
dialects: vec![
|
dialects: vec![Box::new(PostgreSqlDialect {}), Box::new(GenericDialect {})],
|
||||||
Box::new(PostgreSqlDialect {}),
|
|
||||||
Box::new(GenericSqlDialect {}),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue