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;
pub type CreateTableRef = u32;
pub type CreateViewRef = u32;
pub type DropTableRef = u32;
pub type InsertRef = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Statement {
Query(QueryRef),
CreateTable(CreateTableRef),
CreateView(CreateViewRef),
DropTable(DropTableRef),
Insert(InsertRef),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CreateTable {
pub name: Slice,
pub columns: Slice,
pub query: QueryRef,
pub if_not_exists: bool,
pub or_replace: bool,
pub temporary: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ColumnDef {
pub name: StrRef,
pub ty: StrRef,
pub not_null: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CreateView {
pub name: Slice,
pub columns: Slice,
pub query: QueryRef,
pub sql: StrRef,
pub if_not_exists: bool,
pub or_replace: bool,
pub temporary: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DropTable {
pub names: Slice,
pub if_exists: bool,
pub view: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Insert {
pub name: Slice,
pub columns: Slice,
pub source: 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,
},
Values(Slice),
}
#[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,
},
Function {
name: Slice,
args: Slice,
alias: StrRef,
columns: Slice,
},
Values {
rows: Slice,
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,
replacements: 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,
},
Parameter {
name: StrRef,
},
List {
items: Slice,
},
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>,
pub create_tables: Vec<CreateTable>,
pub create_views: Vec<CreateView>,
pub drop_tables: Vec<DropTable>,
pub inserts: Vec<Insert>,
pub column_defs: Vec<ColumnDef>,
pub name_lists: Vec<Slice>,
pub rows: Vec<Slice>,
}
impl Ast {
pub fn string(&self, index: StrRef) -> &str {
if index == NONE { "" } else { &self.strings[index as usize] }
}
pub fn parameters(&self) -> Vec<&str> {
let mut found: Vec<&str> = Vec::new();
for expr in &self.exprs {
if let Expr::Parameter { name } = *expr {
let name = self.string(name);
if !found.contains(&name) {
found.push(name);
}
}
}
found
}
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 create_table(&self, index: CreateTableRef) -> CreateTable {
self.create_tables[index as usize]
}
pub fn create_view(&self, index: CreateViewRef) -> CreateView {
self.create_views[index as usize]
}
pub fn drop_table(&self, index: DropTableRef) -> DropTable {
self.drop_tables[index as usize]
}
pub fn insert(&self, index: InsertRef) -> Insert {
self.inserts[index as usize]
}
pub fn column_defs(&self, slice: Slice) -> &[ColumnDef] {
&self.column_defs[slice.range()]
}
pub fn name_list(&self, slice: Slice) -> &[Slice] {
&self.name_lists[slice.range()]
}
pub fn rows(&self, slice: Slice) -> &[Slice] {
&self.rows[slice.range()]
}
pub fn node_count(&self) -> usize {
self.queries.len() + self.selects.len() + self.exprs.len() + self.sources.len()
}
}