merge main

This commit is contained in:
TcMits
2025-08-27 13:36:54 +07:00
115 changed files with 5078 additions and 3202 deletions

View File

@@ -3,6 +3,8 @@ pub mod fmt;
use strum_macros::{EnumIter, EnumString};
use crate::ast::fmt::ToTokens;
/// `?` or `$` Prepared statement arg placeholder(s)
#[derive(Default)]
pub struct ParameterInfo {
@@ -345,6 +347,9 @@ pub enum Expr {
},
/// binary expression
Binary(Box<Expr>, Operator, Box<Expr>),
/// Register reference for DBSP expression compilation
/// This is not part of SQL syntax but used internally for incremental computation
Register(usize),
/// `CASE` expression
Case {
/// operand
@@ -471,6 +476,76 @@ pub enum Expr {
Variable(String),
}
impl Expr {
pub fn into_boxed(self) -> Box<Expr> {
Box::new(self)
}
pub fn unary(operator: UnaryOperator, expr: Expr) -> Expr {
Expr::Unary(operator, Box::new(expr))
}
pub fn binary(lhs: Expr, operator: Operator, rhs: Expr) -> Expr {
Expr::Binary(Box::new(lhs), operator, Box::new(rhs))
}
pub fn not_null(expr: Expr) -> Expr {
Expr::NotNull(Box::new(expr))
}
pub fn between(lhs: Expr, not: bool, start: Expr, end: Expr) -> Expr {
Expr::Between {
lhs: Box::new(lhs),
not,
start: Box::new(start),
end: Box::new(end),
}
}
pub fn in_select(lhs: Expr, not: bool, select: Select) -> Expr {
Expr::InSelect {
lhs: Box::new(lhs),
not,
rhs: select,
}
}
pub fn like(
lhs: Expr,
not: bool,
operator: LikeOperator,
rhs: Expr,
escape: Option<Expr>,
) -> Expr {
Expr::Like {
lhs: Box::new(lhs),
not,
op: operator,
rhs: Box::new(rhs),
escape: escape.map(Box::new),
}
}
pub fn is_null(expr: Expr) -> Expr {
Expr::IsNull(Box::new(expr))
}
pub fn collate(expr: Expr, name: Name) -> Expr {
Expr::Collate(Box::new(expr), name)
}
pub fn cast(expr: Expr, type_name: Option<Type>) -> Expr {
Expr::Cast {
expr: Box::new(expr),
type_name,
}
}
pub fn raise(resolve_type: ResolveType, expr: Option<Expr>) -> Expr {
Expr::Raise(resolve_type, expr.map(Box::new))
}
}
/// SQL literal
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -856,6 +931,41 @@ pub struct QualifiedName {
pub alias: Option<Name>, // FIXME restrict alias usage (fullname vs xfullname)
}
impl QualifiedName {
/// Constructor
pub fn single(name: Name) -> Self {
Self {
db_name: None,
name,
alias: None,
}
}
/// Constructor
pub fn fullname(db_name: Name, name: Name) -> Self {
Self {
db_name: Some(db_name),
name,
alias: None,
}
}
/// Constructor
pub fn xfullname(db_name: Name, name: Name, alias: Name) -> Self {
Self {
db_name: Some(db_name),
name,
alias: Some(alias),
}
}
/// Constructor
pub fn alias(name: Name, alias: Name) -> Self {
Self {
db_name: None,
name,
alias: Some(alias),
}
}
}
/// `ALTER TABLE` body
// https://sqlite.org/lang_altertable.html
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -1027,7 +1137,7 @@ bitflags::bitflags! {
}
/// Sort orders
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SortOrder {
/// `ASC`
@@ -1036,6 +1146,12 @@ pub enum SortOrder {
Desc,
}
impl core::fmt::Display for SortOrder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_fmt(f)
}
}
/// `NULLS FIRST` or `NULLS LAST`
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
@@ -1204,6 +1320,10 @@ pub enum PragmaName {
AutoVacuum,
/// `cache_size` pragma
CacheSize,
/// encryption cipher algorithm name for encrypted databases
#[strum(serialize = "cipher")]
#[cfg_attr(feature = "serde", serde(rename = "cipher"))]
EncryptionCipher,
/// List databases
DatabaseList,
/// Encoding - only support utf8
@@ -1214,10 +1334,9 @@ pub enum PragmaName {
IntegrityCheck,
/// `journal_mode` pragma
JournalMode,
/// encryption key for encrypted databases. This is just called `key` because most
/// extensions use this name instead of `encryption_key`.
#[strum(serialize = "key")]
#[cfg_attr(feature = "serde", serde(rename = "key"))]
/// encryption key for encrypted databases, specified as hexadecimal string.
#[strum(serialize = "hexkey")]
#[cfg_attr(feature = "serde", serde(rename = "hexkey"))]
EncryptionKey,
/// Noop as per SQLite docs
LegacyFileFormat,

View File

@@ -716,6 +716,11 @@ impl ToTokens for Expr {
op.to_tokens(s, context)?;
rhs.to_tokens(s, context)
}
Self::Register(reg) => {
// This is for internal use only, not part of SQL syntax
// Use a special notation that won't conflict with SQL
s.append(TK_VARIABLE, Some(&format!("$r{reg}")))
}
Self::Case {
base,
when_then_pairs,