finish SELECT without tests

This commit is contained in:
TcMits
2025-08-05 18:20:38 +07:00
parent 5b0d4b1731
commit 34fdec82b9
5 changed files with 1519 additions and 482 deletions

View File

@@ -7,6 +7,27 @@ use turso_sqlite3_parser::lexer::{
Scanner,
};
fn bench_parser(criterion: &mut Criterion) {
let queries = ["SELECT 1"];
for query in queries.iter() {
let mut group = criterion.benchmark_group(format!("Parser `{query}`"));
let qb = query.as_bytes();
group.bench_function(BenchmarkId::new("limbo_parser_query", ""), |b| {
b.iter(|| Parser::new(black_box(qb)).next().unwrap());
});
group.bench_function(BenchmarkId::new("limbo_old_parser_query", ""), |b| {
b.iter(|| {
OldParser::new(black_box(qb)).next().unwrap().unwrap();
});
});
group.finish();
}
}
fn bench_lexer(criterion: &mut Criterion) {
let queries = [
"SELECT 1",
@@ -43,44 +64,9 @@ fn bench_lexer(criterion: &mut Criterion) {
}
}
fn bench_parser(criterion: &mut Criterion) {
let queries = [
"BEGIN",
"BEGIN EXCLUSIVE TRANSACTION my_trans",
"COMMIT",
"COMMIT TRANSACTION my_trans",
"ROLLBACK",
"ROLLBACK TRANSACTION my_transaction TO my_savepoint",
"SAVEPOINT my_savepoint",
"RELEASE SAVEPOINT my_savepoint",
];
for query in queries.iter() {
let mut group = criterion.benchmark_group(format!("Parser `{query}`"));
let qb = query.as_bytes();
group.bench_function(BenchmarkId::new("limbo_parser_query", ""), |b| {
b.iter(|| {
for stmt in Parser::new(black_box(qb)) {
stmt.unwrap();
}
});
});
group.bench_function(BenchmarkId::new("limbo_old_parser_query", ""), |b| {
b.iter(|| {
let mut parser = OldParser::new(black_box(qb));
parser.next().unwrap().unwrap()
});
});
group.finish();
}
}
criterion_group! {
name = benches;
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
targets = bench_lexer, bench_parser
targets = bench_parser, bench_lexer
}
criterion_main!(benches);

View File

@@ -1,5 +1,3 @@
use std::str::{self, Bytes};
use strum_macros::{EnumIter, EnumString};
/// `?` or `$` Prepared statement arg placeholder(s)
@@ -320,18 +318,18 @@ pub enum Expr {
/// `DISTINCT`
distinctness: Option<Distinctness>,
/// arguments
args: Option<Vec<Box<Expr>>>,
args: Vec<Box<Expr>>,
/// `ORDER BY`
order_by: Option<Vec<SortedColumn>>,
order_by: Vec<SortedColumn>,
/// `FILTER`
filter_over: Option<FunctionTail>,
filter_over: FunctionTail,
},
/// Function call expression with '*' as arg
FunctionCallStar {
/// function name
name: Name,
/// `FILTER`
filter_over: Option<FunctionTail>,
filter_over: FunctionTail,
},
/// Identifier
Id(Name),
@@ -578,40 +576,33 @@ pub enum CompoundOperator {
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum OneSelect {
/// `SELECT`
Select(SelectInner),
Select {
/// `DISTINCT`
distinctness: Option<Distinctness>,
/// columns
columns: Vec<ResultColumn>,
/// `FROM` clause
from: Option<FromClause>,
/// `WHERE` clause
where_clause: Option<Box<Expr>>,
/// `GROUP BY`
group_by: Option<GroupBy>,
/// `WINDOW` definition
window_clause: Vec<WindowDef>,
},
/// `VALUES`
Values(Vec<Vec<Box<Expr>>>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
/// `SELECT` core
pub struct SelectInner {
/// `DISTINCT`
pub distinctness: Option<Distinctness>,
/// columns
pub columns: Vec<ResultColumn>,
/// `FROM` clause
pub from: Option<FromClause>,
/// `WHERE` clause
pub where_clause: Option<Box<Expr>>,
/// `GROUP BY`
pub group_by: Option<GroupBy>,
/// `WINDOW` definition
pub window_clause: Option<Vec<WindowDef>>,
}
/// `SELECT` ... `FROM` clause
// https://sqlite.org/syntax/join-clause.html
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FromClause {
/// table
pub select: Option<Box<SelectTable>>, // FIXME mandatory
pub select: Box<SelectTable>, // FIXME mandatory
/// `JOIN`ed tabled
pub joins: Option<Vec<JoinedSelectTable>>,
/// A default join operator
pub op: Option<JoinOperator>, // FIXME transient
pub joins: Vec<JoinedSelectTable>,
}
/// `SELECT` distinctness
@@ -668,7 +659,7 @@ pub enum SelectTable {
/// table
Table(QualifiedName, Option<As>, Option<Indexed>),
/// table function call
TableCall(QualifiedName, Option<Vec<Box<Expr>>>, Option<As>),
TableCall(QualifiedName, Vec<Box<Expr>>, Option<As>),
/// `SELECT` subquery
Select(Select, Option<As>),
/// subquery
@@ -1358,7 +1349,7 @@ pub struct FunctionTail {
/// `FILTER` clause
pub filter_clause: Option<Box<Expr>>,
/// `OVER` clause
pub over_clause: Option<Box<Over>>,
pub over_clause: Option<Over>,
}
/// Function call `OVER` clause
@@ -1390,9 +1381,9 @@ pub struct Window {
/// base window name
pub base: Option<Name>,
/// `PARTITION BY`
pub partition_by: Option<Vec<Box<Expr>>>,
pub partition_by: Vec<Box<Expr>>,
/// `ORDER BY`
pub order_by: Option<Vec<SortedColumn>>,
pub order_by: Vec<SortedColumn>,
/// frame spec
pub frame_clause: Option<FrameClause>,
}

View File

@@ -2,10 +2,12 @@ use crate::parser::{error::Error, token::TokenType};
include!(concat!(env!("OUT_DIR"), "/keywords.rs"));
#[inline(always)]
pub(crate) fn is_identifier_start(b: u8) -> bool {
b.is_ascii_uppercase() || b == b'_' || b.is_ascii_lowercase() || b > b'\x7F'
}
#[inline(always)]
pub(crate) fn is_identifier_continue(b: u8) -> bool {
b == b'$'
|| b.is_ascii_digit()
@@ -22,13 +24,14 @@ pub struct Token<'a> {
}
pub struct Lexer<'a> {
offset: usize,
pub(crate) offset: usize,
input: &'a [u8],
}
impl<'a> Iterator for Lexer<'a> {
type Item = Result<Token<'a>, Error>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
match self.peek() {
None => None, // End of file
@@ -41,22 +44,22 @@ impl<'a> Iterator for Lexer<'a> {
b';' => Some(Ok(self.eat_token(1, TokenType::TK_SEMI))),
b'+' => Some(Ok(self.eat_token(1, TokenType::TK_PLUS))),
b'*' => Some(Ok(self.eat_token(1, TokenType::TK_STAR))),
b'/' => Some(self.eat_slash_or_comment()),
b'/' => Some(self.mark(|l| l.eat_slash_or_comment())),
b'%' => Some(Ok(self.eat_token(1, TokenType::TK_REM))),
b'=' => Some(Ok(self.eat_eq())),
b'<' => Some(Ok(self.eat_le_or_ne_or_lshift_or_lt())),
b'>' => Some(Ok(self.eat_ge_or_gt_or_rshift())),
b'!' => Some(self.eat_ne()),
b'!' => Some(self.mark(|l| l.eat_ne())),
b'|' => Some(Ok(self.eat_concat_or_bitor())),
b',' => Some(Ok(self.eat_token(1, TokenType::TK_COMMA))),
b'&' => Some(Ok(self.eat_token(1, TokenType::TK_BITAND))),
b'~' => Some(Ok(self.eat_token(1, TokenType::TK_BITNOT))),
b'\'' | b'"' | b'`' => Some(self.eat_lit_or_id()),
b'.' => Some(self.eat_dot_or_frac()),
b'0'..=b'9' => Some(self.eat_number()),
b'[' => Some(self.eat_bracket()),
b'?' | b'$' | b'@' | b'#' | b':' => Some(self.eat_var()),
b if is_identifier_start(b) => Some(self.eat_blob_or_id()),
b'\'' | b'"' | b'`' => Some(self.mark(|l| l.eat_lit_or_id())),
b'.' => Some(self.mark(|l| l.eat_dot_or_frac())),
b'0'..=b'9' => Some(self.mark(|l| l.eat_number())),
b'[' => Some(self.mark(|l| l.eat_bracket())),
b'?' | b'$' | b'@' | b'#' | b':' => Some(self.mark(|l| l.eat_var())),
b if is_identifier_start(b) => Some(self.mark(|l| l.eat_blob_or_id())),
_ => Some(Ok(self.eat_unrecognized())),
},
}
@@ -74,6 +77,19 @@ impl<'a> Lexer<'a> {
&self.input[self.offset..]
}
#[inline(always)]
pub fn mark<F, R>(&mut self, exc: F) -> Result<R, Error>
where
F: FnOnce(&mut Self) -> Result<R, Error>,
{
let start_offset = self.offset;
let result = exc(self);
if result.is_err() {
self.offset = start_offset; // Reset to the start offset if an error occurs
}
result
}
/// Returns the current offset in the input without consuming.
#[inline(always)]
pub fn peek(&self) -> Option<u8> {

File diff suppressed because it is too large Load Diff

View File

@@ -184,164 +184,185 @@ impl Display for TokenType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use TokenType::*;
let s = match self {
TK_ABORT => Some("ABORT"),
TK_ACTION => Some("ACTION"),
TK_ADD => Some("ADD"),
TK_AFTER => Some("AFTER"),
TK_ALL => Some("ALL"),
TK_ALTER => Some("ALTER"),
TK_ANALYZE => Some("ANALYZE"),
TK_ALWAYS => Some("ALWAYS"),
TK_AND => Some("AND"),
TK_AS => Some("AS"),
TK_ASC => Some("ASC"),
TK_ATTACH => Some("ATTACH"),
TK_AUTOINCR => Some("AUTOINCREMENT"),
TK_BEFORE => Some("BEFORE"),
TK_BEGIN => Some("BEGIN"),
TK_BETWEEN => Some("BETWEEN"),
TK_BY => Some("BY"),
TK_CASCADE => Some("CASCADE"),
TK_CASE => Some("CASE"),
TK_CAST => Some("CAST"),
TK_CHECK => Some("CHECK"),
TK_COLLATE => Some("COLLATE"),
TK_COLUMNKW => Some("COLUMN"),
TK_COMMIT => Some("COMMIT"),
TK_CONFLICT => Some("CONFLICT"),
TK_CONSTRAINT => Some("CONSTRAINT"),
TK_CREATE => Some("CREATE"),
TK_CURRENT => Some("CURRENT"),
TK_DATABASE => Some("DATABASE"),
TK_DEFAULT => Some("DEFAULT"),
TK_DEFERRABLE => Some("DEFERRABLE"),
TK_DEFERRED => Some("DEFERRED"),
TK_DELETE => Some("DELETE"),
TK_DESC => Some("DESC"),
TK_DETACH => Some("DETACH"),
TK_DISTINCT => Some("DISTINCT"),
TK_DO => Some("DO"),
TK_DROP => Some("DROP"),
TK_EACH => Some("EACH"),
TK_ELSE => Some("ELSE"),
TK_END => Some("END"),
TK_ESCAPE => Some("ESCAPE"),
TK_EXCEPT => Some("EXCEPT"),
TK_EXCLUDE => Some("EXCLUDE"),
TK_EXCLUSIVE => Some("EXCLUSIVE"),
TK_EXISTS => Some("EXISTS"),
TK_EXPLAIN => Some("EXPLAIN"),
TK_FAIL => Some("FAIL"),
TK_FILTER => Some("FILTER"),
TK_FIRST => Some("FIRST"),
TK_FOLLOWING => Some("FOLLOWING"),
TK_FOR => Some("FOR"),
TK_FOREIGN => Some("FOREIGN"),
TK_FROM => Some("FROM"),
TK_GENERATED => Some("GENERATED"),
TK_GROUP => Some("GROUP"),
TK_GROUPS => Some("GROUPS"),
TK_HAVING => Some("HAVING"),
TK_IF => Some("IF"),
TK_IGNORE => Some("IGNORE"),
TK_IMMEDIATE => Some("IMMEDIATE"),
TK_IN => Some("IN"),
TK_INDEX => Some("INDEX"),
TK_INDEXED => Some("INDEXED"),
TK_INITIALLY => Some("INITIALLY"),
TK_INSERT => Some("INSERT"),
TK_INSTEAD => Some("INSTEAD"),
TK_INTERSECT => Some("INTERSECT"),
TK_INTO => Some("INTO"),
TK_IS => Some("IS"),
TK_ISNULL => Some("ISNULL"),
TK_JOIN => Some("JOIN"),
TK_KEY => Some("KEY"),
TK_LAST => Some("LAST"),
TK_LIMIT => Some("LIMIT"),
TK_MATCH => Some("MATCH"),
TK_MATERIALIZED => Some("MATERIALIZED"),
TK_NO => Some("NO"),
TK_NOT => Some("NOT"),
TK_NOTHING => Some("NOTHING"),
TK_NOTNULL => Some("NOTNULL"),
TK_NULL => Some("NULL"),
TK_NULLS => Some("NULLS"),
TK_OF => Some("OF"),
TK_OFFSET => Some("OFFSET"),
TK_ON => Some("ON"),
TK_OR => Some("OR"),
TK_ORDER => Some("ORDER"),
TK_OTHERS => Some("OTHERS"),
TK_OVER => Some("OVER"),
TK_PARTITION => Some("PARTITION"),
TK_PLAN => Some("PLAN"),
TK_PRAGMA => Some("PRAGMA"),
TK_PRECEDING => Some("PRECEDING"),
TK_PRIMARY => Some("PRIMARY"),
TK_QUERY => Some("QUERY"),
TK_RAISE => Some("RAISE"),
TK_RANGE => Some("RANGE"),
TK_RECURSIVE => Some("RECURSIVE"),
TK_REFERENCES => Some("REFERENCES"),
TK_REINDEX => Some("REINDEX"),
TK_RELEASE => Some("RELEASE"),
TK_RENAME => Some("RENAME"),
TK_REPLACE => Some("REPLACE"),
TK_RETURNING => Some("RETURNING"),
TK_RESTRICT => Some("RESTRICT"),
TK_ROLLBACK => Some("ROLLBACK"),
TK_ROW => Some("ROW"),
TK_ROWS => Some("ROWS"),
TK_SAVEPOINT => Some("SAVEPOINT"),
TK_SELECT => Some("SELECT"),
TK_SET => Some("SET"),
TK_TABLE => Some("TABLE"),
TK_TEMP => Some("TEMP"), // or TEMPORARY
TK_TIES => Some("TIES"),
TK_THEN => Some("THEN"),
TK_TO => Some("TO"),
TK_TRANSACTION => Some("TRANSACTION"),
TK_TRIGGER => Some("TRIGGER"),
TK_UNBOUNDED => Some("UNBOUNDED"),
TK_UNION => Some("UNION"),
TK_UNIQUE => Some("UNIQUE"),
TK_UPDATE => Some("UPDATE"),
TK_USING => Some("USING"),
TK_VACUUM => Some("VACUUM"),
TK_VALUES => Some("VALUES"),
TK_VIEW => Some("VIEW"),
TK_VIRTUAL => Some("VIRTUAL"),
TK_WHEN => Some("WHEN"),
TK_WHERE => Some("WHERE"),
TK_WINDOW => Some("WINDOW"),
TK_WITH => Some("WITH"),
TK_WITHOUT => Some("WITHOUT"),
TK_BITAND => Some("&"),
TK_BITNOT => Some("~"),
TK_BITOR => Some("|"),
TK_COMMA => Some(","),
TK_CONCAT => Some("||"),
TK_DOT => Some("."),
TK_EQ => Some("="), // or ==
TK_GT => Some(">"),
TK_GE => Some(">="),
TK_LP => Some("("),
TK_LSHIFT => Some("<<"),
TK_LE => Some("<="),
TK_LT => Some("<"),
TK_MINUS => Some("-"),
TK_NE => Some("!="), // or <>
TK_PLUS => Some("+"),
TK_REM => Some("%"),
TK_RP => Some(")"),
TK_RSHIFT => Some(">>"),
TK_SEMI => Some(";"),
TK_SLASH => Some("/"),
TK_STAR => Some("*"),
_ => None,
}
.unwrap_or("unknown");
TK_ABORT => "ABORT",
TK_ACTION => "ACTION",
TK_ADD => "ADD",
TK_AFTER => "AFTER",
TK_ALL => "ALL",
TK_ALTER => "ALTER",
TK_ANALYZE => "ANALYZE",
TK_ALWAYS => "ALWAYS",
TK_AND => "AND",
TK_AS => "AS",
TK_ASC => "ASC",
TK_ATTACH => "ATTACH",
TK_AUTOINCR => "AUTOINCREMENT",
TK_BEFORE => "BEFORE",
TK_BEGIN => "BEGIN",
TK_BETWEEN => "BETWEEN",
TK_BY => "BY",
TK_CASCADE => "CASCADE",
TK_CASE => "CASE",
TK_CAST => "CAST",
TK_CHECK => "CHECK",
TK_COLLATE => "COLLATE",
TK_COLUMNKW => "COLUMN",
TK_COMMIT => "COMMIT",
TK_CONFLICT => "CONFLICT",
TK_CONSTRAINT => "CONSTRAINT",
TK_CREATE => "CREATE",
TK_CURRENT => "CURRENT",
TK_DATABASE => "DATABASE",
TK_DEFAULT => "DEFAULT",
TK_DEFERRABLE => "DEFERRABLE",
TK_DEFERRED => "DEFERRED",
TK_DELETE => "DELETE",
TK_DESC => "DESC",
TK_DETACH => "DETACH",
TK_DISTINCT => "DISTINCT",
TK_DO => "DO",
TK_DROP => "DROP",
TK_EACH => "EACH",
TK_ELSE => "ELSE",
TK_END => "END",
TK_ESCAPE => "ESCAPE",
TK_EXCEPT => "EXCEPT",
TK_EXCLUDE => "EXCLUDE",
TK_EXCLUSIVE => "EXCLUSIVE",
TK_EXISTS => "EXISTS",
TK_EXPLAIN => "EXPLAIN",
TK_FAIL => "FAIL",
TK_FILTER => "FILTER",
TK_FIRST => "FIRST",
TK_FOLLOWING => "FOLLOWING",
TK_FOR => "FOR",
TK_FOREIGN => "FOREIGN",
TK_FROM => "FROM",
TK_GENERATED => "GENERATED",
TK_GROUP => "GROUP",
TK_GROUPS => "GROUPS",
TK_HAVING => "HAVING",
TK_IF => "IF",
TK_IGNORE => "IGNORE",
TK_IMMEDIATE => "IMMEDIATE",
TK_IN => "IN",
TK_INDEX => "INDEX",
TK_INDEXED => "INDEXED",
TK_INITIALLY => "INITIALLY",
TK_INSERT => "INSERT",
TK_INSTEAD => "INSTEAD",
TK_INTERSECT => "INTERSECT",
TK_INTO => "INTO",
TK_IS => "IS",
TK_ISNULL => "ISNULL",
TK_JOIN => "JOIN",
TK_KEY => "KEY",
TK_LAST => "LAST",
TK_LIMIT => "LIMIT",
TK_MATCH => "MATCH",
TK_MATERIALIZED => "MATERIALIZED",
TK_NO => "NO",
TK_NOT => "NOT",
TK_NOTHING => "NOTHING",
TK_NOTNULL => "NOTNULL",
TK_NULL => "NULL",
TK_NULLS => "NULLS",
TK_OF => "OF",
TK_OFFSET => "OFFSET",
TK_ON => "ON",
TK_OR => "OR",
TK_ORDER => "ORDER",
TK_OTHERS => "OTHERS",
TK_OVER => "OVER",
TK_PARTITION => "PARTITION",
TK_PLAN => "PLAN",
TK_PRAGMA => "PRAGMA",
TK_PRECEDING => "PRECEDING",
TK_PRIMARY => "PRIMARY",
TK_QUERY => "QUERY",
TK_RAISE => "RAISE",
TK_RANGE => "RANGE",
TK_RECURSIVE => "RECURSIVE",
TK_REFERENCES => "REFERENCES",
TK_REINDEX => "REINDEX",
TK_RELEASE => "RELEASE",
TK_RENAME => "RENAME",
TK_REPLACE => "REPLACE",
TK_RETURNING => "RETURNING",
TK_RESTRICT => "RESTRICT",
TK_ROLLBACK => "ROLLBACK",
TK_ROW => "ROW",
TK_ROWS => "ROWS",
TK_SAVEPOINT => "SAVEPOINT",
TK_SELECT => "SELECT",
TK_SET => "SET",
TK_TABLE => "TABLE",
TK_TEMP => "TEMP", // or TEMPORARY
TK_TIES => "TIES",
TK_THEN => "THEN",
TK_TO => "TO",
TK_TRANSACTION => "TRANSACTION",
TK_TRIGGER => "TRIGGER",
TK_UNBOUNDED => "UNBOUNDED",
TK_UNION => "UNION",
TK_UNIQUE => "UNIQUE",
TK_UPDATE => "UPDATE",
TK_USING => "USING",
TK_VACUUM => "VACUUM",
TK_VALUES => "VALUES",
TK_VIEW => "VIEW",
TK_VIRTUAL => "VIRTUAL",
TK_WHEN => "WHEN",
TK_WHERE => "WHERE",
TK_WINDOW => "WINDOW",
TK_WITH => "WITH",
TK_WITHOUT => "WITHOUT",
TK_BITAND => "&",
TK_BITNOT => "~",
TK_BITOR => "|",
TK_COMMA => ",",
TK_CONCAT => "||",
TK_DOT => ".",
TK_EQ => "=", // or ==
TK_GT => ">",
TK_GE => ">=",
TK_LP => "(",
TK_LSHIFT => "<<",
TK_LE => "<=",
TK_LT => "<",
TK_MINUS => "-",
TK_NE => "!=", // or <>
TK_PLUS => "+",
TK_REM => "%",
TK_RP => ")",
TK_RSHIFT => ">>",
TK_SEMI => ";",
TK_SLASH => "/",
TK_STAR => "*",
_ => "unknown",
};
write!(f, "{s}")
}
}
impl TokenType {
/// if your parsing process expects next token to be TK_ID, remember to call this function !!!
pub fn fallback_id_if_ok(self) -> Self {
use TokenType::*;
match self {
TK_ABORT | TK_ACTION | TK_AFTER | TK_ANALYZE | TK_ASC | TK_ATTACH | TK_BEFORE
| TK_BEGIN | TK_BY | TK_CASCADE | TK_CAST | TK_COLUMNKW | TK_CONFLICT | TK_DATABASE
| TK_DEFERRED | TK_DESC | TK_DETACH | TK_DO | TK_EACH | TK_END | TK_EXCLUSIVE
| TK_EXPLAIN | TK_FAIL | TK_FOR | TK_IGNORE | TK_IMMEDIATE | TK_INITIALLY
| TK_INSTEAD | TK_LIKE_KW | TK_MATCH | TK_NO | TK_PLAN | TK_QUERY | TK_KEY | TK_OF
| TK_OFFSET | TK_PRAGMA | TK_RAISE | TK_RECURSIVE | TK_RELEASE | TK_REPLACE
| TK_RESTRICT | TK_ROW | TK_ROWS | TK_ROLLBACK | TK_SAVEPOINT | TK_TEMP
| TK_TRIGGER | TK_VACUUM | TK_VIEW | TK_VIRTUAL | TK_WITH | TK_WITHOUT | TK_NULLS
| TK_FIRST | TK_LAST | TK_EXCEPT | TK_INTERSECT | TK_UNION | TK_CURRENT
| TK_FOLLOWING | TK_PARTITION | TK_PRECEDING | TK_RANGE | TK_UNBOUNDED | TK_EXCLUDE
| TK_GROUPS | TK_OTHERS | TK_TIES | TK_GENERATED | TK_ALWAYS | TK_MATERIALIZED
| TK_REINDEX | TK_RENAME | TK_CTIME_KW | TK_IF => TK_ID,
_ => self,
}
}
}