Merge branch 'main' into perf-3

This commit is contained in:
TcMits
2025-09-02 18:13:58 +07:00
94 changed files with 3786 additions and 1704 deletions

View File

@@ -982,6 +982,8 @@ pub enum AlterTableBody {
RenameTo(Name),
/// `ADD COLUMN`
AddColumn(ColumnDefinition), // TODO distinction between ADD and ADD COLUMN
/// `ALTER COLUMN`
AlterColumn { old: Name, new: ColumnDefinition },
/// `RENAME COLUMN`
RenameColumn {
/// old name

View File

@@ -1409,6 +1409,13 @@ impl ToTokens for AlterTableBody {
s.append(TK_COLUMNKW, None)?;
def.to_tokens_with_context(s, context)
}
Self::AlterColumn { old, new } => {
s.append(TK_ALTER, None)?;
s.append(TK_COLUMNKW, None)?;
old.to_tokens_with_context(s, context)?;
s.append(TK_TO, None)?;
new.to_tokens_with_context(s, context)
}
Self::RenameColumn { old, new } => {
s.append(TK_RENAME, None)?;
s.append(TK_COLUMNKW, None)?;

View File

@@ -169,7 +169,7 @@ pub fn is_identifier_continue(b: u8) -> bool {
|| b > b'\x7F'
}
#[derive(Clone, PartialEq, Eq)] // do not derive Copy for Token, just use .clone() when needed
#[derive(Clone, PartialEq, Eq, Debug)] // do not derive Copy for Token, just use .clone() when needed
pub struct Token<'a> {
pub value: &'a [u8],
pub token_type: Option<TokenType>, // None means Token is whitespaces or comments

View File

@@ -16,6 +16,9 @@ use crate::token::TokenType::{self, *};
use crate::Result;
use turso_macros::match_ignore_ascii_case;
const TRUE_LIT: &str = "TRUE";
const FALSE_LIT: &str = "FALSE";
macro_rules! peek_expect {
( $parser:expr, $( $x:ident ),* $(,)?) => {
{
@@ -419,7 +422,8 @@ impl<'a> Parser<'a> {
}
TK_COLUMNKW => {
let prev_tt = self.current_token.token_type.unwrap_or(TK_EOF);
let can_be_columnkw = matches!(prev_tt, TK_ADD | TK_RENAME | TK_DROP);
let can_be_columnkw =
matches!(prev_tt, TK_ADD | TK_RENAME | TK_DROP | TK_ALTER);
if !can_be_columnkw {
tok.token_type = Some(TK_ID);
@@ -1536,7 +1540,18 @@ impl<'a> Parser<'a> {
Name::Ident(s) => Literal::String(s),
})))
} else {
Ok(Box::new(Expr::Id(name)))
match name {
Name::Ident(s) => match s.as_str() {
s if s.eq_ignore_ascii_case(TRUE_LIT) => {
return Ok(Box::new(Expr::Literal(Literal::Numeric("1".into()))))
}
s if s.eq_ignore_ascii_case(FALSE_LIT) => {
return Ok(Box::new(Expr::Literal(Literal::Numeric("0".into()))))
}
_ => return Ok(Box::new(Expr::Id(Name::Ident(s)))),
},
_ => Ok(Box::new(Expr::Id(name))),
}
}
}
}
@@ -3400,7 +3415,7 @@ impl<'a> Parser<'a> {
Ok(result)
}
fn parse_column_definition(&mut self, in_alter: bool) -> Result<ColumnDefinition> {
pub fn parse_column_definition(&mut self, in_alter: bool) -> Result<ColumnDefinition> {
let col_name = self.parse_nm()?;
if !in_alter && col_name.as_str().eq_ignore_ascii_case("rowid") {
return Err(Error::Custom("cannot use reserved word: ROWID".to_owned()));
@@ -3419,7 +3434,7 @@ impl<'a> Parser<'a> {
eat_assert!(self, TK_ALTER);
eat_expect!(self, TK_TABLE);
let tbl_name = self.parse_fullname(false)?;
let tok = eat_expect!(self, TK_ADD, TK_DROP, TK_RENAME);
let tok = eat_expect!(self, TK_ADD, TK_DROP, TK_RENAME, TK_ALTER);
match tok.token_type.unwrap() {
TK_ADD => {
@@ -3470,6 +3485,19 @@ impl<'a> Parser<'a> {
}))
}
}
TK_ALTER => {
eat_expect!(self, TK_COLUMNKW);
let col_name = self.parse_nm()?;
eat_expect!(self, TK_TO);
let new = self.parse_column_definition(true)?;
Ok(Stmt::AlterTable(AlterTable {
name: tbl_name,
body: AlterTableBody::AlterColumn { old: col_name, new },
}))
}
_ => unreachable!(),
}
}
@@ -9837,6 +9865,24 @@ mod tests {
}),
}))],
),
(
b"ALTER TABLE foo ALTER COLUMN bar TO baz INTEGER".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable (AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AlterColumn {
old: Name::Ident("bar".to_owned()),
new: ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![],
},
},
}))],
),
// parse create index
(
b"CREATE INDEX idx_foo ON foo (bar)".as_slice(),