use crate::matcher::NONE;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Slice {
pub start: u32,
pub len: u32,
}
impl Slice {
pub const fn is_empty(self) -> bool {
self.len == 0
}
pub const fn range(self) -> std::ops::Range<usize> {
self.start as usize..(self.start + self.len) as usize
}
}
pub type StrRef = u32;
pub type ExprRef = u32;
pub type SourceRef = u32;
pub type QueryRef = u32;
pub type SelectRef = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Statement {
Query(QueryRef),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Query {
pub body: QueryBody,
pub order_by: Slice,
pub order_by_all: bool,
pub limit: ExprRef,
pub limit_percent: bool,
pub offset: ExprRef,
}
impl Query {
pub const fn bare(body: QueryBody) -> Self {
Self {
body,
order_by: Slice { start: 0, len: 0 },
order_by_all: false,
limit: NONE,
limit_percent: false,
offset: NONE,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueryBody {
Select(SelectRef),
SetOp {
op: SetOp,
quantifier: Quantifier,
by_name: bool,
left: QueryRef,
right: QueryRef,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SetOp {
Union,
Except,
Intersect,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Quantifier {
Unstated,
All,
Distinct,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Distinct {
No,
Yes,
On(Slice),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Select {
pub distinct: Distinct,
pub targets: Slice,
pub from: Slice,
pub filter: ExprRef,
pub group_by: Slice,
pub group_by_all: bool,
pub having: ExprRef,
}
impl Select {
pub const fn empty() -> Self {
Self {
distinct: Distinct::No,
targets: Slice { start: 0, len: 0 },
from: Slice { start: 0, len: 0 },
filter: NONE,
group_by: Slice { start: 0, len: 0 },
group_by_all: false,
having: NONE,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Target {
pub expr: ExprRef,
pub alias: StrRef,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrderItem {
pub expr: ExprRef,
pub order: Order,
pub nulls: Nulls,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Order {
Unstated,
Ascending,
Descending,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Nulls {
Unstated,
First,
Last,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Source {
Table {
name: Slice,
alias: StrRef,
columns: Slice,
},
Subquery {
query: QueryRef,
alias: StrRef,
columns: Slice,
},
Join {
left: SourceRef,
right: SourceRef,
kind: JoinKind,
natural: bool,
on: ExprRef,
using: Slice,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum JoinKind {
Inner,
Left,
Right,
Full,
Semi,
Anti,
Cross,
Positional,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Expr {
Star {
qualifier: Slice,
},
Column {
name: Slice,
},
Literal {
kind: LiteralKind,
text: StrRef,
},
Unary {
op: UnaryOp,
operand: ExprRef,
},
Binary {
op: BinaryOp,
left: ExprRef,
right: ExprRef,
},
Function {
name: Slice,
args: Slice,
distinct: bool,
},
Cast {
operand: ExprRef,
ty: StrRef,
try_cast: bool,
},
Case {
operand: ExprRef,
arms: Slice,
otherwise: ExprRef,
},
Between {
operand: ExprRef,
low: ExprRef,
high: ExprRef,
negated: bool,
},
In {
operand: ExprRef,
list: Slice,
negated: bool,
},
Row {
items: Slice,
},
Subquery {
query: QueryRef,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CaseArm {
pub when: ExprRef,
pub then: ExprRef,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LiteralKind {
Number,
String,
Null,
True,
False,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Not,
Negate,
Plus,
BitNot,
Factorial,
IsNull,
IsNotNull,
IsTrue,
IsNotTrue,
IsFalse,
IsNotFalse,
IsUnknown,
IsNotUnknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Or,
And,
Eq,
NotEq,
Lt,
Gt,
LtEq,
GtEq,
IsDistinctFrom,
IsNotDistinctFrom,
Add,
Subtract,
Multiply,
Divide,
IntegerDivide,
Modulo,
Power,
BitAnd,
BitOr,
ShiftLeft,
ShiftRight,
Concat,
Like,
NotLike,
ILike,
NotILike,
Glob,
SimilarTo,
NotSimilarTo,
Regex,
RegexInsensitive,
NotRegexInsensitive,
Collate,
AtTimeZone,
Arrow,
LongArrow,
Contains,
ContainedBy,
Overlaps,
StartsWith,
InetContainedByOrEq,
InetContainsOrEq,
Named(StrRef),
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Ast {
pub statements: Vec<Statement>,
pub queries: Vec<Query>,
pub selects: Vec<Select>,
pub exprs: Vec<Expr>,
pub sources: Vec<Source>,
pub strings: Vec<String>,
pub parts: Vec<StrRef>,
pub expr_lists: Vec<ExprRef>,
pub source_lists: Vec<SourceRef>,
pub targets: Vec<Target>,
pub order_items: Vec<OrderItem>,
pub case_arms: Vec<CaseArm>,
}
impl Ast {
pub fn string(&self, index: StrRef) -> &str {
if index == NONE { "" } else { &self.strings[index as usize] }
}
pub fn name(&self, slice: Slice) -> impl Iterator<Item = &str> {
self.parts[slice.range()].iter().map(|&part| self.string(part))
}
pub fn name_text(&self, slice: Slice) -> String {
self.name(slice).collect::<Vec<_>>().join(".")
}
pub fn expr(&self, index: ExprRef) -> Expr {
self.exprs[index as usize]
}
pub fn source(&self, index: SourceRef) -> Source {
self.sources[index as usize]
}
pub fn query(&self, index: QueryRef) -> Query {
self.queries[index as usize]
}
pub fn select(&self, index: SelectRef) -> Select {
self.selects[index as usize]
}
pub fn expr_list(&self, slice: Slice) -> &[ExprRef] {
&self.expr_lists[slice.range()]
}
pub fn source_list(&self, slice: Slice) -> &[SourceRef] {
&self.source_lists[slice.range()]
}
pub fn target_list(&self, slice: Slice) -> &[Target] {
&self.targets[slice.range()]
}
pub fn order_list(&self, slice: Slice) -> &[OrderItem] {
&self.order_items[slice.range()]
}
pub fn arm_list(&self, slice: Slice) -> &[CaseArm] {
&self.case_arms[slice.range()]
}
pub fn node_count(&self) -> usize {
self.queries.len() + self.selects.len() + self.exprs.len() + self.sources.len()
}
}